Forum: Mikrocontroller und Digitale Elektronik ATmega 644 Timer und Motorsteuerung, Problem mit PWM


von Marc H. (martrixmarc)


Lesenswert?

Guten Tag.
Ich habe derzeit ein Problem bei meiner Diplomarbeit. Ziel ist es einen 
Quadcopter zu bauen. Steuerung für Links Rechts Vor Zurück funktioniert 
schon alles. Allerdings habe ich das Problem das bei einem der Timer das 
PWM Signal nicht ganz stimmt.

Timer1: _|--|_|--|_|--|_|--|_|--|_

Timer2: _|--|_|--|______|--|_|--|_

In dieser kleinen GRafik habe ich versucht das Problem wiederzuegeben. 
Die beiden PWM Signale sollten eigentlich genau gleich sein. Allerdings 
fehlt bei Timer2 ein Teil.

Im Anhang habe ich den C Code angehängt.
Ich hoffe hier kann mir wer helfen. Ich glaube ja das der Fehler dadurch 
zustande kommt, weil ich die Timer auch verwende um das Signal der 
Fernsteuerung auszuwerten. Dies funktioniert durch Interrupts.

mfg Marc
1
#define F_CPU 2000000UL  // CPU Frequenz deklarieren
2
3
#include <avr/io.h>    //IO Pins einbinden
4
#include <avr/interrupt.h>  //Interrupts einbinden
5
#include <util/delay.h>    //Delay Funktion einbinden
6
7
8
volatile int flanke=0;
9
volatile int flanke1=0;
10
volatile int flanke2=0;
11
12
volatile int aktuell_pwm=0;
13
volatile int aktuell_pwm1=0;
14
volatile int aktuell_pwm2=0;
15
16
volatile int vornerechts=0;
17
volatile int vornelinks=0;
18
volatile int hintenrechts=0;
19
volatile int hintenlinks=0;
20
21
volatile int vornerechts2=0;
22
volatile int vornelinks2=0;
23
volatile int hintenrechts2=0;
24
volatile int hintenlinks2=0;
25
26
volatile int count = 0;
27
28
29
ISR(PCINT0_vect)
30
{
31
  if(flanke==0)
32
  {           
33
      TCNT1L = 0; //Timer auf null zurück
34
35
       //TCCR1B&= ~(1<<ICES1); //INT0-Pin auf fallende Flanke einstellen
36
       flanke=1;
37
  }
38
  else
39
  {
40
       flanke=0;
41
       //TCCR1B|=(1<<ICES1);    //INT0 auf steigende Flanke wieder aktivieren
42
       aktuell_pwm=TCNT1L;      //Zählerstand speichern
43
  }
44
45
}
46
ISR(PCINT1_vect)
47
{
48
    if(flanke1==0)
49
      {           
50
        TCNT2 = 0; //Timer auf null zurück
51
        flanke1=1;
52
      }
53
      else
54
      {
55
        flanke1=0;
56
        aktuell_pwm1=TCNT2;      //Zählerstand speichern
57
      count=1;
58
      }
59
}
60
ISR(PCINT2_vect)
61
{
62
    if(flanke2==0)
63
      {           
64
        TCNT1L = 0; //Timer auf null zurück
65
        flanke2=1;
66
      }
67
      else
68
      {
69
        flanke2=0;
70
        aktuell_pwm2=TCNT1L;      //Zählerstand speichern
71
      count=0;
72
    }
73
}
74
75
int abs(int z) 
76
{ 
77
  if (z>=0) 
78
  { 
79
    return z; 
80
  } 
81
  return -z; 
82
}
83
84
int main (void)
85
{
86
  //char my_buffer[120]; //Buffer einlesen
87
  //setup_uart(); // RS232 einrichten
88
89
90
91
  DDRA = 0x00;     //PINA0 als eingang deklarieren
92
    //PORTA = 0xff;    //PUllup Widerstand aktivieren
93
94
95
    PCICR |= (1 << PCIE0) | (1 << PCIE1) | (1 << PCIE2) | (1 << PCIE3);    // set PCIE0 to enable PCMSK0 scan
96
    PCMSK0 |= (1 << PCINT0);
97
  PCMSK1 |= (1 << PCINT8);
98
  PCMSK2 |= (1 << PCINT16);
99
  PCMSK3 |= (1 << PCINT27);  // set PCINT0 to trigger an interrupt on state change 
100
  // set PCINT0 to trigger an interrupt on state change 
101
    //EIMSK |= (1 << INT1) | (1 << INT2);    // set PCIE0 to enable PCMSK0 scan
102
    
103
    sei();                    //Interrupts anschalten
104
105
106
  DDRD |= (1 << PIND0) | (1 << PIND1);
107
  //DDRD &= ~(1 << PIND5);
108
    
109
  DDRD |= (1 << PIND4) | (1 << PIND5);
110
     DDRD |= (1 << PIND6) | (1 << PIND7); // PIN 6 & 7 auf Output setzen (PWM)
111
    DDRB = (1 << PINB4) | (1 << PINB3); // PIN 3 & 4 auf Output setzen (PWM)
112
113
114
  //Timer 2 PWM Settings
115
  TCCR2A = (1<<COM2B1) | (1<<COM2A1) | (1<<WGM20);
116
  TCCR2B = (1<<CS20) | (1<<CS21);
117
118
119
  //Timer 1 Prescaler setzen
120
  TCCR1B = (1<<CS10) | (1<<CS11);
121
122
123
  //Timer 0 PWM Settings
124
  TCCR0A = (1<<COM0B1) | (1<<COM0A1) | (1<<WGM00) | (1<<WGM01); //Fast PWM OCRA TOP TOP
125
  TCCR0B = (1<<CS00) | (1<<CS01);
126
127
128
  while(1)
129
    {
130
    if (aktuell_pwm >= 0 && aktuell_pwm < 100)
131
      {  
132
133
      OCR0A = 10;
134
      OCR0B = 10;
135
136
      OCR2A = 10;
137
      OCR2B = 10;
138
      }  
139
    else if (aktuell_pwm >= 100)
140
      {
141
      //LINKS - RECHTS
142
      if (aktuell_pwm1 < 96 && aktuell_pwm1 > 10)
143
        {  
144
        hintenrechts = abs(aktuell_pwm1-110)/3; //rechts hinten
145
        vornerechts = abs(aktuell_pwm1-110)/3;
146
        }
147
    
148
      else if(aktuell_pwm1 > 150)
149
        {
150
        hintenlinks = abs(aktuell_pwm1-110)/3;
151
        vornelinks = abs(aktuell_pwm1-110)/3;
152
        }  
153
      else if(aktuell_pwm1 < 150 && aktuell_pwm1 > 96)
154
        {
155
        hintenrechts = 0;
156
        vornelinks = 0;
157
        hintenlinks = 0;
158
        vornerechts = 0;
159
        } 
160
161
      //VOR - ZURÜCK
162
      if (aktuell_pwm2 < 96 && aktuell_pwm2 > 10)
163
        {  
164
        vornelinks2 = abs(aktuell_pwm2-110)/3; //rechts hinten
165
        vornerechts2 = abs(aktuell_pwm2-110)/3;
166
        }
167
    
168
      else if(aktuell_pwm2 > 150)
169
        {
170
        hintenlinks2 = abs(aktuell_pwm2-110)/3;
171
        hintenrechts2 = abs(aktuell_pwm2-110)/3;
172
        }  
173
      else if(aktuell_pwm2 < 150 && aktuell_pwm2 > 96)
174
        {
175
        hintenrechts2 = 0;
176
        vornelinks2 = 0;
177
        hintenlinks2 = 0;
178
        vornerechts2 = 0;
179
        }       
180
181
182
      OCR0A = aktuell_pwm-hintenrechts-hintenrechts2; //rechts hinten
183
      OCR0B = aktuell_pwm-hintenlinks-hintenlinks2; // links hinten
184
        
185
      OCR2A = aktuell_pwm-vornelinks-vornelinks2; //links vorne
186
      OCR2B = aktuell_pwm-vornerechts-vornerechts2; //rechts vorne
187
188
      } 
189
  
190
    }
191
}

