AVR Timers-PWM Mode-Part II

AVR Series 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.
Ciclo di lavoro
  • 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.
Così ora, senza troppi problemi, vediamo come implementarlo utilizzando i microcontrollori AVR. Prima di procedere, ti suggerisco di passare attraverso i miei post precedenti su Timer e PWM.

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:

  1. Usare il Timer in CTC Modalità
  2. 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

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

    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à

    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

    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

    Confrontare modalità di uscita, fase corretta modalità PWM

    Fase corretta 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.

Equazione V_out

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!

Write a Comment

Il tuo indirizzo email non sarà pubblicato.