PWM-generator

Från ElektronikWikin
Hoppa till navigering Hoppa till sök

Exempelkod på en interrupt driven PWM-generator till ATmega:s med timer.

Vad är det och vad kan man göra med den ?

Det är en fristående interrupt funktion (den använter 16-bitars timern) som fristående då genererar pulser för att styra tex. hobby servon. Det menar att du kan göra vad du vill i din kod utan att behöva göra annat än att säga till vart du vill att servona ska.

Till vilken Atmega är koden skriven?

Till ATmega32 men borde vara kompatibel med dom flesta som har en 16-bits timer.

Hur använder man den ?

Lägg till de två filerna i projektet (pwmsignals.h och pwmsignals.c) inkludera pwmsignals.h ( include "pwmsignals.h" ) i din kod och starta upp interrupterna med StartPWMSignals();

Nu har du upp till (max) 16 servopulser (de kan ändras med en #define som finns i koden, #define SERVOS 15)på PORTA och PORTB. Du kan gärna ändra så att andra portar används, då får du ändra funktionen port();

Från början så står alla servon på 1.5msec (mittenläget på servot) och för att vrida dom så kan då använda dessa funktioner:

void segmentsetdirectvalue(int segment,int16_t value);

för att sätta en position på ett servo, tex såhär för att köra servo 0 max till höger: segmentsetdirectvalue(0,2000); eller servo 7 max till vänster; segmentsetdirectvalue(0,1000);

Man kan också säga till interrupten att köra från en "vinkel" till en annan, då får man först läsa in "tiden" (i mikro sekunder) från interrupten:

unsigned long int timenow=usecselapsed();

lägga till lite (hur många micro sekunder man vill att det ska ta) till exempet en sekund:

unsigned long int timeend=timenow+1000000;

så är det bara att tala om för "interrupten" att vi vill tex. gå från längst till vänster till längst till höger för servo 3:

segmentset(3,timenow,1000,timeend,2000);

så kommer interrupten automatiskt att vrida servot från vänster till höger på en sekund. Tja, iallafall så kommer servot att försöka att klara av det.

Ett par andra liknande funktioner:


gå på Tid tid från läget Läget-1 till läget Läget-2 för servot Servo:

segmentsetnow(Servo,Tid,Läget1,Läget2);


eller gå från nuvarande läge till läget Läge på Tid tid:

segmentgoto(Servo,Tid,Läge);


Hur koden funkar : Signalerna genereras en efter annan, servo 0 puls, servo 1 puls , servo 2 puls osv. När sista servot har gjort sin puls kollas det om vi behöver vänta lite, alltså har rundan tagit typ minst 20msec (denna siffra kan man ändra, det är en #define i koden).

Detta är ju inte en optimal lösning, men det borde funka ok på typ upp till 10-15 servos antar jag, har genererat pulser för 16 men hade bara två servon för test inkopplade men det funkade bra (servona snurrade som dom skulle utan att hacka).


Koden

Jag lyckas inte lägga in koden direkt på sidan så det får bli en länk för tillfället: