Forum: Mikrocontroller und Digitale Elektronik Probleme mit Servoansteuerung auf Atmega mit C


von Mike (Gast)


Lesenswert?

Hi!

Ich versuche derzeit einen Servo mit einem ATmega328P anzusteuern.
Dieser sitzt in einem Arduino UNO. Dieser dient allerdings nur zur 
Stromversorgung, etc. Programmiert wird ohne Bootloader direkt aus 
AtmelStudio mit dem AVR ISP mkii.

Habe versucht den Code aus folgendem Artikel 
Modellbauservo Ansteuerung auf meine CPU anzupassen:
1
#define F_CPU 16000000UL
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <util/delay.h>
5
6
#define taster1 PB2
7
#define taster2 PB0
8
#define ausgang PB1
9
10
ISR( TIMER1_COMPA_vect )                // Interruptbehandlungsroutine
11
{
12
  OCR1A = 5000-OCR1A;      // Das Servosignal wird aus der Differenz von
13
  // Periodenlänge (5000*0.004ms=20ms) und letztem
14
  // Vergleichswert (OCR1A) gebildet
15
}
16
17
int main (void)
18
{
19
  DDRB &= ~((1<<taster1) | (1<<taster2));          // PB1 und PB2 ist Eingang
20
  DDRB |= (1<<ausgang);
21
  
22
  TCCR1A = (1<<COM1A0);                 // Togglen bei Compare Match
23
  TCCR1B = (1<<WGM12) | (1<<CS11) | (1<<CS10) ;      // CTC-Mode; Prescaler 64
24
  TIMSK1  = (1<<OCIE1A);                 // Timer-Compare Interrupt an
25
  
26
  OCR1A = 4625;                         // Neutralposition ist 4625 ((5000-4625)*0.004ms)=1,5ms); 2ms == 4500; 1ms == 4750
27
  
28
  sei();                                // Interrupts global an
29
  
30
  while( 1 ) 
31
  {
32
    if ( !(PINB & (1<<taster1)) ) 
33
    {       // Impuls-Zeit verlängern
34
      cli();
35
      OCR1A = OCR1A + 100;
36
      sei();
37
      _delay_ms(50);
38
    }
39
    
40
    if ( !(PINB & (1<<taster2)) ) 
41
    {       // Impuls-Zeit verkürzen
42
      cli();
43
      OCR1A = OCR1A - 100;
44
      sei();
45
      _delay_ms(50);
46
    }
47
  }
48
  return 0;
49
}

Irgendwas stimmt da aber nicht.

Ich bekomme an PB1 eine PWM mit ungefähr gleichbleibender Frequenz von 
ca. 49Hz.

Wenn ich für OCR1A beispielsweise mal 4500 einsetze, was ja 1ms 
Impulsdauer entsprechen sollte, bekomme ich aber eine Impulsdauer von 
ca. 17,2ms. Bei OCR1A = 4700 bekomme ich 18,4ms. Für OCR1A = 2000 ist 
die Impulsdauer 16,7ms.

Wenn ich nun für OCR1A 200 einsetze, verändert sich das Tastverhältnis 
über die Zeit.

Irgendjemand eine Idee, was ich falsch mache? Stimmen die Berechnungen 
für OCR1A so (Siehe Code)?

Grüße und schonmal danke!

von ChuckNorris (Gast)


Lesenswert?

Hallo,

ich glaube, du hast mehr als ein Problem. Das fiese daran ist, dass sich 
sowas immer als Überlagerung darstellt, wo es dann gilt, die 
verschiedenen Fehler "raus zu extrahieren".
Den ersten Schritt zu einem Ansatz hast du schon gemacht. Du schreibst, 
dass sich da etwas über die Zeit verändert. Dann kommentier erstmal 
alles was in der while Schleife ist aus (die Tasterabfragen). Da sind ja 
die "OCR1A = OCR1A +- 100;" Anweisungen drin. Die könnten für das 
zeitliche Verhalten verantwortlich sein.

Ich habe die Timer für Servoanwendungen immer im Fast PWM Modus laufen 
lassen und die Periodendauer ich glaub mit diesem InputCaptrue Register 
begrenzt.
Das geht so lange, wie du den Timer nur für Servos benutzt. Wenn du ihn 
noch als Zeitbasis für etwas anderes nutzten willst, musst du ihn 
einfach durchlaufen lassen. Dann löst du bei Comparematchen auf OCR1A/B 
noch den Interrupt aus und musst Differenzwerte berechnen (Überlauf 
beachten!!).  Hier könnte es dann wieder sinnvoll sein, mit dem Toggle 
on Match zu arbeiten ... KÖNNTE, kann mich nicht genauer erinnern.

von STK500-Besitzer (Gast)


Lesenswert?

Du togglest den Ausgang ja nur.
Du musst den Ausgang beim Overflow einschalten und beim OC-Event wieder 
ausschalten. Das erledigt der FastPWM-Mode, wenn man ihn richtig 
konfiguriert.

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.