mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Servos und PWM


Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich habe ein kleines Programm geschrieben, welches über zwei taster ganz 
simpel einen servo einmal nach links und einmal nach rechts ausschlagen 
läßt. das nacch links ausschlagen funktioniert auch soweit. (ich hatte 
in einem beitrag gelesen, das 2ms voller ausschlag zur einen und 1ms 
voller ausschlag zur anderen seite ist.) nach rechts jedoch bleibt er 
ungefär in mittelstellung stehen. kein problem dachte ich mir, 
verringerst du die zeit unter ein ms. hier trat folgendes problem auf. 
bei 0 ms verzögerung drehte sich der servo hin und her, als ich wenn ich 
anstatt der funktion _delay _ms(); _delay_us(); nehme mechert avr studio 
rum. er will die ganze zeit neu kompilieren und so. diese funktion 
benötige ich aber spätestenz, wenn ich zwischenstellen zwischen 
ausschlag rechts und ausschlag links haben möchte.

hier erstmal mein code:
#define __OPTIMIZE__ // Code Optimieren für richtige verzögerungszeit

#define F_CPU 8000000
 

#include <avr/io.h>
#include <util/delay.h>


int8_t flag;


void left(){  // Funktion linksdrehung

  _delay_ms(20); 

  PORTB |= (1 << 0);    /* setzt Bit 0 an PortC auf 1 */

  _delay_ms(2); 

  PORTB &= ~(1 << 0);   /* loescht Bit 0 an PortC */

  _delay_ms(20);

  PORTB |= (1 << 0);    /* setzt Bit 0 an PortC auf 1 */

  _delay_ms(2); 

  PORTB &= ~(1 << 0);   /* loescht Bit 0 an PortC */

}

void right(){  // funktion rechtsdrehung

  _delay_ms(20); 

  PORTB |= (1 << 0);    /* setzt Bit 0 an PortC auf 1 */

  _delay_us(1000);  // 1 ms warten für rechtsdrehung

  PORTB &= ~(1 << 0);   /* loescht Bit 0 an PortC */

  _delay_ms(20);

  PORTB |= (1 << 0);    /* setzt Bit 0 an PortC auf 1 */

  _delay_us(1000);   // 1 ms warten für rechtsdrehung

  PORTB &= ~(1 << 0);   /* loescht Bit 0 an PortC */

}



int main(){




DDRB = 0xff;
DDRD = 0x00;

while(1==1){

  while(!(PIND & (1 << 0))){  // bit 1 wird abgefragt gesezt (Taster abfragen)
  _delay_ms(100); 

     left(); //(links drehen)
 
  }


  while(!(PIND & (1 << 1))){  // bit 2 wird abgefragt gesezt (Taster abfragen)
  _delay_ms(100); 
 
     right();  //(rechts drehen)
 
  }




}


}

hier die Fehlermeldung:


avr-gcc.exe  -mmcu=atmega8515 -Wall -gdwarf-2 -O0 -MD -MP -MT servo.o 
-MF dep/servo.o.d  -c  ../servo.c
c:/winavr-20071221/bin/../avr/include/util/delay.h: In function 'right':
c:/winavr-20071221/bin/../avr/include/util/delay.h:143: sorry, 
unimplemented: inlining failed in call to '_delay_ms': function not 
considered for inlining
c:/winavr-20071221/bin/../avr/include/util/delay.h:116: sorry, 
unimplemented: called from here
c:/winavr-20071221/bin/../avr/include/util/delay.h:143: sorry, 
unimplemented: inlining failed in call to '_delay_ms': function not 
considered for inlining
c:/winavr-20071221/bin/../avr/include/util/delay.h:116: sorry, 
unimplemented: called from here

ich benutze das stk500 mit einem 8515 und programmiere in c.



Mach ich villeicht bei der PWM was falsch???

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Delay-Funktion (kann auch ein Makro sein...) hat einen möglichen 
Wertebereich, der von der Taktfrequenz abhängt.
Möglicherweise hängt dein Problem damit zusammen.
Das vermute ich aber auch nur. Mit der Funktion habe ich noch nie 
gearbeitet,  da es meiner Meinung nach einfacher ist, einen Timer 
entsprechend zu konfigurieren.

Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gut ich werde das mal probieren. hab ich noch nie gemacht mal sehen 
danke erstmal

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
http://www.hanneslux.de/avr/mobau/7ksend/7ksend02.html

Ist zwar in Assembler, erklärt aber, wie man Impulse für Servos in 
Software (also ohne Nutzung der Hardware-PWM) erzeugen kann.

...

Autor: Olaf Dreyer (Firma: O.D.I.S.) (dreyero)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich baue auch gerade eine Servosteuerung.
Die PWM muß aber eine Periode von 20ms und ein Pulsbreite von 1 bzw. 2 
ms haben. Also _delay_ms(100) kann nicht funktionieren.

Gruß

Olaf

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Die PWM muß aber eine Periode von 20ms und ein Pulsbreite von 1 bzw. 2
>ms haben.

Nee, muß sie nicht!

Autor: Olaf Dreyer (Firma: O.D.I.S.) (dreyero)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
STK500-Besitzer wrote:
>>Die PWM muß aber eine Periode von 20ms und ein Pulsbreite von 1 bzw. 2
>>ms haben.
>
> Nee, muß sie nicht!

Stimmt... Es schadet aber trotzdem nicht, so zu tun, als käme der Impuls 
aus einem handelsüblichen RC-Empfänger.

-------------

Und lasst den Blödsinn mit den Warteschleifen, das bisschen 
Servo-Impulstelegramm erzeugt ein AVR ganz nebenbei in einer 
State-machine im Timer-Interrupt, wobei nur wenige Prozent 
Rechenleistung beansprucht werden. Der Mainloop steht also weiterhin 
fast die gesamte Rechenleistung zur Verfügung.

...

Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gibts dazu ne gute anleitung oder ein tutorial, weil ich weder mit 
timern noch mit externen interrupts bei einem avr gearbeitet habe.

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sönke Paschko wrote:
> gibts dazu ne gute anleitung oder ein tutorial, weil ich weder mit
> timern noch mit externen interrupts bei einem avr gearbeitet habe.

Ist das jetzt Dein Ernst???

Im oben genannten Link wird der Programmablauf mit normalem Deutschen 
Text beschrieben. Der beiliegende Quelltext ist sehr üppig kommentiert, 
den versteht man auch ohne fundierte ASM-Kenntnisse. Ein Blick ins 
Datenblatt des AVRs ist allerdings nötig, denn wenn man die Architektur 
des verwendeten Controllers nicht kennt, kann man auch das beste 
Programm oder Tutorial nicht verstehen.

...

Autor: Peter Bünger (pbuenger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Um zwei Servos an den OC1A und OC1B Pins eines Tiny 2313 zu betreiben 
reicht schon eine Handvoll Codezeilen:
// Servo Frame-Time:
#define FRAME_TIME 20 // msec

// init timer 1:
ICR1   = FRAME_TIME * 1000;                      // PWM cycle time in usec
TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11); // OC1A/B clr on match, set on TOP
TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11);    // TOP = ICR1, clk = sysclk/8 (->1us)
TCNT1  = 0;                                      // reset Timer

OCR1A  = 1000;    // set Servo 1 to 1ms-position
OCR1B  = 2000;    // set Servo 1 to 2ms-position 

Durch die Verwendung der Output-Compare-Funktion des 16bit-Timers 1 
bleiben die Servos gesteuert, ohne dass der Prozessor auch nur einen 
einzigen Befehl dazu abarbeiten müsste. Er muss lediglich die 
OCR-Register passend beschreiben, wenn die Servos bewegt werden sollen.

Gruß,
Peter

Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
so damit hast du jezt den timer gestartet oder was???

was ist OCR1A?
was ist OCR1b?

wan wird ein Pin für pwm beschrieben, oder muss ich das selbst machen 
wenn ja wann?

zum Datenplatt, im datenblatt steht nur, das man einen prescaler 
benutzen kann, jedoch weder wie man ihn benutzt noch wie man den timer 
initialisiert.

Autor: Peter Bünger (pbuenger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> so damit hast du jezt den timer gestartet oder was???
Mal nebenbei: Wenn Du hilfreiche Antworten haben willst, darfst Du auch 
gerne einen Tick freundlicher sein. Danke.

Zum Timer: Guck Dir mal im Datenblatt den Teil vom Timer 1 an, speziell 
den "Fast PWM Mode". Dort steht genau beschrieben, wie die Ausgangspinne 
OC1A und OC1B gesteuert werden.

Der Timer selbst läuft immer zwischen Null und einer Obergrenze. Hat er 
die erreicht, fängt er wieder bei Null an. Bei meiner Konfiguration gibt 
ICR1 die Obergrenze vor, welche ich auf 20000 gesetzt habe. Programmiert 
man jetzt noch den Vorteiler auf 8, so rennt der Timer bei einem 8MHz 
Quartz in 1us-Schritten von Null bis 20ms, was genau der 
RC-Wiederholungsrate entspricht.

Die Compare Register steuern die Ausgangspins: Beim Sprung des Timers 
auf Null werden sie gesetzt, überschreitet der Timers die Werte in 
OCR1A/OCR1B, wird der entsprechende Pin auf low gesetzt. Du musst halt 
nur in OCR1A/OCR1B eine Zahl zwischen 1000 und 2000 eintragen, das gibt 
dann die gewünschten 1...2ms Pulsbreite mit 20ms Abstand.

Ach ja, die Pins OC1A und OC1B müssen unbedingt als Ausgänge gesetzt 
sein.

Gruß,
Peter

Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke, ich meinte das nicht böse oben,dein text ist echt super so hab 
ichs verstanden.

einen nachteil hat das doch aber weil oc1a an ein pin gekoppelt ist und 
sich damit also nur ein servo steuern läßt. kann man das nicht so lösen, 
das eine Interruptrutine aufgerufen wird, die dann die Pins steuert, 
sodass auch mehrere Pins geschaltet werden können?

Autor: Peter Bünger (pbuenger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, und mit OC1B steuerst Du ein zweites Servo. Wenn's mehr sein soll, 
brauchst Du entweder einen AVR mit mehr 16-Bit PWMs oder eine 
Softwarelösung. Du hattest aber in Deinem Initialposting auch nur von 
einem Servo geschrieben.

Gruß,
Peter

Autor: Gustav K. (hanibal)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo, ich habe veruscht den code zu verwende, aber irgendwie 
funktiioniert der nicht.

#include <avr/io.h>

int main()
{

  DDRB = (1 << PB1 );
  DDRB = (1 << PB2 );
// Servo Frame-Time:
#define FRAME_TIME 20 // msec

// init timer 1:
ICR1   = FRAME_TIME * 1000;                      // PWM cycle time in 
usec
TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11); // OC1A/B clr on match, 
set on TOP
TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11);    // TOP = ICR1, clk = 
sysclk/8 (->1us)
TCNT1  = 0;                                      // reset Timer

OCR1A  = 1000;    // set Servo 1 to 1ms-position
OCR1B  = 2000;    // set Servo 1 to 2ms-position


  while( 1 )
    ;
}


frequenz ist 8 mhz internal. und servo ist an pb1 angeschlossen.

Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kannst du mit nem Osziloskop mal gucken, ob die Pulsweiten stimmen? bzw. 
ob überhaupt was rauskommt

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  DDRB = (1 << PB1 );
>  DDRB = (1 << PB2 );

Demnach ist nur noch PB2 ein Ausgang.

Schreib es lieber so:

  DDRB = (1 << PB1 ) | (1 << PB2 );

>Kannst du mit nem Osziloskop mal gucken, ob die Pulsweiten stimmen? bzw.
>ob überhaupt was rauskommt

Einfacher: Häng eine LED an einen Port und lass sie im Sekundentakt 
blinken.

Autor: Gustav K. (hanibal)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
oh, wie peinlich, das hätte mir auch auffallen solln.

PS: wenn man eine led dranhängt, ans pwm signal kann man auch gucken, ob 
die gedimmt ist.

Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wobei man das bei meinen LEDs nicht immer so genau sieht finde ich- aber 
Blinken ist natürlich das beste

Autor: Hannes Lux (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das kleine Hemdentaschenmultimeter von Pollin Best.Nr. 830 096 zum Preis 
von 12,95 EUR hat unter Anderem auch einen Frequenzmessbereich mit dem 
man die Periodendauer messen kann. Dieser lässt sich auf Tastgradmessung 
umschalten, was das Messen der relativen Impulsbreite ermöglicht. Bei 
einem Servoimpuls von 1.0 bis 2,0 ms im Abstand von 20 ms sind das 5 bis 
10 % Tastgrad.

Ich möchte weder gegen ein Oszilloskop diskutieren, noch Werbung für 
Pollin machen, aber die Anschaffung dieses kleinen schnuckligen 
Mini-Multimeters sollte auch als sparsamer Bastler drin sein. Das 
amortisiert sich schnell.

...

Autor: Gustav K. (hanibal)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stimmt, mein multimeter hat auch duty cicle messung und frequenzmessung, 
funktioniert super, hab die werte gerade nachgerechnet, stimmt fast 100% 
genau

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.