Forum: Mikrocontroller und Digitale Elektronik Regelkreis mit ATMEGA32


von wultna (Gast)


Angehängte Dateien:

Lesenswert?

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

von K. D. (deka)


Lesenswert?

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
von Toto (Gast)


Lesenswert?

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 ?

von Euro (Gast)


Lesenswert?

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 !

von wultna (Gast)


Lesenswert?

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 */

von Gerd (Gast)


Lesenswert?

Etwas lang geraten. Warum kein Array für deine Messwerte? Oder noch 
besser gleich Aufsummieren beim Wandeln?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@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
Noch kein Account? Hier anmelden.