Questo articolo è in continuazione con il precedente post PWM. Imparare a programmare i timer per operare in modalità PWM! Quindi cominciamo!
Ciao gente! E ‘ da tanto che non ci vediamo! 🙂
Nel mio post precedente, abbiamo discusso i concetti di base di PWM. Riassumiamo prima:
- PWM sta per Pulse Width Modulation.
- Può essere generato confrontando forma d’onda predeterminata con un livello di tensione di riferimento o facendo semplici circuiti analogici.
- Il ciclo di lavoro di una forma d’onda PWM è dato dalla seguente relazione.
- Ci sono tre modalità di funzionamento PWM-Veloce PWM, fase corretta PWM e frequenza e fase corretta PWM
- Come scegliere timer, modalità di funzionamento e confrontare modalità di uscita per generare il PWM desiderato.
Prendiamo una dichiarazione problema. Dobbiamo generare un segnale PWM a 50 Hz con un ciclo di lavoro del 45%.
Analisi
Dato che
Frequency = 50 Hz
In altre parole, il periodo di tempo, T
T = T(on) + T(off) = 1/50 = 0.02 s = 20 ms
Inoltre, dato che
Duty Cycle = 45%
Quindi, risolvere, secondo l’equazione di cui sopra, otteniamo
T(on) = 9 msT(off) = 11 ms
Ora, questo può essere realizzato in due modi:
- Usare il Timer in CTC Modalità
- Usare il Timer in Modalità PWM
Metodologia – CTC Modalità
va Bene, quindi non posso scrivere qui il codice (solo la pseudo codice). Presumo che dopo aver letto i miei post precedenti, sei abbastanza intelligente da scriverne uno tu stesso! Discuteremo solo i concetti.
In primo luogo, scegliere un timer adatto. Per questa applicazione, possiamo scegliere uno qualsiasi dei tre timer disponibili in ATMEGA32. Scegliere un prescaler adatto. Quindi impostare il timer e procedere come al solito. Il problema è che è necessario aggiornare il valore di confronto del registro OCx ogni volta. Uno di questi modi è discusso nello pseudo codice riportato di seguito.
Questo è analogo al tradizionale lampeggiatore a LED, tranne il fatto che i tempi di accensione e spegnimento sono diversi.
Pseudo Codice
#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 }}
Ora questo è un metodo. Ed è molto inefficiente. È possibile aumentare la sua efficienza scrivendo un codice C migliore (in termini di sintassi), tuttavia il concetto rimane lo stesso. Se avete qualsiasi altro metodo / concetto, siete i benvenuti a condividere qui! 🙂
AGGIORNAMENTO: Uno dei lettori di maxEmbedded, “coolpales” ha scritto questo codice, e ha funzionato per lui.
Si prega di notare che questo codice non ancora testato! Quindi, se qualcuno di voi lo sta provando, pubblica i tuoi risultati qui, sarei felice di vederli! 🙂
Metodologia-Modalità PWM
Va bene, così ora consente di conoscere la modalità PWM. La modalità PWM in AVR è controllata dall’hardware. Ciò significa che tutto, con tutto ciò che intendo “tutto”, è fatto dalla CPU AVR. Tutto quello che devi fare è inizializzare e avviare il timer e impostare il ciclo di lavoro! Figo, eh?! Impariamo come!
Qui, ho usato Timer0 di ATMEGA32 per la dimostrazione. È possibile scegliere qualsiasi altro altro timer o AVR microcontrollore pure. Ora diamo un’occhiata ai registri.
TCCR0 – Timer/Counter0 Control Register
Ci siamo imbattuti in questo registro nel mio tutorial Timer0. Qui, impareremo come impostare bit appropriati per eseguire il timer in modalità PWM.
TCCR0 Register
Discuteremo solo i bit che ci interessano ora.
- Bit 6,3 – WGM01:0 – Modalità di generazione della forma d’onda – Questi bit possono essere impostati su “00” o “01” a seconda del tipo di PWM che si desidera generare. Ecco la tabella di ricerca.
Modalità di generazione della forma d’onda Bit Descrizione
- Bit 5,4-COM01: 0-Confronta Partita Modalità di uscita-Questi bit sono impostati al fine di controllare il comportamento di uscita Confrontare pin (OC0, pin 4 in ATMEGA32) in conformità con il WGM01:0 bit. La seguente tabella di ricerca determina le operazioni del pin OC0 per la modalità PWM veloce.
Confrontare modalità di uscita, veloce PWM Modalità
Ora consente di avere uno sguardo al veloce PWM forme d’onda. Una spiegazione dettagliata può essere trovata nel mio precedente tutorial.
Veloce PWM
Ora lasciate che vi ricordi che il AVR PWM è completamente hardware controllato, il che significa che anche il timer confrontare il funzionamento è fatto dal AVR CPU. Tutto quello che dobbiamo fare è dire alla CPU cosa fare una volta che si verifica una corrispondenza. I pin COM01:0 entrano in gioco qui. Vediamo che impostandolo su “10” o “11”, il pin di uscita OC0 viene impostato o cancellato (in altre parole, determina se il PWM è in modalità invertita o in modalità non invertita).
Allo stesso modo per la fase PWM corretta, la tabella di ricerca e le forme d’onda vanno in questo modo.
Confrontare modalità di uscita, fase corretta modalità PWM
Fase corretta PWM
Anche qui, impostazione COM01:0 a “10” o “11” determina il comportamento di OC0 pin. Come mostrato nelle forme d’onda, ci sono due istanze: una durante l’up – counting e l’altra durante il down-counting. Il comportamento è chiaramente descritto nella tabella di ricerca.
Si prega di notare che OC0 è un pin di uscita. Pertanto, gli effetti di WGM e COM non entreranno in gioco a meno che il registro DDRx non sia impostato correttamente. Fare riferimento a questo tutorial per maggiori informazioni.
- Bit 2:0 – CS02:0 – Bit di selezione dell’orologio-Questi bit sono già discussi nel tutorial Timer0.
Compare0 – Output Confronta Registro
Abbiamo incontrato anche questo registro nel mio tutorial Timer0. Usiamo questo registro per memorizzare il valore di confronto. Ma quando usiamo Timer0 in modalità PWM, il valore memorizzato in esso agisce come il duty cycle (ovviamente!). Nella dichiarazione del problema, è dato che il ciclo di lavoro è del 45%, il che significa
OCR0 = 45% of 255 = 114.75 = 115
E il gioco è fatto! Ora siamo pronti a scrivere un codice per questo! 🙂
Modifica: Nota
Il seguente codice illustra come creare un segnale PWM di un ciclo di lavoro desiderato. Se si desidera modificare la sua frequenza, è necessario modificare il valore SUPERIORE, che può essere fatto utilizzando il registro ICRx (che non è supportato da timer a 8 bit). Per Timer1 a 16 bit, può essere variato utilizzando ICR1A. Ne parlerò presto quando discuteremo del servocomando.
Codice
Quindi ecco il codice. Per informazioni sulle operazioni di porta I/O in AVR, visualizzare questo. Per conoscere le manipolazioni dei bit, visualizza questo. Per informazioni su come utilizzare AVR Studio 5, visualizza questo. Per sapere come è strutturato questo codice, visualizza il precedente post TIMER0.
#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; }}
Dichiarazione problema
Quindi ora, prendiamo un’altra dichiarazione problema. Questo sta per essere un più di una roba pratica a differenza di quella precedente!
Prendiamo il tradizionale lampeggiatore a LED dove abbiamo bisogno di lampeggiare un LED ad una particolare frequenza. Ma hey, aspetta, non ne abbiamo discusso molto tempo fa in questo post (scorrere verso il basso verso la fine)? Hmm, quindi cerchiamo di modificarlo in modo da incorporare PWM. A differenza del tradizionale lampeggiatore a LED (dove i LED sono accesi o spenti), consente di farlo brillare alla massima luminosità, quindi diminuire lentamente la sua luminosità fino a raggiungere lo zero, quindi aumentare di nuovo la sua luminosità lentamente fino a diventare massima.
Analisi e codice
Quindi come lo facciamo? Sì, hai indovinato! Diminuire lentamente il ciclo di lavoro da 255 a zero, quindi aumentarlo da zero a 255. A seconda del ciclo di lavoro, la tensione applicata al LED varia e quindi la luminosità. La seguente formula fornisce la relazione tra tensione e duty cycle.
Quindi ecco il codice. Non te lo spiego, puoi decodificarlo tu stesso. Per informazioni sulle operazioni di porta I/O in AVR, visualizzare questo. Per conoscere le manipolazioni dei bit, visualizza questo. Per informazioni su come utilizzare AVR Studio 5, visualizza questo. Per sapere come è strutturato questo codice, visualizza il precedente post TIMER0.
// 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 }}
Così qui finisce il mio altro tanto atteso e lungo tutorial! Il prossimo.. Comunicazione seriale! Ci vediamo in giro!! 🙂
E sì, se avete suggerimenti, dubbi, critiche costruttive, ecc, siete i benvenuti a cadere una nota qui sotto! Iscriviti al mio blog o prendi i feed RSS per rimanere aggiornato!