pwm_modulation.c


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