mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ATMega16 und 4Servos


Autor: Johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

ich wuerde gerne wissen ob ich die Forumsbeitraege bezueglich Servos
richtig verstanden habe! Hier mein Vorhaben (arbeite mit ATMega16
(16MHz), WinAVR-GCC):

Ich will insgesamt 4 Servos ansteuern; das Hauptprogramm hat einiges zu
rechnen (ca. 20 * sin/cos/atan u.a. pro Durchlauf).

Ich opfere einen Timer der mir alle 3 Sekunden einen Interrupt erzeugt
waehrend dem ich nacheinander fuer die 4 Servos einen Puls(5V) von
1ms...2ms erzeuge. Ausserhalb dieser Impulse sind die Servo-Pins
low(0V). Das ergibt eine maximale Periodendauer von 4*(3+2)=20ms und
eine minimale von 4*(3+1)=16ms. In den jeweils 3ms zwischen den
Interrupts lass ich dem uC Zeit fuer meine sin, cos usw...

richtig/falsch gedacht? prinzipielle Verbesserungen?

danke allen Erfahrenen!
mg,
Johannes

Autor: Fritz Ganter (fritzg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bin mir nicht sicher, aber brauchen die Servos nicht alle 20ms den
Impuls? ich glaub bei mir war es so, sonst drehen die durch.

Autor: Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du könntest auch den Timer dauernd einen 1-2ms-Impuls erzeugen lassen -
das würde die Servos nicht stören. Einfach in der ISR einen neuen
OC-Wert setzen und das nächste Servo einschalten. Und das im Kreis
herum...
Die Werte würden dann in einem Feld liegen, dessen Einträge durch die
Berechnungen (vermutlich) verändert werden. Bei 4 Servos hat man dann
sogar eine Simpel-Ringpuffer-taugliche Zahl...

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich denke mal deine 3 sekunden sollen Millisekunden sein...
das mit Timer und Interrupt ist die eleganteste Lösung vergiss blos die

volatile für die Servowerte nicht.
Der Stellbereich von Servos liegt zwischen 0,8 und 2,2 ms mit 1 bis
2ms
bekommt man je nach Typ nicht die vollen 180 grad. Danach solltest du
ihnen etwas Zeit lassen.
Etwas besser ist es nur jeweils die High Zeiten für das jeweilige Servo
zu nehmen und dann eine Wartezeit bis 20ms einzulegen.
Also in Timerinterrupt:

1.
Servo1 auf 1
Lade Zeit für Servo1 in Timer
Timer starten
raus aus interrupt

beim nächsten Timerinterrupt
Servo1 auf 0
Servo2 auf 1
Lade Zeit für Servo2 in Timer
Timer starten
raus..

etc. bis zum letzten Servo

dann Servox auf 0
Lade verbleibende Zeit bis 20ms
Timer starten
raus..

danach wieder zu 1.

damit kannst du 10 Servos (bei max 2ms) betreiben und bleibst in der
Spezifikation von 20ms.
Wobei die meisten Servos auch eine längere Ruhepause akzeptieren.
Dein Mikrocontroller hat für seine Berechnungen dabei die ganze Zeit
abzüglich der paar Mikrosekunden für den Timerinterrupt.

Autor: Johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

danke fuer eure Beitraege, ganz besonders @Wolfram!!

Ich hab mal mit dem Timer angefangen und nach vielem Probieren und
Ueberlegen nicht herausgefunden, warum mein Timer nicht geht?!
warscheinlich ists ein Trivialikus den ich ueberseh.  Die LEDs an PortC
tun gar nix; eigentlich sollten eines 1s an, und danach 1s aus sein.
Hier der Code:
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <avr/signal.h>


#ifndef F_CPU
#define F_CPU 16000000           /* Oszillator-Frequenz in Hz */
#endif

#define UART_BAUD_RATE 9600
#define UART_BAUD_CALC(UART_BAUD_RATE,F_OSC)
((F_CPU)/((UART_BAUD_RATE)*16L)-1)

//globals
volatile uint8_t counter;

/*------Interrupt Service Routines---------------*/
/* output compare ISR, executed when TCNT1 = OCR1A*/
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
counter++;
}


/*------------------------------Functions------------------------------- 
--*/
void timer16_load(uint16_t microsec)
{
//Zeitbasis fuer diesen Timer sind 0.5us, deswegen wird microsec mal
zwei genommen (um eine Stelle geshiftet)

// microsec = 2     ->  OCF1A-interrupt in 2 us
// microsec = 1000  ->  OCF1A-interrupt in 1 ms
OCR1A = (uint16_t)(microsec<<1);  //loading timer-interrupt value
}

