ATmega 644 Timer und Motorsteuerung, Problem mit PWM

#4019467
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
}
#4028142
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.
#4028154
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.
#4028176
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren