Forum: Mikrocontroller und Digitale Elektronik PWM und Timer für Dumme


von Peter F. (piet)


Lesenswert?

Hallo!
Zuerstmal, ich hab mir schon einen Rechteck Generator mit Grafik LCD, 
variabler Pulsweite und Frequenz gebaut.
Auch ne Stoppuhr im ms Sekunden bereich mit GLCD hab ich hin bekommen 
aber ich bekomm es gerade nicht auf die Reihe ne simple Soft-PWM für nen 
Servo zu ralisieren die so funktioniert wie man erwarten sollte.

ATMega16 bei 5V und 16Mhz
Fuse auf ext. Crystal / High Freq
Das ganze in C

Ziel ist, Frequenz 50Hz, das sind 20ms.
Pulsweite von 1,5ms bis 2,5ms

Takt nach Prescaler:
16000000 / 8 = 2000000

Sekunde je Takt:
1 / 2000000 = 0,0000005000

Ein überlauf bei einem OCR0 wert von 200:
0,0000005000 / 200 = 0.0001 Sekunden

Zählschleife im Interrupt macht daraus 20ms wenn "pwmcounter" einen Wert 
von 200 hat:
0.0001 * 200 = 0,02 Sekunden

Jetzt wird "servo_pos[0]" mit "pwmcounter" vergliechen.
Eine Pulsweite von 1,5ms würde also einem "servo_pos[0]"-Wert von 150 
entsprechen.
Eine Pulsweite von 2,5ms würde also einem "servo_pos[0]"-Wert von 250 
entsprechen.

Da ist aber irgendwo ein Fehler drinn... Es geht nähmlich nicht, zum 
nachmessen habe ich leider nichts da...
Ich hab aber rausgefunden das ein Wert von 5 bis 20 den Servo zum 
bewegen bringt.
Habe drei verschiedene Servos:
Nummer1 geht mit werten von 5 bis 20
Nummer2 macht genau das gegenteil von Nummer1 mit werten von 5 bis 20
Nummer3 macht nur komische Sachen.

Wo hab ich den Fehler?

Aus dem Code:
1
// soft-PWM loop counter
2
uint8_t pwmcounter = 0;
3
4
// servo positions
5
volatile uint8_t servo_pos[10] = {15,16,16,16,16,7,22,40};

1
// initialise servos and timer
2
void init_servos(void) {
3
  
4
  // set servoport as output 
5
  SERVODDR = 0xFF;
6
  SERVOPORT = 0xFF;
7
8
  // soft-PWM timer0 in ctc mode with prescaler 8
9
  TCCR0 = (1<<WGM01) | (1<<CS01);
10
11
  // enable timer0 compare match interrupt
12
  TIMSK = (1<<OCF0);
13
14
  // timer0 compare value
15
  OCR0 = 200;
16
}

[c]
// timer0 soft-PWM interrupt
ISR(TIMER0_COMP_vect) {

  // when counter value is servo value set pin low
  if(pwmcounter == servo_pos[0]) {
    SERVOPORT &= ~(1<<SERVO0);
  }

  // reset soft-PWM counter set all pins high
  if( pwmcounter++ == 200) {
    pwmcounter = 0;
    SERVOPORT = 0xFF;
  }
}
[c]

von STk500-Besitzer (Gast)


Lesenswert?

>uint8_t pwmcounter = 0;

mach den mal volatile


Und das Thema "Modellservo ansteuern" hatten wir hier schon zuhauf...

von Karl H. (kbuchegg)


Lesenswert?

Peter F. schrieb:

> Zählschleife im Interrupt macht daraus 20ms wenn "pwmcounter" einen Wert
> von 200 hat:
> 0.0001 * 200 = 0,02 Sekunden
>
> Jetzt wird "servo_pos[0]" mit "pwmcounter" vergliechen.
> Eine Pulsweite von 1,5ms würde also einem "servo_pos[0]"-Wert von 150
> entsprechen.
> Eine Pulsweite von 2,5ms würde also einem "servo_pos[0]"-Wert von 250
> entsprechen.

Hmm
Ein Stück weiter oben hast du ausgerechnet, dass ein wert von 200 ganzen 
20ms entspricht. Und hier wäre dann ein wert von 250 auf einmal nur 
2.5ms?

Um es mit Ede Zimmermann zu sagen: Da stimmt doch was nicht.


Im übrigen: kleb nicht an den 20ms. Die sind das unwichtigste in der 
ganzen Ansteuerung.

PS2: Ein einzelnes Servo kann ein Timer auch ganz alleine in einem PWM 
Modus ansteuern.

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.