denne artikkelen er i fortsettelse med forrige pwm innlegg. Lær hvordan du programmerer tidtakere til å operere i PWM-modus! Så la oss begynne!
Hei folkens! Lenge siden sist! 🙂
i mitt forrige innlegg har vi diskutert de grunnleggende konseptene FOR PWM. La oss oppsummere det først:
- PWM Står For Pulse Width Modulation.
- det kan genereres ved å sammenligne forhåndsbestemt bølgeform med et referansespenningsnivå eller ved å lage enkle analoge kretser.
- Driftssyklus av EN pwm-bølgeform er gitt av følgende forhold.
- Det er tre moduser AV pwm drift – Fast Pwm, Fase Riktig PWM Og Frekvens Og Fase Riktig PWM
- Hvordan velge timer, driftsmodus og sammenligne utgangsmodus for å generere ønsket PWM.
La oss ta en problemstilling. Vi må generere et 50 Hz PWM-signal med 45% driftssyklus.
Analyse
Gitt at
Frequency = 50 Hz
med andre ord, tidsperioden, T
T = T(on) + T(off) = 1/50 = 0.02 s = 20 ms
også, gitt at
Duty Cycle = 45%
dermed løser vi i henhold til ligningen gitt ovenfor, får vi
T(on) = 9 msT(off) = 11 ms
nå kan dette være oppnådd på to måter:
- Bruk Timer I CTC-Modus
- Bruk Timer I PWM-Modus
Metodikk-CTC-Modus
Ok, så jeg vil ikke skrive noen kode her (bare pseudokoden). Jeg antar at etter å ha lest mine tidligere innlegg, er du smart nok til å skrive en selv! Vi diskuterer bare konseptene.
Velg Først en passende timer. For dette programmet, kan vi velge noen av de tre timere tilgjengelig I ATMEGA32. Velg en passende prescaler. Sett deretter opp timeren og fortsett som vanlig. Fangsten ligger her er at du må oppdatere sammenligne verdien Av OCRx register hver gang. En slik måte er diskutert i pseudokoden gitt nedenfor.
dette er analogt med den tradisjonelle LED-flasheren, bortsett fra at av og på tider er forskjellige.
Pseudokode
#include <avr/io.h>#include <avr/interrupt.h> uint8_t count = 0; // global counter // initialize timer, interrupt and variablevoid timerX_init(){ // set up timerX with suitable prescaler and CTC mode // initialize counter // initialize compare value // enable compare interrupt // enable global interrupts} // process the ISR that is firedISR (TIMERx_COMPA_vect){ // do whatever you want to do here // say, increment the global counter count++; // check for the global counter // if count == odd, delay required = 11 ms // if count == even, delay required = 9 ms // thus, the value of the OCRx should be constantly updated if (count % 2 == 0) OCRx = 9999; // calculate and substitute appropriate value else OCRx = 10999; // calculate and substitute appropriate value} int main(void){ // initialize the output pin, say PC0 DDRC |= (1 << 0); // initialize timerX timerX_init(); // loop forever while(1) { // do nothing }}
Nå er dette en metode. Og det er veldig ineffektivt. Du kan øke effektiviteten ved å skrive en bedre C-kode( syntaksvis), men konseptet forblir det samme. Hvis du har noen annen metode/konsept, er du hjertelig velkommen til å dele den her! 🙂
UPDATE: En av leserne til maxEmbedded,» coolpales » har skrevet denne koden, og det fungerte for ham.
Vær oppmerksom på at denne koden ikke er testet ennå! Så, hvis noen av dere prøver det, legg inn resultatene dine her, jeg vil gjerne se dem! 🙂
Metodikk-PWM-Modus
Ok, så nå kan vi lære OM PWM-modusen. PWM-Modusen i avr er maskinvarestyrt. Dette betyr at alt, med alt jeg mener «alt», er gjort av AVR CPU. Alt du trenger å gjøre er å initialisere og starte timeren, og sette driftssyklusen! Kult, hva?! La oss lære hvordan!
Her har jeg brukt Timer0 AV ATMEGA32 for demonstrasjon. Du kan velge hvilken som helst annen annen timer eller avr mikrokontroller også. La oss nå se på registre.
TCCR0-Timer / Counter0 Kontroll Register
Vi har kommet over dette registeret i min Timer0 tutorial. Her lærer vi hvordan du setter passende biter for å kjøre timeren i PWM-modus.
Tccr0 Register
vi diskuterer bare de biter som er av interesse for oss nå.
- Bit 6,3-WGM01: 0 – Bølgeformgenereringsmodus-disse bitene kan settes til enten «00» eller » 01 » avhengig AV HVILKEN TYPE PWM du vil generere. Her er se opp tabellen.
Bølgeform Generasjon Modus Bit Beskrivelse
- Bit 5,4-COM01: 0-Sammenlign Match Output Mode-disse bitene er satt For å kontrollere oppførselen Til Output Sammenlign pin (OC0, pin 4 I ATMEGA32) i samsvar MED WGM01:0 bits. Folgende slå opp tabell bestemmer operasjonene TIL OC0 pin for Rask PWM-modus.
Sammenlign Utgangsmodus, Rask Pwm-Modus
nå kan vi se På De Raske pwm-bølgeformene. Detaljert forklaring finner du i min forrige opplæring.
Fast Pwm
la Meg nå minne deg på at AVR PWM er fullt maskinvarestyrt, noe som betyr at selv timeren sammenligner operasjonen er gjort av AVR CPU. ALT vi trenger å gjøre er å fortelle CPU hva du skal gjøre når en kamp oppstår. Com01: 0-pinnene kommer inn i spill her. Vi ser at ved å sette den til «10» eller «11», er output pin OC0 enten satt eller fjernet(med andre ord, det bestemmer om PWM er i invertert modus eller i ikke-invertert modus).
På Samme måte for Fase Riktig PWM, ser opp tabellen og bølgeformene slik ut.
Sammenlign Utgangsmodus, Fase Riktig Pwm-Modus
Phase Correct PWM
selv her bestemmer innstillingen COM01:0 til «10» eller «11» oppførselen TIL OC0 pin. Som vist i bølgeformene, er det to forekomster-en under opp-telling, og andre under ned-telling. Oppførselen er tydelig beskrevet i oppslagstabellen.
Vær oppmerksom PÅ AT OC0 er en utgangspinne. Dermed vil effektene AV WGM OG COM ikke komme inn i spill med mindre ddrx-registeret er satt riktig. Se denne opplæringen for mer info.
- Bit 2: 0-CS02: 0-Klokke Velg Biter – disse bitene er allerede diskutert I Timer0 opplæringen.
OCR0-Output Sammenlign Register
vi har kommet over selv dette registeret i min Timer0 tutorial. Vi bruker dette registeret til å lagre sammenligningsverdien. Men når Vi bruker Timer0 I PWM-modus, fungerer verdien som er lagret i den som driftssyklusen (åpenbart!). I problemstillingen er det gitt at driftssyklusen er 45%, noe som betyr
OCR0 = 45% of 255 = 114.75 = 115
og det er det! Nå er vi klare til å skrive en kode for det! 🙂
Rediger: Merk
følgende kode diskuterer hvordan du oppretter ET pwm-signal av en ønsket driftssyklus. Hvis du ønsker å endre frekvensen, må DU endre TOPPVERDIEN, som kan gjøres ved Hjelp Av ICRx-registeret (som ikke støttes av 8-bits timere). For 16-bit Timer1 kan den varieres VED HJELP AV ICR1A. jeg vil diskutere om dette snart når vi diskuterer om servokontroll.
Kode
så her går koden. For å lære om i/o-portoperasjoner i AVR, se dette. For å vite om bit manipulasjoner, se dette. For å lære hvordan du bruker Avr Studio 5, se dette. Hvis du vil vite hvordan denne koden er strukturert, kan du se forrige timer0-innlegg.
#include <avr/io.h>#include <util/delay.h>void pwm_init(){ // initialize TCCR0 as per requirement, say as follows TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00); // make sure to make OC0 pin (pin PB3 for atmega32) as output pin DDRB |= (1<<PB3);} void main(){ uint8_t duty; duty = 115; // duty cycle = 45% of 255 = 114.75 = 115 // initialize timer in PWM mode pwm_init(); // run forever while(1) { OCR0 = duty; }}
Problemstilling
så nå, la oss ta en annen problemstilling. Dette kommer til å være en mer av en praktisk ting i motsetning til den forrige!
La oss ta den tradisjonelle LED flasher der vi må blinke EN LED på en bestemt frekvens. Men hei, vent, diskuterte vi ikke det lenge tilbake i dette innlegget (bla ned mot slutten)? Hmm, så la oss endre det slik som å innlemme PWM. I motsetning til den tradisjonelle LED-flasheren (Hvor Lysdiodene ER ENTEN PÅ ELLER AV), kan vi få det til å lyse ved maksimal lysstyrke, og deretter sakte redusere lysstyrken til den når null, og deretter øke lysstyrken sakte til den blir maksimal.
Analyse Og Kode
Så Hvordan gjør vi det? Ja, du gjettet det riktig! Reduser driftssyklusen sakte fra 255 til null, og øk den deretter fra null til 255. Avhengig av driftssyklusen varierer spenningen på LYSDIODEN, og dermed lysstyrken. Følgende formel gir forholdet mellom spenning og driftssyklus.
så her går koden. Jeg vil ikke forklare det, du kan dekode det selv. For å lære om i/o-portoperasjoner i AVR, se dette. For å vite om bit manipulasjoner, se dette. For å lære hvordan du bruker Avr Studio 5, se dette. Hvis du vil vite hvordan denne koden er strukturert, kan du se forrige timer0-innlegg.
// program to change brightness of an LED// demonstration of PWM #include <avr/io.h>#include <util/delay.h> // initialize PWMvoid pwm_init(){ // initialize timer0 in PWM mode TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00); // make sure to make OC0 pin (pin PB3 for atmega32) as output pin DDRB |= (1<<PB3);} void main(){ uint8_t brightness; // initialize timer0 in PWM mode pwm_init(); // run forever while(1) { // increasing brightness for (brightness = 0; brightness < 255; ++brightness) { // set the brightness as duty cycle OCR0 = brightness; // delay so as to make the user "see" the change in brightness _delay_ms(10); } // decreasing brightness for (brightness = 255; brightness > 0; --brightness) { // set the brightness as duty cycle OCR0 = brightness; // delay so as to make the user "see" the change in brightness _delay_ms(10); } // repeat this forever }}
så her slutter min en annen mye ventet og lang tutorial! Neste opp.. Seriell Kommunikasjon! Vi ses!! 🙂
og ja, hvis du har noen forslag, tvil, konstruktiv kritikk, etc, er du hjertelig velkommen til å slippe et notat nedenfor! Abonner på bloggen min eller ta TAK I RSS-Feeder for å holde deg oppdatert!