Frohe Weihnachten an das mikrocontroller.net-Forum, ich habe mal eine mehr oder weniger allgemeine Frage bezüglich der Realisierung eines Regelkreises mithilfe eines µC's vom Typ ATMEGA32 (genauer gesagt C-Control Pro 32 von Conrad). Im Vorfeld möchte ich noch sagen, dass es mir lieb wäre, direkt auf mein Problem einzugehen. Aussagen wie "Mach das ganze statt mit nem µC lieber mit nem Komparator" ect. helfen mir da wenig. Der µC misst über zwei seiner internen AD-Wandler die Spannung über und unter einem Shunt (etwa 100mΩ), welcher über dem Drain eines BUZ11-Mosfet's liegt. Der Source des Mosfet's liegt auf Masse, am Gate des Mosfets liegt ein PWM-Ausgang des µC's, welcher mit einem kleinen Tantalkondesator gegen Masse leicht HF-entstört wird. Der Strom über den Shunt soll nun mittels des Tastgrades aus dem PWM-Ausgang konstant gehalten werden. Eine Skizze des Schaltplanes habe ich als Grafik angehängt. Soviel zum Aufbau des analogen Teils. Der Mikrocontroller misst die beiden Spannungen über und unter dem Shunt und Subtrahiert den unteren vom oberen Wert. Da er jedoch eine weitgehend ungeglättete PWM-Spannung messen muss, lasse ich die Messung z.Zt. ca. 32x hintereinander mit einer kurzen Pause dazwischen ausführen, und bilde anschließend das arithmetische Mittel aus diesen Messwerten. Dieses wird nun durch den Wiederstand des Shunts geteilt und als Strommesswert weiterverwendet. Ich ziehe diesen Strom nun von der Periodenlänge meines Timers ab: tastgrad=Periodenlänge*Anpassungsfaktor-Strom*Anpassungsfaktor und erhalte somit am PWM-Ausgang eine Spannung, die ab einem gewissen Strom über dem Shunt linear kleiner geregelt wird. Mittels zweier if-Verzweigungen sorge ich dafür, dass Werte kleiner 0 als 0 bzw. Werte größer der Periodenlänge als Periodenlänge gewertet werden. Das funktioniert soweit auch ganz gut, solange ich die PWM Spannung nicht über dem Gate des Mosfet's in den Regelkreis einkopple. Wie nämlich zu erwarten war, fängt des Regelkreis dann recht schnell an zu oszillieren. Meine Frage ist nun folgende: Wie kann ich in dem Regelalgorithmus einen Dämpfungsalgorithmus hinzufügen? Oder besser gefragt: wie hat dieser Mathematisch auszusehen? Aus vielerlei Gründen möchte ich keinerlei analoge Dämpfungsglieder im Laststromkreis einsetzen. Mit freundlichen Grüßen Robert
wultna schrieb: > Das funktioniert soweit auch ganz gut, solange ich die PWM Spannung > nicht über dem Gate des Mosfet's in den Regelkreis einkopple. Wie > nämlich zu erwarten war, fängt des Regelkreis dann recht schnell an zu > oszillieren. > > Meine Frage ist nun folgende: > Wie kann ich in dem Regelalgorithmus einen Dämpfungsalgorithmus > hinzufügen? Oder besser gefragt: wie hat dieser Mathematisch auszusehen? > Aus vielerlei Gründen möchte ich keinerlei analoge Dämpfungsglieder im > Laststromkreis einsetzen. Ja entweder entscheidest du dich für einen geeigneteren Regler oder du bastelst im einfachsten fall einen Tiefpass oder eine Bandsperre ein. Dafür in C Algorithmen zu finden, sollte nicht schwer sein. Ein bisschen Theorie http://www.mikrocontroller.net/attachment/80230/schift-filter-tp.pdf Sogar mit Code.
:
Wiederhergestellt durch Admin
Ich finde es mutig, die 30V an den OpAmp und an den Mega32 zu geben.. Was ist die Spannung, die aufgrund der Planung maximal am Opamp anliegen sollte ?
Toto schrieb: > Ich finde es mutig, die 30V an den OpAmp und an den Mega32 zu geben.. > > Was ist die Spannung, die aufgrund der Planung maximal am Opamp anliegen > sollte ? wenn ich das richtig sehe ist da noch ein 7805 zwischen !
Hallo, nach tagelangem Grübeln ist es mir gelungen, eine Lösung für das Problem zu finden. Leider kann ich nicht genau in Worte fassen, wie die Lösung aussieht. Der Algorithmus nährt sich dem idealen Tastgrad irgendwie in festgelegten Stufen. Ich denke, es ist am besten direkt den Code zu Posten. Eventuell kann jemand mal was damit anfangen. Der Algorithmus funktioniert bis auf kleinere Macken !Achtung! nach dem Reset liegt der PWM-Ausgang für einen kurzen Augenblick komplett auf High! Außerdem benötigen die Werte für die Übergänge zwischen den verschiedenen Tastgradanpassungsgeschwindigkeiten noch Finetuning. Zusätzlich finde meine Lösung (mathematisch ausgedrückt) unelegant. Zu viele Wiederholungen des immer gleichen Codes, das Benutzen des Goto-Befehls ect. Ich wäre sehr froh darüber, wenn mir jemand ein paar Verbesserungsvorschläge nennen könnte. C-Code für C-Control Pro Mega32
1 | char str[80]; //Deklaration der Variable für die Textausgabe z. Diagnose |
2 | float currentI; //Deklaration der Variable für den entgültigen Messwert des Stromes |
3 | int tastgrad; //Deklaration der Variable für die Pulsweite des PWM-Ausganges |
4 | |
5 | void main(void) //Aufruf der Main-Prozedur |
6 | {
|
7 | float soll, soll2, highI1, highI2, lowI1, lowI2; //Deklaration der Arbeitsvariablen für die Tastgradanpassung |
8 | |
9 | Timer_T1PWMX(10000,0,0,PS_1); //Initialisierung des Timers |
10 | while(1) //Start der Endlosschleife (ein Überbleibsel aus der älteren Version) |
11 | {
|
12 | soll=0.7; //Übertrag des gewünschten Stromwertes an ihre Arbeitsvariable |
13 | soll2=soll; //Übergabe jenes Stromwertes an die zweite Arbeitsvariable, welche die Einregelungszeit verkürzt |
14 | if (soll2>=1)soll2=1; //nötig zur Anpassung der Wirkung der schnellen Tastgradanpassung |
15 | if (soll2<=0.0001)soll2=0.0001; //Verhindert division durch 0 |
16 | tastgrad=1; //Legt den Anfangstastgrad fest |
17 | label0: //Goto Sprunganker |
18 | currentI=GetCurrent(0); //Ruft die Funktion zur Messung des Stromes auf, Mitgabewert bisher Irrelevant, daher 0 |
19 | highI1=currentI-soll*(0.1/soll2);//Kalkulation des Übergabepunktes von schneller zu mittlerer neg. Tastgradanpassung |
20 | highI2=currentI-soll; //Kalkulation des Übergabepunktes von mittlerer zu langsamer neg. Tastgradanpassung |
21 | lowI1=currentI+soll*(0.1/soll2);//Kalkulation des Übergabepunktes von schneller zu mittlerer pos. Tastgradanpassung |
22 | lowI2=currentI+soll;//Kalkulation des Übergabepunktes von mittlerer zu langsamer pos. Tastgradanpassung |
23 | |
24 | if (highI1>=soll) //Aufruf des Algorithmus zur schnellen positiven Tastgradanpassung, wenn Bedingung erfüllt |
25 | {
|
26 | tastgrad=tastgrad-200; //Berechnung und Übertrag des neuen Tastgrades |
27 | if (tastgrad<=1)tastgrad=1; //verhindert den Unterlauf des PWM-Ausganges |
28 | if (tastgrad>=9999)tastgrad=9999; //verhindert den Überlauf des PWM-Ausganges |
29 | Timer_T1PWB(tastgrad); //übergibt dem Timer den neuen Tastgrad |
30 | goto label0; //Rücksprung zum Sprunganker |
31 | }
|
32 | else
|
33 | {
|
34 | if (highI2>=soll) //Die Tastgradanpassungsalgorithmen werden nun der Reihe nach |
35 | { //abgefragt. Das Schema bleibt das selbe wie bei der ersten |
36 | tastgrad=tastgrad-20; //if-Verzweigung. Erfüllt ein Algorithmus die Bedinung, so wird er |
37 | if (tastgrad<=1)tastgrad=1; //ausgeführt. Dabei wird immer zuerst die Bedingung des |
38 | if (tastgrad>=9999)tastgrad=9999; //schnellsten Algorithmuses abgefragt. Dies spart AND-Verknüpfungen |
39 | Timer_T1PWB(tastgrad); |
40 | goto label0; |
41 | }
|
42 | else
|
43 | {
|
44 | if (currentI>=soll) |
45 | {
|
46 | tastgrad=tastgrad-1; |
47 | if (tastgrad<=1)tastgrad=1; |
48 | if (tastgrad>=9999)tastgrad=9999; |
49 | Timer_T1PWB(tastgrad); |
50 | goto label0; |
51 | }
|
52 | else
|
53 | {
|
54 | if (lowI1<=soll) |
55 | |
56 | {
|
57 | tastgrad=tastgrad+100; |
58 | if (tastgrad<=1)tastgrad=1; |
59 | if (tastgrad>=9999)tastgrad=9999; |
60 | Timer_T1PWB(tastgrad); |
61 | goto label0; |
62 | }
|
63 | else
|
64 | {
|
65 | if (lowI2<=soll) |
66 | {
|
67 | tastgrad=tastgrad+10; |
68 | if (tastgrad<=1)tastgrad=1; |
69 | if (tastgrad>=9999)tastgrad=9999; |
70 | Timer_T1PWB(tastgrad); |
71 | goto label0; |
72 | }
|
73 | else
|
74 | {
|
75 | if (currentI<=soll) |
76 | {
|
77 | tastgrad=tastgrad+1; |
78 | if (tastgrad<=1)tastgrad=1; |
79 | if (tastgrad>=9999)tastgrad=9999; |
80 | Timer_T1PWB(tastgrad); |
81 | goto label0; |
82 | }
|
83 | else
|
84 | {
|
85 | goto label0; //Sollte das Messergebniss exakt mit dem Soll übereinstimmen, so springt |
86 | } //das Programm direkt zurück zum Anker |
87 | }
|
88 | }
|
89 | }
|
90 | }
|
91 | }
|
92 | Str_Printf(str,"Strom = %1.3f A\r",currentI); //Relikt aus einer älteren Version zur Ausgabe einer Variablen |
93 | Msg_WriteText(str); //in der Entwicklungsumgebung |
94 | }
|
95 | }
|
96 | |
97 | float GetCurrent(float lastI) //Aufruf der Strommess-Funktion und Deklaration ihres Rückgabewertes, Einordnung der Mitgabe |
98 | {
|
99 | word raw0; //Deklaration der Arbeitsvariablen für den blanken Messwert |
100 | float UADC0, UADC1, UADC2, UADC3, UADC4, UADC5, UADC6, UADC7, UADC8, UADC9, //Deklaration der Arbeitsvariablen |
101 | UADC10, UADC11, UADC12, UADC13, UADC14, UADC15, UADC16, UADC17, UADC18, //der Funktion |
102 | UADC19, UADC20, UADC21, UADC22, UADC23, UADC24, UADC25, UADC26, UADC27, |
103 | UADC28, UADC29, UADC30, UADC31, mem, mem1, mem2, mem3, mem4, R1, ref; |
104 | |
105 | R1=0.175; //Setzen des Widerstandswertes in Ohm |
106 | ref=2.56/1023.0; //Setzen des Referenzwertes; Bestehend aus der Referenzspannung und der größe der Messwerte |
107 | |
108 | ADC_Set (ADC_VREF_BG,7); //Initialisieren des AD-Wandlers zur Spannungsmessung |
109 | raw0=ADC_Read(); //Auslesen des AD-Wandlers |
110 | UADC0=raw0*ref; //Umrechnen in die zugehörige Spannung und übertrag an die Speichervariable |
111 | raw0=ADC_Read(); //... |
112 | UADC1=raw0*ref; //... |
113 | raw0=ADC_Read(); // |
114 | UADC2=raw0*ref; //Insgesamt misst die Funktion die Spannung 128 mal. Am Schluss bildet sie aus diesen Messwerten |
115 | raw0=ADC_Read(); //das aritmethische Mittel. Das ist notwendig, weil eine ungeglättete PWM-Spannung gemessen werden muss. |
116 | UADC3=raw0*ref; //Würde man Beispielsweise nur zehn mal messen, so würde es einen Unterschied machen, |
117 | raw0=ADC_Read(); //ob die Messung gerade bei einem High-Pegel oder bei einem Low-Pegel des PWM-Zykluses einsetzt. |
118 | UADC4=raw0*ref; //Da der Takt der PWM und der Arbeitstakt gekoppelt sind, würde es zwangsläufig zu Resonanzen kommen. |
119 | raw0=ADC_Read(); |
120 | UADC5=raw0*ref; |
121 | raw0=ADC_Read(); |
122 | UADC6=raw0*ref; |
123 | raw0=ADC_Read(); |
124 | UADC7=raw0*ref; |
125 | raw0=ADC_Read(); |
126 | UADC8=raw0*ref; |
127 | raw0=ADC_Read(); |
128 | UADC9=raw0*ref; |
129 | raw0=ADC_Read(); |
130 | UADC10=raw0*ref; |
131 | raw0=ADC_Read(); |
132 | UADC11=raw0*ref; |
133 | raw0=ADC_Read(); |
134 | UADC12=raw0*ref; |
135 | raw0=ADC_Read(); |
136 | UADC13=raw0*ref; |
137 | raw0=ADC_Read(); |
138 | UADC14=raw0*ref; |
139 | raw0=ADC_Read(); |
140 | UADC15=raw0*ref; |
141 | raw0=ADC_Read(); |
142 | UADC16=raw0*ref; |
143 | raw0=ADC_Read(); |
144 | UADC17=raw0*ref; |
145 | raw0=ADC_Read(); |
146 | UADC18=raw0*ref; |
147 | raw0=ADC_Read(); |
148 | UADC19=raw0*ref; |
149 | raw0=ADC_Read(); |
150 | UADC20=raw0*ref; |
151 | raw0=ADC_Read(); |
152 | UADC21=raw0*ref; |
153 | raw0=ADC_Read(); |
154 | UADC22=raw0*ref; |
155 | raw0=ADC_Read(); |
156 | UADC23=raw0*ref; |
157 | raw0=ADC_Read(); |
158 | UADC24=raw0*ref; |
159 | raw0=ADC_Read(); |
160 | UADC25=raw0*ref; |
161 | raw0=ADC_Read(); |
162 | UADC26=raw0*ref; |
163 | raw0=ADC_Read(); |
164 | UADC27=raw0*ref; |
165 | raw0=ADC_Read(); |
166 | UADC28=raw0*ref; |
167 | raw0=ADC_Read(); |
168 | UADC29=raw0*ref; |
169 | raw0=ADC_Read(); |
170 | UADC30=raw0*ref; |
171 | raw0=ADC_Read(); |
172 | UADC31=raw0*ref; |
173 | mem1=UADC0+UADC1+UADC2+UADC3+UADC4+UADC5+UADC6+UADC7+UADC8+UADC9+UADC10+ //Übergabe der Messwerte an die erste |
174 | UADC11+UADC12+UADC13+UADC14+UADC15+UADC16+UADC17+UADC18+UADC19+UADC20+ //Speichervariable |
175 | UADC21+UADC22+UADC23+UADC24+UADC25+UADC26+UADC27+UADC28+UADC29+UADC30+ |
176 | UADC31; |
177 | raw0=ADC_Read(); //... |
178 | UADC0=raw0*ref; //... |
179 | raw0=ADC_Read(); |
180 | UADC1=raw0*ref; |
181 | raw0=ADC_Read(); |
182 | UADC2=raw0*ref; |
183 | raw0=ADC_Read(); |
184 | UADC3=raw0*ref; |
185 | raw0=ADC_Read(); |
186 | UADC4=raw0*ref; |
187 | raw0=ADC_Read(); |
188 | UADC5=raw0*ref; |
189 | raw0=ADC_Read(); |
190 | UADC6=raw0*ref; |
191 | raw0=ADC_Read(); |
192 | UADC7=raw0*ref; |
193 | raw0=ADC_Read(); |
194 | UADC8=raw0*ref; |
195 | raw0=ADC_Read(); |
196 | UADC9=raw0*ref; |
197 | raw0=ADC_Read(); |
198 | UADC10=raw0*ref; |
199 | raw0=ADC_Read(); |
200 | UADC11=raw0*ref; |
201 | raw0=ADC_Read(); |
202 | UADC12=raw0*ref; |
203 | raw0=ADC_Read(); |
204 | UADC13=raw0*ref; |
205 | raw0=ADC_Read(); |
206 | UADC14=raw0*ref; |
207 | raw0=ADC_Read(); |
208 | UADC15=raw0*ref; |
209 | raw0=ADC_Read(); |
210 | UADC16=raw0*ref; |
211 | raw0=ADC_Read(); |
212 | UADC17=raw0*ref; |
213 | raw0=ADC_Read(); |
214 | UADC18=raw0*ref; |
215 | raw0=ADC_Read(); |
216 | UADC19=raw0*ref; |
217 | raw0=ADC_Read(); |
218 | UADC20=raw0*ref; |
219 | raw0=ADC_Read(); |
220 | UADC21=raw0*ref; |
221 | raw0=ADC_Read(); |
222 | UADC22=raw0*ref; |
223 | raw0=ADC_Read(); |
224 | UADC23=raw0*ref; |
225 | raw0=ADC_Read(); |
226 | UADC24=raw0*ref; |
227 | raw0=ADC_Read(); |
228 | UADC25=raw0*ref; |
229 | raw0=ADC_Read(); |
230 | UADC26=raw0*ref; |
231 | raw0=ADC_Read(); |
232 | UADC27=raw0*ref; |
233 | raw0=ADC_Read(); |
234 | UADC28=raw0*ref; |
235 | raw0=ADC_Read(); |
236 | UADC29=raw0*ref; |
237 | raw0=ADC_Read(); |
238 | UADC30=raw0*ref; |
239 | raw0=ADC_Read(); |
240 | UADC31=raw0*ref; |
241 | mem2=UADC0+UADC1+UADC2+UADC3+UADC4+UADC5+UADC6+UADC7+UADC8+UADC9+UADC10+ //Übergabe der Messwerte an die zweite |
242 | UADC11+UADC12+UADC13+UADC14+UADC15+UADC16+UADC17+UADC18+UADC19+UADC20+ //Speichervariable |
243 | UADC21+UADC22+UADC23+UADC24+UADC25+UADC26+UADC27+UADC28+UADC29+UADC30+ |
244 | UADC31; |
245 | raw0=ADC_Read(); //... messen messen ... |
246 | UADC0=raw0*ref; //... rechnen rechnen ... |
247 | raw0=ADC_Read(); |
248 | UADC1=raw0*ref; |
249 | raw0=ADC_Read(); |
250 | UADC2=raw0*ref; |
251 | raw0=ADC_Read(); |
252 | UADC3=raw0*ref; |
253 | raw0=ADC_Read(); |
254 | UADC4=raw0*ref; |
255 | raw0=ADC_Read(); |
256 | UADC5=raw0*ref; |
257 | raw0=ADC_Read(); |
258 | UADC6=raw0*ref; |
259 | raw0=ADC_Read(); |
260 | UADC7=raw0*ref; |
261 | raw0=ADC_Read(); |
262 | UADC8=raw0*ref; |
263 | raw0=ADC_Read(); |
264 | UADC9=raw0*ref; |
265 | raw0=ADC_Read(); |
266 | UADC10=raw0*ref; |
267 | raw0=ADC_Read(); |
268 | UADC11=raw0*ref; |
269 | raw0=ADC_Read(); |
270 | UADC12=raw0*ref; |
271 | raw0=ADC_Read(); |
272 | UADC13=raw0*ref; |
273 | raw0=ADC_Read(); |
274 | UADC14=raw0*ref; |
275 | raw0=ADC_Read(); |
276 | UADC15=raw0*ref; |
277 | raw0=ADC_Read(); |
278 | UADC16=raw0*ref; |
279 | raw0=ADC_Read(); |
280 | UADC17=raw0*ref; |
281 | raw0=ADC_Read(); |
282 | UADC18=raw0*ref; |
283 | raw0=ADC_Read(); |
284 | UADC19=raw0*ref; |
285 | raw0=ADC_Read(); |
286 | UADC20=raw0*ref; |
287 | raw0=ADC_Read(); |
288 | UADC21=raw0*ref; |
289 | raw0=ADC_Read(); |
290 | UADC22=raw0*ref; |
291 | raw0=ADC_Read(); |
292 | UADC23=raw0*ref; |
293 | raw0=ADC_Read(); |
294 | UADC24=raw0*ref; |
295 | raw0=ADC_Read(); |
296 | UADC25=raw0*ref; |
297 | raw0=ADC_Read(); |
298 | UADC26=raw0*ref; |
299 | raw0=ADC_Read(); |
300 | UADC27=raw0*ref; |
301 | raw0=ADC_Read(); |
302 | UADC28=raw0*ref; |
303 | raw0=ADC_Read(); |
304 | UADC29=raw0*ref; |
305 | raw0=ADC_Read(); |
306 | UADC30=raw0*ref; |
307 | raw0=ADC_Read(); |
308 | UADC31=raw0*ref; |
309 | mem3=UADC0+UADC1+UADC2+UADC3+UADC4+UADC5+UADC6+UADC7+UADC8+UADC9+UADC10+ //... wie zuvor ... |
310 | UADC11+UADC12+UADC13+UADC14+UADC15+UADC16+UADC17+UADC18+UADC19+UADC20+ |
311 | UADC21+UADC22+UADC23+UADC24+UADC25+UADC26+UADC27+UADC28+UADC29+UADC30+ |
312 | UADC31; |
313 | raw0=ADC_Read(); //Messung #97 |
314 | UADC0=raw0*ref; |
315 | raw0=ADC_Read(); |
316 | UADC1=raw0*ref; |
317 | raw0=ADC_Read(); |
318 | UADC2=raw0*ref; |
319 | raw0=ADC_Read(); |
320 | UADC3=raw0*ref; |
321 | raw0=ADC_Read(); |
322 | UADC4=raw0*ref; |
323 | raw0=ADC_Read(); |
324 | UADC5=raw0*ref; |
325 | raw0=ADC_Read(); |
326 | UADC6=raw0*ref; |
327 | raw0=ADC_Read(); |
328 | UADC7=raw0*ref; |
329 | raw0=ADC_Read(); |
330 | UADC8=raw0*ref; |
331 | raw0=ADC_Read(); |
332 | UADC9=raw0*ref; |
333 | raw0=ADC_Read(); |
334 | UADC10=raw0*ref; |
335 | raw0=ADC_Read(); |
336 | UADC11=raw0*ref; |
337 | raw0=ADC_Read(); |
338 | UADC12=raw0*ref; |
339 | raw0=ADC_Read(); |
340 | UADC13=raw0*ref; |
341 | raw0=ADC_Read(); |
342 | UADC14=raw0*ref; |
343 | raw0=ADC_Read(); |
344 | UADC15=raw0*ref; |
345 | raw0=ADC_Read(); |
346 | UADC16=raw0*ref; |
347 | raw0=ADC_Read(); |
348 | UADC17=raw0*ref; |
349 | raw0=ADC_Read(); |
350 | UADC18=raw0*ref; |
351 | raw0=ADC_Read(); |
352 | UADC19=raw0*ref; |
353 | raw0=ADC_Read(); |
354 | UADC20=raw0*ref; |
355 | raw0=ADC_Read(); |
356 | UADC21=raw0*ref; |
357 | raw0=ADC_Read(); |
358 | UADC22=raw0*ref; |
359 | raw0=ADC_Read(); |
360 | UADC23=raw0*ref; |
361 | raw0=ADC_Read(); |
362 | UADC24=raw0*ref; |
363 | raw0=ADC_Read(); |
364 | UADC25=raw0*ref; |
365 | raw0=ADC_Read(); |
366 | UADC26=raw0*ref; |
367 | raw0=ADC_Read(); |
368 | UADC27=raw0*ref; |
369 | raw0=ADC_Read(); |
370 | UADC28=raw0*ref; |
371 | raw0=ADC_Read(); |
372 | UADC29=raw0*ref; |
373 | raw0=ADC_Read(); |
374 | UADC30=raw0*ref; |
375 | raw0=ADC_Read(); |
376 | UADC31=raw0*ref; |
377 | mem4=UADC0+UADC1+UADC2+UADC3+UADC4+UADC5+UADC6+UADC7+UADC8+UADC9+UADC10+ //Übergabe der Messwerte an die letzte |
378 | UADC11+UADC12+UADC13+UADC14+UADC15+UADC16+UADC17+UADC18+UADC19+UADC20+ //Speichervariable |
379 | UADC21+UADC22+UADC23+UADC24+UADC25+UADC26+UADC27+UADC28+UADC29+UADC30+ |
380 | UADC31; |
381 | mem=(mem1+mem2+mem3+mem4)/128; //Bildung des arithmetischen Mittels aus den 128 Messungen. |
382 | return mem/R1; //Berechnung des Stromes und Rückgabe |
383 | }
|
384 | |
385 | /* 2012, Robert Weidner */
|
Etwas lang geraten. Warum kein Array für deine Messwerte? Oder noch besser gleich Aufsummieren beim Wandeln?
Das sieht nach dem klassischen Job für einen PID Regler aus. Schau dir mal Application Note 221 von AVR an, dort wird ein sehr brauchbarer PID Regler beschrieben. Für deine Zwecke ist es vermutlich sinnvoll, die Werte für P, I und D zu exponieren und z.B. über ein Konsoleninterface einstellbar zu machen. Ebenso könntest du P,I und D über drei Kanäle deines AVR auf Potis legen und so regeln. Hast du brauchbare Werte mit annehmbarer Regelzeit und ohne Überschwingen, kannst du sie ins EEPROM oder Flash ablegen. wultna schrieb: > UADC5=raw0*ref; > raw0=ADC_Read(); > UADC6=raw0*ref; > raw0=ADC_Read(); > UADC7=raw0*ref; > raw0=ADC_Read(); usw. bis zum Ende des Flash.... Da musst du was tun. Das ist ja ungeheurer Speicherplatzverbrauch und ein einziger Tippfehler kippt das ganze Konstrukt.
@wultna (Gast) >nach tagelangem Grübeln ist es mir gelungen, eine Lösung für das Problem >zu finden. Leider kann ich nicht genau in Worte fassen, wie die Lösung >aussieht. Mir fehlen angesichts deines Postings auch die Worte! Mann O Mann. 1.) Lange Quelltexte gehören in den ANHANG, siehe Netiquette. 2.) Was soll dieser Unsinn?
1 | raw0=ADC_Read(); //Messung #97 |
2 | UADC0=raw0*ref; |
Schon mal was von Schleifen und Arrays gehört? >Eventuell kann jemand mal was damit anfangen. Nö. Ein gutes Beispiel, wie man es NICHT machen sollte. >Goto-Befehls ect. Ich wäre sehr froh darüber, wenn mir jemand ein paar >Verbesserungsvorschläge nennen könnte. >Der µC misst über zwei seiner internen AD-Wandler die Spannung über und >unter einem Shunt (etwa 100mΩ), welcher über dem Drain eines >BUZ11-Mosfet's liegt. Schlaue Leute packen den Shunt in den Source-Zweig und messen ganz einfach massebezogen ohne aufwändigen Differenzverstärker. >Der Source des Mosfet's liegt auf Masse, am Gate >des Mosfets liegt ein PWM-Ausgang des µC's, welcher mit einem kleinen >Tantalkondesator gegen Masse leicht HF-entstört wird. So ein Käse. Der MOSFET hat schon genug Gatekapazität. > Der Strom über den >Shunt soll nun mittels des Tastgrades aus dem PWM-Ausgang konstant >gehalten werden. Eine Skizze des Schaltplanes habe ich als Grafik >angehängt. Soviel zum Aufbau des analogen Teils. Dazu schaltet man einen passenden RC-Tiefpass hinter den Shunt und misst die mittlere Spannung = mittler Strom. Damit spart man sich schnelle AD-Messungen. >weitgehend ungeglättete PWM-Spannung messen muss, lasse ich die Messung >z.Zt. ca. 32x hintereinander mit einer kurzen Pause dazwischen >ausführen, und bilde anschließend das arithmetische Mittel aus diesen >Messwerten. Eben das spart man sich. >tastgrad=Periodenlänge*Anpassungsfaktor-Strom*Anpassungsfaktor >und erhalte somit am PWM-Ausgang eine Spannung, die ab einem gewissen >Strom über dem Shunt linear kleiner geregelt wird. Das ist ein verkorkster P-Regler. Der regelt aber nicht auf Null Fehler. >nämlich zu erwarten war, fängt des Regelkreis dann recht schnell an zu >oszillieren. ;-) >hinzufügen? Oder besser gefragt: wie hat dieser Mathematisch auszusehen? Man muss die Regelparameter richtig wählen. http://de.wikipedia.org/wiki/Regler http://de.wikipedia.org/wiki/Faustformelverfahren_%28Automatisierungstechnik%29 >Aus vielerlei Gründen möchte ich keinerlei analoge Dämpfungsglieder im >Laststromkreis einsetzen. Jaja, die vielerlei Gründe der streng geheimen Area51 Projekte. Mach es einfach wie der Rest der Welt, dann läuft das auch.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.