von Marc H. (martrixmarc)


Lesenswert?

little thumb up :)

von Marc H. (martrixmarc)


Lesenswert?

weiß denn keiner woran das liegen kann?

von Karl H. (kbuchegg)


Lesenswert?

Wenn du dich in den ISR am Timer vergreifst und dessen Zählerstand 
mutwillig veränderst, darfst du dich nicht wundern, wenn die 
Hardware-PWM durcheinander kommt.

Wenn ein Timer eine PWM eigenständig generieren soll, dann musst du den 
in Ruhe arbeiten lassen! Jede Einmischung von aussen am Zählerstand ist 
verboten und führt unweigerlich zum Schluckauf in der generierten PWM.

von Karl H. (kbuchegg)


Lesenswert?

Um ein Signal auszuwerten, muss man auch nicht den zuständigen Timer auf 
0 zurücksetzen. Oder stellst du dauernd deine Armbanduhr um, wenn du für 
eine Aktion eine Zeit stoppen sollst? Du merkst dir, wann das 
'Startereignis' eingetreten ist, zum Beispiel als der Sekundenzeiger auf 
48 stand, und wann das Endereignis eingetreten ist, zum Beispiel steht 
der Sekudenzeiger dann auf 12, und aus der Differenz und dem Wissen, 
dass der Sekundenzeiger bei 60 konzeptionell wieder bei 0 beginnt 
errechnest du die Zeitdauer: 12 + 60 - 48 = 24 (in diesem Fall, da 12 - 
48 ein negatives Ergebnis bringen würde, was aber offensichtlich nicht 
richtig sein kann. Ein von einem Hochhaus fallender Ziegelstein kann 
dazu nicht eine negative Zeit benötigen). Die Aktion hat also 24 
Sekunden gedauert. Und das hast du festgestellt, ohne dass du deine 
Armbanduhr manipulieren musstest oder irgendetwas zurücksetzen musstest.

von Oliver S. (oliverso)


Lesenswert?

Marc Hiedl schrieb:
> //Timer 1 Prescaler setzen
>   TCCR1B = (1<<CS10) | (1<<CS11);

Laut deinem Programm läuft Timer 1 im Normal-Modus ohne PWM. Also ist 
das entweder nicht das echte Programm, oder das falsche Diagramm.

Ansonsten pfuschst du ja lustig in den Zählerständen rum. Was da wann 
warum und wie passiert, kann dir so keiner sagen.

Schmeiß alles raus, was nicht mit dem Problem zu tun hat, und wenn das 
Problem dann noch da ist, zeig das hier mit einem compilierbaren !!! 
Programm als Anhang !!!.

Oliver

von Marc H. (martrixmarc)


Lesenswert?

Sorry ich meinte natürlich Timer0

Das mit dem wert merken und dann einfach abziehen und so die 
Zeitdifferenz berechnen werde ich mal ausprobeiren :)

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.