mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Servo am AtMega8


Autor: Adi A. (mateit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo µC-Freunde,

ich habe mal wieder ein Problem.
Und zwar möchte ich mich an diesem verschneiten Sonntag mit Servos 
beschäftigen. Dazu habe ich einen GWS IQ-200MG neben mir stehen und die 
Impulsleitung an PB1 meines AtMega8 angeschlossen. Den µC fahre ich bei 
1MHz internal Clock.
Soweit so gut.

Folgendes habe ich mir gedacht:
Der Servo erwartet ein PWM Signal mit einer Periodendauer von 20ms und 
darin einen Impuls von 1-2ms.
Um das zu realisieren habe ich das Datenblatt des Mega durchforstet und 
herausgefunden, dass ich den 16bit Timer benötige.
Der Timer zählt also von 0 an zu zählen, dabei soll er high an PB1 
(OC1A) führen. Nach 1000 Takten (also 1ms) soll er low führen - er muss 
demnach einen Compare Match Interrupt ausführen - darf dabei aber nicht 
zurückgesetzt werden.. Dann soll er bis 20.000 (20ms) zählen und erneut 
bei null anfangen - also Overflow-Interrupt.

Hier nun mein nicht funktionstüchtiger Code:
/***********************************/
/* Servo-Test                      */
/* 31.01.10                        */
/* F_CPU 1000000                   */
/***********************************/

#include <avr/io.h>
#include <avr/interrupt.h>


volatile unsigned char comp, overflow;

/***********************************/
/* init_servo function             */
/* sets registers                  */
/***********************************/
void init_servo()
{
  //fast pwm 10bit
  TCCR1A |= (1 << COM1A1) | (1 << WGM10) | (1 << WGM11) | (1 << WGM12);
  // prescaler 1
  TCCR1B |= (1 << CS10);

  //set top
  ICR1 = 20000; //20ms

  //drive to position
  OCR1A = 1000; //1ms - left stop

}

/***********************************/
/* main function                   */
/***********************************/
int main()
{
  //set DataDirectionRegisters
  DDRB |= (1 << PB1);
  
  // enable global interrupts
  sei();

  //start
  PORTB |= (1 << PB1);

  //call servo function
  init_servo();

  //endless loop
  while(1)
  {
    if( (comp == 1) || (overflow == 1) )
    {
      PORTB ^= (1 << PB1);
      comp = 0;
      overflow = 0;
    }

  }
  return 0;
}


/***********************************/
/* InterruptServiceRoutine         */
/***********************************/
ISR(TIMER1_COMPA_vect)
{
  comp = 1;
}

ISR(TIMER1_OVF_vect)
{
  overflow = 1;
}


Vielleicht noch zur Erläuterung:
  PORTB |= (1 << PB1); 
nutze ich, damit ich das Bit toggeln kann.

Ein Oszilloskop besitze ich leider nicht und kann daher auch nicht 
sagen, was gerade an PB1 anliegt.

Ich verstehe einfach nicht, was daran falsch ist. Stehe ich gerade voll 
auf dem Schlauch oder wo liegt der Fehler?

Ich hoffe Ihr könnt mir helfen.
Danke schon im Voraus.


Grüße
mateit

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Dann soll er bis 20.000 (20ms) zählen und erneut bei null anfangen - also 
>Overflow-Interrupt.

Für diese Stelle ist der Capture-Interrupt und nicht der 
Overflow-Interrupt zuständig.

MfG Spess

Autor: Markus Müller (mmvisual)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Um zu wissen was da am PWM Ausgang an kommt kann man sich auch mit einem 
kleinen RC-Glied behelfen.

R 10K an Port-Pin.
Andere Ende des R an C 100nF.
Andere Ande von C an GND.

Jetzt die Spannung von C mit einem Multimeter messen.

Beispiel:
CPU läuft mit 5V
so ist bei einem PWM von 50% Ein/Aus-Dauer die Spannung am C 2,5V
bei einem PWM von 2ms/20ms (10%) ist die Spannung am C 0,5V.

Es braucht also nicht zwingend ein Oszi. Ein einfaches Multimeter reicht 
da schon.

Damit man die Frequenz von 50Hz (20ms) messen kann, kann man da auch 
einfach ein Lautsprecher (über Kondensator) anschließen. Wenn sich der 
gleich anhört wied er Netzbrumm von einem Trafo, dann sind das etwa 
50Hz.

Ein Oszi ist ja schon was feines, wenn Du öfter was machst, dann ist ein 
Oszi eine gute Hilfe, vor allem spart man sich doch viele Stunden mit 
Rätsel Raten.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Noch einiges:

>  //fast pwm 10bit
>TCCR1A |= (1 << COM1A1) | (1 << WGM10) | (1 << WGM11) | (1 << WGM12);

WGM12 befindet sich in TCCR1B. Abgesehen davon willst du Timer-Mode 7 
benutzen. Der hat aber als Top $3FF (1023). Damit wird die Anweisung
ICR1 = 20000; //20ms sinnlos, da ICR1 hier überhaupt nicht mitspielt. Du 
hast hier 2 Timermodes durcheinander gebracht. Für dein Vorhaben ist 
Timer-Mode 14 sinnvoll.

MfG Spess

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.