1 | /* ATmega644 programmieren */
|
2 | /* Testprogramm PWM-Modulation */
|
3 | /* Timer0 8-Bit; Zaehler */
|
4 | /* Timer1 16-Bit; PWM-Modus */
|
5 | /* Timer2 8-Bit; Zaehler */
|
6 | /* PID-Regler */
|
7 |
|
8 | /** C P U _ Definieren und BAUDRATE berechnen **/
|
9 | //*/
|
10 | #ifndef F_CPU
|
11 |
|
12 | #warning "F_CPU war noch nicht definiert, wird nun nachgeholt mit 20000000"
|
13 |
|
14 | #define F_CPU 20000000UL // Systemtakt in Hz - Definition als unsigned long beachten
|
15 | // Ohne ergeben sich unten Fehler in der Berechnung
|
16 | #endif
|
17 |
|
18 | #define BAUD 9600UL // Baudrate
|
19 |
|
20 | // Berechnungen
|
21 | #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) // clever runden
|
22 | #define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1))) // Reale Baudrate
|
23 | #define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
|
24 |
|
25 | #if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
|
26 | #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
|
27 | #endif
|
28 | //*/
|
29 |
|
30 | #include <avr/io.h>
|
31 | #include <stdint.h> //standardisierte Datentypen z.b typedef signed char int8_t;
|
32 | #include <stdlib.h>
|
33 | #include <avr/interrupt.h>
|
34 | #include <math.h>
|
35 |
|
36 | volatile unsigned char m = 0;
|
37 | volatile unsigned char n = 0;
|
38 | volatile unsigned char OldPegel = 0;
|
39 | volatile unsigned char Pegel = 0;
|
40 | volatile unsigned char OldPuls = 0;
|
41 | volatile unsigned char Puls = 0;
|
42 |
|
43 | volatile unsigned short i = 0;
|
44 | volatile unsigned short j = 0;
|
45 | volatile unsigned short k = 0;
|
46 | int16_t l = 0;
|
47 | volatile unsigned char zeichen = 0;
|
48 | volatile unsigned short counter = 0;
|
49 |
|
50 | volatile unsigned long pwm_Ein = 0;
|
51 | volatile unsigned long pwm_Gesamt = 0;
|
52 | volatile unsigned long pwm_Verhaeltnis = 0;
|
53 | volatile unsigned short test = 0;
|
54 | volatile unsigned short start = 0;
|
55 |
|
56 | volatile unsigned short sensor_Verhaeltnis = 0;
|
57 | volatile unsigned short sen_v = 0;
|
58 | volatile unsigned short sen_rps = 0;
|
59 | volatile unsigned short soll_wert = 0;
|
60 | volatile unsigned short ist_wert = 0;
|
61 |
|
62 |
|
63 | /***PID-Reglerwerte ***/
|
64 | volatile float q0 = 0;
|
65 | volatile float q1 = 0;
|
66 | volatile float q2 = 0;
|
67 | volatile float Kp = 0.1*0.5;
|
68 | volatile float Ki = 0;
|
69 | volatile float Kd = 0;
|
70 | volatile float Ta = 0.000012;
|
71 | volatile float e = 0;
|
72 | volatile float ealt = 0;
|
73 | volatile float ealt2 = 0;
|
74 | volatile float y = 0;
|
75 | volatile float yalt = 0;
|
76 |
|
77 | volatile float ausgang = 0;
|
78 | /***---------------------------------------port_set---------------------------------------------------------------***/
|
79 |
|
80 | /** Register, Directions, Ports und Pins setzten **/
|
81 | void port_set(void){
|
82 |
|
83 | // PORTA
|
84 | DDRA = (0<< DDA0) | (0<< DDA1) | (0<< DDA2) | (0<< DDA3) | (0<< DDA4) | (0<< DDA5) | (0<< DDA6) | (0<< DDA7); // PORTA: PIN: 0-3 = LED [H5- H8] ; PIN: 5-6 = Gyro; PIN: 4,7 = Schalter
|
85 | PORTA = (0<< PA0) | (0<< PA1) | (0<< PA2) | (0<< PA3) | (0<< PA4) | (0<< PA5) | (0<< PA6) | (0<< PA7) ; // PIN 1-4 = LED auf GND dann ON ! PU Widerstand bei Taster
|
86 |
|
87 | // PORTB
|
88 | DDRB = (0<< DDB0) | (0<< DDB1) | (0<< DDB2) | (1<< DDB3) | (1<< DDB4) | (1<< DDB5) | (0<< DDB6) | (0<< DDB7); // PORTB: PIN: 0-3 = LED [H1- H4]; PIN: 3 = OC0A
|
89 | PORTB = (0<< PB0) | (0<< PB1) | (0<< PB2) | (0<< PB3) | (0<< PB4) | (0<< PB5) | (0<< PB6) | (0<< PB7) ;
|
90 |
|
91 | // PORTD
|
92 | DDRD = (1<< DDD5); // PORTA: PIN: 5 = PWM OC1A 16_Bit auf Ausgang
|
93 | //PORTD = 0x00; //(1<<PD5);
|
94 |
|
95 | }
|
96 |
|
97 | /***---------------------------------------timer0---------------------------------------------------------------***/
|
98 |
|
99 |
|
100 | /** TIMER0 Einstellungen und Register **/
|
101 | void timer0_set(void){
|
102 |
|
103 | TCCR0A |= (0<<COM0A1) | (0<<COM0A0) | (0<<WGM01) | (0<<WGM00); // T/C0 Control Register A: normaler Modus
|
104 | TCCR0B |= (0<<WGM02) | (0<<CS02) | (0<<CS01) | (1<<CS00); // Starte Timer0 mit clk/1
|
105 | TIMSK0 |= (1<<TOIE0); // Fuer Interrupt Routine
|
106 |
|
107 | }
|
108 |
|
109 | /***---------------------------------------timer1---------------------------------------------------------------***/
|
110 |
|
111 |
|
112 | /** TIMER1 Einstellungen und Register **/
|
113 | void timer1_set(void){
|
114 |
|
115 |
|
116 | TCCR1A |= (1<<COM1A1) | (1<<WGM11) | (0<<WGM10); // T/C1 Control Register A: Fast PWM, TOP=ICRn, Update=BOTTOM, TOV Flag=TOP
|
117 | TCCR1B |= (1<<WGM13) | (1<<WGM12) | (0<<CS12) | (1<<CS11) | (0<<CS10); // T/C1 Control Register B: Prescaler = CLKcpu / 8
|
118 | //TIMSK1 |= (1<<OCIE1A);
|
119 |
|
120 | ICR1 = 0xc34f; // Output Compare Register 16-Bit = 50Hz = 49999dec bzw.0xc34f
|
121 | // Output Compare Register 16-Bit = 1 kHz = 0x09c3
|
122 |
|
123 | OCR1A = 0x0dde; // Output Compare Register 16-Bit = 3750 = 1.5ms = 0x0ea6 ;0x0f09 = 3850
|
124 | // Init bei 1.42ms = 3550 = 0x0dde
|
125 | //
|
126 | }
|
127 |
|
128 | /***---------------------------------------timer2---------------------------------------------------------------***/
|
129 |
|
130 |
|
131 | /** TIMER2 Einstellungen und Register **/
|
132 | void timer2_set(void){
|
133 |
|
134 | TCCR2A |= (0<<COM2A1) | (0<<COM2A0) | (0<<WGM21) | (0<<WGM20); // T/C0 Control Register A: normaler Modus
|
135 | TCCR2B |= (0<<WGM22) | (1<<CS22) | (1<<CS21) | (0<<CS20); // Starte Timer2 mit clk/256 = 78.125kH ;clk/1024 = 19.53125kHz
|
136 | TIMSK2 |= (1<<TOIE2); // Fuer Interrupt Routine
|
137 |
|
138 | }
|
139 |
|
140 | /*===================================== U A R T - INTERFACE =========================================================*/
|
141 |
|
142 | //USART - Initialisierung
|
143 | void usart_init(void){
|
144 |
|
145 | UBRR0H = UBRR_VAL >> 8;
|
146 | UBRR0L = UBRR_VAL & 0xFF;
|
147 |
|
148 | //test = UBRR_VAL;
|
149 |
|
150 | UCSR0A = (0<<RXC0) | (0<<UDRE0) | (0<<U2X0); //Double Speed Mode U2X0 = 1;
|
151 |
|
152 | UCSR0B = (1<<RXCIE0) | (1<<RXEN0) | (1<<TXEN0); //Aktiviert Reciever und Transmitter
|
153 |
|
154 | UCSR0C = (0<<UMSEL01) | (0<<UMSEL00) | (0<<UPM01) | (0<<UPM00) | (1<<UCSZ01) | (1<<UCSZ00); //Festlegung des Frames: 1 Startbit, 8 Datenbits, 0x26,
|
155 | // 1 Paritätsbit even, 1 Stoppbit
|
156 |
|
157 |
|
158 | }
|
159 |
|
160 | //USART - Transmitter
|
161 | //*/
|
162 | int uart_putc(unsigned char c)
|
163 | {
|
164 | while (!(UCSR0A & (1<<UDRE0))) // warten bis Senden moeglich
|
165 | {
|
166 | }
|
167 |
|
168 | UDR0 = c; // sende Zeichen
|
169 | return 0;
|
170 | }
|
171 |
|
172 |
|
173 | // puts ist unabhaengig vom Controllertyp
|
174 | void uart_puts(char *s)
|
175 | {
|
176 | while (*s)
|
177 | { // so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)"
|
178 | uart_putc(*s);
|
179 | s++;
|
180 | }
|
181 | }
|
182 | /*/
|
183 |
|
184 | // USART - Receiver
|
185 | /*/
|
186 | uint8_t uart_getc(void)
|
187 | {
|
188 | while (!(UCSR0A & (1<<RXC0))) // warten bis Zeichen verfuegbar
|
189 | ;
|
190 | return UDR0; // Zeichen aus UDR an Aufrufer zurueckgeben
|
191 | }
|
192 | //*/
|
193 |
|
194 | /*=================================== U A R T - INTERFACE - STOPP ==================================================*/
|
195 |
|
196 | /***---------------------------------------Start-Algorithmus---------------------------------------------------------------***/
|
197 |
|
198 | volatile unsigned short start_algo(void){
|
199 |
|
200 | while(n == 0){ // Endlosschleife bis der Motor Initialsiert wurde und
|
201 | // hochgefahren ist
|
202 | }
|
203 |
|
204 | }
|
205 |
|
206 | /***---------------------------------------PWM_Verhaeltnis---------------------------------------------------------------***/
|
207 |
|
208 | volatile unsigned short pwm_verhaeltnis(void){
|
209 |
|
210 | Pegel = PINB & 0x02; // Pegel = welchen Zustand hat der Pin gerade
|
211 |
|
212 | if(Pegel != OldPegel){ // hat sich was veraender ?
|
213 | // wenn ja, dann war eine Flanke an diesem Pin
|
214 |
|
215 | if(Pegel){ // was war das fuer eine Flanke ?
|
216 | // nachdem der Pin jetzt auf 1 ist, muss er
|
217 | // vorher auf 0 gewesen sein, und das ganze
|
218 | // war eine Flanke 0-> 1
|
219 |
|
220 | if (m < 1){ TCNT0 = 0x00; i=0; start_algo(); } // Setze Timer0 auf Anfangswert da erste Flanke nach Start von uC gemessen.
|
221 | // Starte den Motor über den Start Algorithmus
|
222 | m=m+1; // m = Merker
|
223 | // bevor erste "High"Flanke gemessen m=0;
|
224 | // ab erste "High" Flanke m=1
|
225 | // bei zweiter "High" Flanke m=2 -> Periode zu Ende
|
226 | if (m == 2){
|
227 |
|
228 | pwm_Gesamt = ((i<<8)+TCNT0); // Gesamtzeit
|
229 | TCNT0 = 0x00; // Setze Timer0 auf Anfangswert
|
230 | i=0;
|
231 | pwm_Verhaeltnis = ((pwm_Ein*100) / pwm_Gesamt) -2; //(pwm_Ein * ICR1) / pwm_Gesamt;
|
232 | OCR1A = (3850) + ((1150/100) * pwm_Verhaeltnis);
|
233 | //test = OCR1A;
|
234 | m=1;
|
235 | }
|
236 |
|
237 | }
|
238 |
|
239 |
|
240 | else{ // No, der Pin ist jetzt 0.
|
241 | // also muss das eine Flanke 1 -> 0 gewesen sein
|
242 |
|
243 | pwm_Ein = ((i<<8)+TCNT0); // Einzeit
|
244 |
|
245 | }
|
246 |
|
247 | OldPegel = Pegel; // jetzigen Zustand merken, damit im naechsten
|
248 | // Durchgang wieder eine Veränderung festgestellt
|
249 | // werden kann
|
250 | }
|
251 |
|
252 | return pwm_Verhaeltnis; // Rueckgabewert
|
253 | }
|
254 |
|
255 | /***---------------------------------------Sensor_Verhaeltnis---------------------------------------------------------------***/
|
256 |
|
257 | volatile unsigned short sensor_verhaeltnis(void){
|
258 |
|
259 | if (counter>=305){ // 1 Sekunde: 20*10^6/256(Prescaler)*256(Schritte) = 305,175.. OVFs/sec = 3 bei 10ms
|
260 |
|
261 | sen_v= (j*100) / 417; // 25.000 rpm = ca.417rps
|
262 | sen_rps = j; // Umdrehungen / Sekunde
|
263 | counter=0;
|
264 | j=0;
|
265 | }
|
266 |
|
267 | Puls = PINB & 0x04;
|
268 |
|
269 | if(Puls != OldPuls){
|
270 |
|
271 | if(Puls){
|
272 |
|
273 |
|
274 | }
|
275 |
|
276 | else{ // Flanke 1 -> 0
|
277 |
|
278 | j++;
|
279 |
|
280 | }
|
281 |
|
282 | OldPuls = Puls;
|
283 |
|
284 | sensor_Verhaeltnis = sen_v;
|
285 |
|
286 | }
|
287 | return sensor_Verhaeltnis;
|
288 | }
|
289 |
|
290 | /***---------------------------------------PID-Regler---------------------------------------------------------------***/
|
291 |
|
292 | volatile unsigned short pid_regler(volatile float s_wert, volatile float i_wert){
|
293 |
|
294 | /*
|
295 | q0=Kp+Ki*Ta+Kd/Ta; // Reglerfaktor q0
|
296 | q1=-Kp-2*Kd/Ta; // Reglerfaktor q1
|
297 | q2=Kd/Ta; // Reglerfaktor q2
|
298 |
|
299 | e = s_wert - i_wert; // Regler Differenz
|
300 | y = yalt + q0*e + q1*ealt + q2*ealt2; // Berechnung des PID- Ausgangs
|
301 | ealt2 = ealt;
|
302 | ealt = e;
|
303 | yalt = y;
|
304 | */
|
305 |
|
306 |
|
307 | ausgang = y;
|
308 | return ausgang;
|
309 | }
|
310 |
|
311 | void usart_drehzahl(volatile unsigned short rps){
|
312 |
|
313 | char s[7];
|
314 | int16_t l = rps;
|
315 | utoa( l, s, 10 ); // 10 fuer radix -> Dezimalsystem itoa = +/- .. utoa = +
|
316 | uart_puts( s );
|
317 |
|
318 | }
|
319 |
|
320 | /***----------------------------------------main--------------------------------------------------------------***/
|
321 |
|
322 |
|
323 | int main (void) {
|
324 |
|
325 | cli(); // INTERRUPT Enabled Bit OFF
|
326 | port_set(); // Initalisierung der Ports
|
327 | timer0_set(); // Initalisierung des Timer0
|
328 | timer1_set(); // Initalisierung des Timer1
|
329 | timer2_set(); // Initalisierung des Timer2
|
330 |
|
331 | usart_init(); //USART initialsieren
|
332 |
|
333 | sei(); // INTERRUPT Enabled Bit ON
|
334 |
|
335 | OldPegel = PINB & 0x02; // OldPegel = steigende Flanke an PB1
|
336 | OldPuls = PINB & 0x04; // OldPuls = steigende Flanke an PB
|
337 |
|
338 |
|
339 | while(1){
|
340 | soll_wert = pwm_verhaeltnis();
|
341 | ist_wert = sensor_verhaeltnis();
|
342 | //usart_drehzahl(ist_wert);
|
343 | //ausgang = pid_regler(soll_wert, ist_wert);
|
344 | //OCR1A = 3850 + (1150 * ausgang); //(1150 * ausgang)+3850;// Anfangswert fuer Brushlessregler bei 1,54ms = 3850dec bzw. 0x0f0a
|
345 | // Der Bereich in dem das Tastverhaeltnis umgestellt werden kann,
|
346 |
|
347 | //PORTB ^= (1<<PB3); //TA analysieren fuer PID-Regler // liegt zwischen 1.54ms = 3850 und 2ms = 5000 also delta = 1150 = 100%
|
348 | }
|
349 |
|
350 |
|
351 | }
|
352 |
|
353 | /*** INTERRUPT TIMER0 ***/
|
354 | ISR(TIMER0_OVF_vect){
|
355 | i++; // i zaehlt die OVFs
|
356 | }
|
357 |
|
358 |
|
359 |
|
360 | /*** INTERRUPT TIMER2 ***/
|
361 | ISR(TIMER2_OVF_vect){
|
362 |
|
363 |
|
364 | counter++; // counter zaehlt die OVFs
|
365 | test++;
|
366 |
|
367 | /* Startalgorythmus des BL Motors */
|
368 | if(test >= 4){
|
369 |
|
370 | test = 0;
|
371 |
|
372 | if( n!=1 ){
|
373 |
|
374 | OCR1A = OCR1A+1;
|
375 | start = OCR1A;
|
376 | PORTB |= (1<<PB3);
|
377 | }
|
378 |
|
379 | }
|
380 |
|
381 | if (start >= 0x0f6e){
|
382 |
|
383 | //PORTB |= (1<<PB4);
|
384 | //PORTB ~= (1<<PB3);
|
385 | OCR1A = 0x0f6e;
|
386 | n=1;
|
387 |
|
388 | }
|
389 |
|
390 | }
|
391 |
|
392 | //ISR-Recieve Complete
|
393 | ISR( USART0_RX_vect ){
|
394 |
|
395 | zeichen = uart_getc();
|
396 |
|
397 | switch (zeichen){
|
398 |
|
399 | case'1':
|
400 | uart_putc(ist_wert); //if(n<=>m){...}
|
401 | break;
|
402 |
|
403 | case'2':
|
404 | uart_putc(soll_wert);
|
405 | break;
|
406 |
|
407 | case'sprung':
|
408 |
|
409 | break;
|
410 |
|
411 | }
|
412 | }
|
413 |
|
414 | /*
|
415 | // Zeiten fuer den Motor //
|
416 | 1.55ms = 3850 = f0a
|
417 | 1.63ms = 4050 = fd2
|
418 | 1.66ms = 4150 = 1036
|
419 | */
|