int main(void)
{

// Timer1 (16bit) config

   //prescaler = 8; -> Zeitbasis =0.47us ~= 0.5us
   CLEARBIT(TCCR2, CS22);
   SETBIT(TCCR2, CS21);
   CLEARBIT(TCCR2, CS20);

   //setting CTC mode = clear timer on compare
   SETBIT(TCCR1B, WGM12);

   //enable output compare interrupt (when TCNT1=OCR1A)
   SETBIT(TIMSK, OCIE1A);

//other initialization stuff
 counter = 0;
 DDRC = 0XFF;
 PORTC = 0x00;

 sei();
 timer16_load(32000);  //load 32ms in den Timer
 for(;;)
 {
  if (counter>=31)   //31*32ms = 992ms ~= 1s
       SETBIT(PORTC,PC3);
  else CLEARBIT(PORTC,PC2);

  if (counter>= 62) counter=0;

 }//for(;;)

}//main()


also wer sieht den Fehler??

Autor: Johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
SETBIT und CLEARBIT sollen natuerlich dasselbe bit PC2 verwenden. Das
hatte ich nur aus Testzwecken geaendert...

Autor: Johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

also ich hab's. Es ist tatsaechlich ein Trivialikus gewesen:

Ich hab staendig vom Timer1 geredet und gelesen und gesucht und
Register gechecked bis mir ... grgrgrgr

Sollte jemand meinen obigen Code verwenden muessen folgende drei Zeilen
ersetzt werden:

CLEARBIT(TCCR2, CS22);
SETBIT(TCCR2, CS21);
CLEARBIT(TCCR2, CS20);

zu ersetztn durch:

CLEARBIT(TCCR1B, CS22);
SETBIT(TCCR1B, CS21);
CLEARBIT(TCCR1B, CS20);

mg,
Johannes

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das dürfte aber noch nicht ganz richtig sein.
Jetzt mal ohne deine Werte nachzurechnen...
Der TimerInterrupt sollte eigentlich nur kommen, wenn im
Statusregister
allgemein Interrupts erlaubt sind.(zusätzlich zu TIMSK Interruptflag)
mit CLEARBIT/SETBIT änderst du die Bits einzeln nacheinander!
d.h. du setzt 3x eine andere Zeitbasis für den Timer ,der beim ersten
setzen losläuft. Dies hat in diesem Fall, da es unmittelbar
hintereinander geschieht wahrscheinlich keinen Einfluß, aber dein Timer
läuft los ,es könnte also ein Interrupt vor deinen 32ms auftreten.
Erst die Werte setzen dann eine Taktquelle an den Timer legen,denn dann
läuft er los.

Autor: AxelR. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
..Zitat
CLEARBIT(TCCR2, CS22);
SETBIT(TCCR2, CS21);
CLEARBIT(TCCR2, CS20);

zu ersetztn durch:

CLEARBIT(TCCR1B, CS22);
SETBIT(TCCR1B, CS21);
CLEARBIT(TCCR1B, CS20);
/Zitat

noch richtiger, obwohl das gleiche:

CLEARBIT(TCCR2, CS22);
SETBIT(TCCR2, CS21);
CLEARBIT(TCCR2, CS20);

zu ersetztn durch:

CLEARBIT(TCCR1B, CS12);
SETBIT(TCCR1B, CS11);
CLEARBIT(TCCR1B, CS10);

Beim Teilerfaktor 8 haut das alles noch hin. Dusseliger wird es, wenn
Du 256 vorteilen willst und alle drei Timer gleich initialisierst,
(weil du zB alle in deiner Applikation brauchst)
Dadurch, dass sich beim Timer2 der Faktor 1/128 "zwischenschiebt",
stimmt dann garnichts mehr.
Siehe Datenblatt
Seite 112 Tabelle 48 (Timer1 Prescaler)
und zum Vergleich
Seite 129 Tabelle 54 (Timer2 Prescaler)

Gruß
Axel

Autor: Johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

also die Bemerkung von Wolfram bezueglich Timerinitialisierung [dreimal
SETBIT() ist ungut -> verwende anstelle TCCR1B |=
(1<<CSxx)|(1<<CSxx)|(1<<CSxx) ] leuchtet mir ein! Danke fuer den
Hinweis.

@AxelR
In meiner Applikation verwend ich tatsaechlich manchmal alle Timer, und
zwar mit ganz unterschiedlichen Teilfaktoren. Ich versteh aber leider
nicht auf welches Problem du dich beziehst?
Die Timer sind doch unabhaengig voneinander; ich kann sie doch
initialisieren wo und wann ich will ohne dass sie sich beeinflussen.
Prescaler-Faktoren sind natuerlich teilweise unterschiedlich...
Sitz ich auf der Leitung? bitte um Aufklaerung.

mg,
Johannes

Autor: AxelR. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jahaa, war ja nur für die faulen..

ich hatte mir temp1(R16) mit den (für alle drei gleichen) Teilerfaktor
geladen und nacheinander die drei TCCRs damit geladen, da tanzte dann
ein Timer aus der Reihe.
ich weiss, Thema verfehlt, 6, setzen. :-)

Autor: Johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und ich habs nicht gechecked...
also auch setzn, 0b00000110

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.