Hallo,
gerade bin ich dabei, mal einen standesgemäßen PID Regler (Lageregelung
Motor) aufzubauen und habe dazu folgendes Programm erstellt:
1 | static int16_t eOld;
|
2 | static int32_t eSum;
|
3 | uint8_t tmp_sreg;
|
4 | int16_t e;
|
5 | int16_t eDiff;
|
6 | int32_t y_P = 0;
|
7 | int32_t y_I = 0;
|
8 | int32_t y_D = 0;
|
9 | int32_t y;
|
10 |
|
11 | if (iStatusFlags & FLAG_SLID_ENABLE) {
|
12 |
|
13 | CLEAR_INT;
|
14 | e = lSlidTargetPosition - lSlidActPosition;
|
15 | RESET_INT;
|
16 |
|
17 | // I Anteil begrenzt
|
18 | eSum += e;
|
19 | if (eSum > 5000) eSum = 5000;
|
20 | if (eSum < -5000) eSum = -5000;
|
21 |
|
22 | y_I = iSlidKiTa * eSum / 64;
|
23 |
|
24 | eDiff = e - eOld;
|
25 |
|
26 | // Reglergleichung PID
|
27 | y_P = iSlidKp * e / 256;
|
28 | y_D = iSlidKdTa * eDiff / 256 ;
|
29 | y = y_P + y_I + y_D;
|
30 |
|
31 | if (iDebug == 1) {
|
32 | UsartPuts("\ny_P: ");
|
33 | UsartPuts( ltoa( y_P, sOutString, 10 ));
|
34 | UsartPuts(" y_D: ");
|
35 | UsartPuts( ltoa( y_D, sOutString, 10 ));
|
36 | UsartPuts(" y_I: ");
|
37 | UsartPuts( ltoa( y_I, sOutString, 10 ));
|
38 | UsartPuts("\ne: ");
|
39 | UsartPuts( ltoa( e, sOutString, 10 ));
|
40 | UsartPuts(" eDiff: ");
|
41 | UsartPuts( ltoa( eDiff, sOutString, 10 ));
|
42 | UsartPuts(" eSum: ");
|
43 | UsartPuts( ltoa( eSum, sOutString, 10 ));
|
44 | UsartPuts("\n");
|
45 | iDebug = 0;
|
46 | }
|
47 |
|
48 | // Store e
|
49 | eOld = e;
|
50 |
|
51 | // Direction
|
52 | if (y > 0) SLID_FORWARD; else SLID_BACKWARD;
|
53 |
|
54 | // Norm y
|
55 | y = abs(y);
|
56 |
|
57 | // Set speed
|
58 | if (y > 255) SLID_SPEED = 255; else SLID_SPEED = y;
|
59 |
|
60 | // Check Timeout
|
61 | if (y < iSlidMinDeviation) {
|
62 | iStatusFlags |= FLAG_SLID_REACH;
|
63 | } else {
|
64 | iStatusFlags &= ~FLAG_SLID_REACH;
|
65 | if ((iSlidTimeoutCount > 0) && (labs(eDiff) > 20)) {
|
66 | if (iSlidTimeoutCount-- == 0) lErrorFlags |= ERR_SLID_TIMEOUT;
|
67 | }
|
68 | }
|
69 |
|
70 | }
|
Sorgen macht mir die Zeile:
y_P = iSlidKp * e / 256;
Hier wird nicht in int32_t gerechnet, sondern in int16_t, obwohl y_P als
32 bit definiert ist. Wie bringe ich gcc dazu, diesen Ausdruck gleich
als 32 bit zu berechnen ?
Ich kann ja e/256 in Klammern setzten. Dann funktioniert es auch Aber
ich verliere Genauigkeit dabei. Dann kann ich mir auch sparen, y_P als
32 bit zu definieren.
Gleiches gilt ja auch für die anderen beiden Regelparameter.
Die Teiler 64 und 256 stehen noch nicht fest. Ich bin noch am austesten
der Regelparameter.
Der Aufruf erfolgt indirekt über einen Timerinterrupt (Setzen eines
Flags im ISR und dann Aufruf im Hauptprogramm). Die Regelparameter
iSlidKp, iSlidKiTa und iSlidKdTa sind global und werden an anderer
Stelle aus dem EEprom ausgelesen.
Sonstige konstruktive Kritik am Code ist willkommen.
Gruß
Andy