In questo articolo tratteremo il modulo Timer0 dell’ Atmega328p e tutte le modalità di funzionamento del generatore di forme d’onda. Timer0 è un modulo composto da un contatore e da due comparatori ad 8 bit. Il segnale di ingresso per il conteggio può essere selezionato tra diverse sorgenti che sono il clock della mcu ed un segnale applicato al pin T0. Dispone di due uscite OC0A ed OC0B (Output Compare A e B) dipendenti dal relativo comparatore. Timer0 genera interrupt su rollover del contatore e su match con ciascuno dei due comparatori
Abilitazione del modulo
Il modulo è normalmente attivo, ma può essere disattivato impostando ad 1 il bit PRTIM0 del registro PRR ( Power Reduction Register )
Descrizione
Sorgente di clock
La sorgente di clock è selezionata tramite i valori dei bit CS[2:0] (Clock Source) del registro TCCR0B. Gli 8 possibili valori permettono scollegare la sorgente di clock arrestando il contatore, collegare il clock della mcu programmando la divisione del prescaler ( 1, 8, 64, 256 e 1024 ), oppure collegare la sorgente di clock esterna presente sul pin T0 che deve comunque avere una frequenza inferiore a quella di clock della mcu
Counter Unit
Il cuore del modulo è il registro TCNT0 (Timer Counter 0) che viene azzerato, incrementato o decrementato in base alla modalità di funzionamento selezionata tramite i bit WGM0[2:0] (Waveform Generation Mode) dei registri TCCR0A e TCCR0B. C’è una connessione diretta tra la modalità di conteggio e la forma d’onda in uscita sui pin OC0A ed OC0B. L’overflow del contatore viene segnalato tramite il bit TOV0 che può essere utilizzata per generare l’ interrupt TIMER0_OVF_vect
Output Compare Unit
Il valore presente in TCNT0 viene confrontato ad ogni ciclo di clock con quello dei registri OCR0A e OCR0B (Output Compare 0 A e B). Quando i valori corrispondono viene segnalato tramite i flag OCF0A ed OCF0B (Output Compare Flag 0 A e B) che possono essere utilizzati per generare interrupt TIMER0_COMPA_vect e TIMER0_COMPB_vect
Compare Match Output Unit
Controlla come vengono impostate le uscite OC0A e OC0B tramite il generatore di forme d’onda quando si verifica la corrispondenza dei valori tra TCNT0 ed uno dei due registri OCR0A ed OCR0B. I bit di controllo sono contenuti nel registro TCCR0A e sono COM0A[1:0], COM0B[1:0]
Uscite
Il modulo Timer0 permette do generare dei segnali sui pin OC0A ed OC0B che devono essere impostati come uscite tramite i bit DDD6 e DDD5 del registro DDRD per poter leggere i segnali generati
Interrupt
Quando il contatore TCNT0 viene resettato, viene impostato il flag TOV0 e viene generato il segnale di interrupt TIMER0_OVF_vect
Quando si verifica il match tra TCNT0 e d il registro OCR0x, viene impostato il flag OCF0x e viene generato il segnale di interrupt TIMER0_COMPx_vect
Poichè in alcune modalità il contatore viene resettato sul match, non è possibile utilizzare l’interrupt generata da TOV0
I flag possono essere resettati scrivendoci un 1
Modalità di lavoro
La combinazione di Waveform Generation Mode ( WGM0[2:0] ) e Compare Output Mode ( COM0[A|B][1:0] ) definiscono il comportamento del Timer/counter e delle uscite OC0[A|B]
WGM02 | WGM01 | WGM00 | Modalità |
---|---|---|---|
0 | 0 | 0 | Normal Mode |
0 | 0 | 1 | PWM, Phase Correct |
0 | 1 | 0 | Clear Timer on Compare Match ( CTC ) |
0 | 1 | 1 | Fast PWM |
1 | 0 | 0 | – |
1 | 0 | 1 | PWM, Phase Correct |
1 | 1 | 0 | – |
1 | 1 | 1 | Fast PWM |
La frequenza dei segnali generati è funzione della sorgente di clock selezionata tramite i bit CS[2:0] ed ipotizzando che si tratti di quella relativa al clock interno, la identificheremo con dove rappresenta la frequenza di clock della mcu ( 16 MHz ) ed N la divisione impostata sul prescaler. Utilizzeremo successivamente per effettuare dei calcoli
Normal mode
Questa è la modalità non PWM più semplice che viene selezionata impostando i bit WGM0[2:0] = 000. TCNT0 conta in avanti fino al valore 0xFF dopo di che viene resettato quindi la frequenza di conteggio è determinata solo dalla sorgente di clock selezionata. Quando il contatore viene resettato viene impostato il flag TOV0 (Timer Overflow 0 ) generando l’interrupt. Vengono generate anche le interrupt sul match tra il TCNT0 e OCR0A e OCR0B
E’ possibile impostare i bit COM0A[1:0] con il valore 01 per far commutare l’uscita OC0A in corrispondenza del match con il valore contenuto in OCR0A, in modo da avere un’onda quadra in uscita alla frequenza di
Facendo altrettanto con i bit COM0B[1:0] otteniamo un’onda quadra sull’uscita OC0B della stessa frequenza ma traslata rispetto a quella su OC0A di secondi
Combinando i due segnali con una porta XOR esterna è possibile ottenere un segnale PWM il cui duty cycle dipende dalla differenza tra i valori di OCR0B ed OCR0A
I due segnali possono essere combinati per ottenere altre forme d’onda
Clear Timer on Compare Match ( CTC )
Questa è la seconda modalità non PWM e viene selezionata da WGM0[2:0] = 010. A differenza della modalità normal mode, TCNT0 viene azzerato ogni volta che si verifica il match con il registro OCR0A che quindi determina la risoluzione del contatore e la frequenza con cui viene resettato
Per generare un segnale su OC0A occorre impostare COM0A[1:0] = 01 per alternare lo stato logico dell’ uscita OC0A ogni volta che si verifica il match. Come nella modalità normal mode i tempi Ton e Toff del segnale sono uguali e dipendono dalla sorgente di clock selezionata ma in questo caso dipendono anche dal valore di OCR0A. La frequenza del segnale generato in questa modalità vale
E’ possibile utilizzare una ISR per modificare il valore di OCR0A in modo da modificare i valori Ton e Toff del segnale, che al netto dei tempi necessari ad eseguire il codice nelle ISR sono così calcolati:
Se nella ISR vengono scritti valori troppo bassi in OCR0A, durante l’esecuzione del codice il contatore può superare il valore da confrontare con il risultato di saltare il match. Questo rischio viene ridotto utilizzando il prescaler per abbassare la frequenza con cui viene incrementato TCNT0
Solo il match con OCR0A resetta il contatore, ma come in Normal Mode si può utilizzare il match con il registro OCR0B per farcommutare OC0B tramite la combinazione dei flag COM0B[1:0]=01. In questo caso il match con OCR0B avviene solo se il valore è minore o uguale a OCR0A perchè in caso contrario il contatore verrebbe resettato sempre prima di raggiungere OCR0B. In questo modo si ottengono due segnali ad onda quadra su OC0A ed OC0B con duty cycle pari al 50%, della stessa frequenza determinata da OCR0A e traslati nel tempo di che possono essere utilizzati in combinazione con componenti esterni per generare i segnali desiderati. Nel caso di un segnale PWM ottenuto con una XOR tra OC0A ed OC0B, il duty cycle vale ed è evidente l’influenza di OCR0A sulla risoluzione del segnale
In quersta modalità non viene utilizzato il flag TOV0 e non viene generata l’interrupt TIMER0_OVF_vect
Fast Pulse Width Modulation
Questa è la prima modalità PWM, il contatore viene incrementato da 0 al valore massimo e poi riportato a 0. Il valore massimo è definito dai bit WGM0[2:0] e vale 0xFF quando bit WGM0[2:0] = 011 mentre vale OCR0A quando bit WGM0[2:0] = 111
Quando il valore del contatore corrisponde a quello di OCR0A l’uscita OC0A viene impostata in accordo con i valori dei bit COM0A[1:0] quindi tralasciando la combinazione 00 che disabilita l’uscita ci sono 3 diverse combinazioni che generano un segnale
WGM0[2:0] | COM0A[1:0] | OC0A Match contatore |
OC0A Clear Contatore |
Descrizione |
---|---|---|---|---|
011 | 10 | 0 | 1 | PWM normale |
011 | 11 | 1 | 0 | PWM Invertita |
111 | 01 | commuta | – | Onda quadra |
Solo con WGM0[2:0]=011 otteniamo dei segnali PWM, la cui frequenza vale
Con WGM0[2:0]=111 ed COM0A[1:0]=01 otteniamo il segnale ad onda quadra su OC0A
In questa modalità non è possibile utilizzare COM0B[1:0]=01 e l’uscita OC0B
Ogni volta che che il contatore raggiunge il valore massimo viene impostato il flag TOV0 che può essere utilizzato per generare una interrupt
Phase Correct Pulse Width Modulation
Questa è la seconda modalità PWM e differisce dalla precedente per il fatto che quando il contatore raggiunge il valore massimo viene decrementato fino al valore minimo invece che essere resettato, questo causa il dimezzamento della frequenza del segnale generato. Come nella Fast PWM, il valore massimo del contatore viene stabilito dalla combinazione dei bit WGM0[2:0] e vale 0xFF quando bit WGM0[2:0] = 001 mentre vale OCR0A quando bit WGM0[2:0] = 101. Il comportamento dell’uscita OC0A è analogo alla modalità Fast PWM ma la commutazione avviene sul match sia quando il contatore viene incrementato che quando viene decrementato. Anche qui ci sono 3 combinazioni utili:
WGM0[2:0] | COM0A[1:0] | OC0A Match contatore in salita |
OC0A Match Contatore in discesa |
Descrizione |
---|---|---|---|---|
001 | 10 | 0 | 1 | PWM normale |
001 | 11 | 1 | 0 | PWM Invertita |
101 | 01 | commuta | – | Onda quadra |
Solo con WGM0[2:0]=001 otteniamo dei segnali PWM, la cui frequenza vale
Con WGM0[2:0]=101 ed COM0A[1:0]=01 otteniamo il segnale ad onda quadra su OC0A e vale tutto quanto detto per la modalità Fast PWM con WGM0[2:0]=111
In questa modalità non è possibile utilizzare COM0B[1:0]=01 e l’uscita OC0B
Ogni volta che che il contatore raggiunge il valore minimo viene impostato il flag TOV0 che può essere utilizzato per generare una interrupt
Registri
TCCR0A: Timer/Counter Control Register A
TCCR0A | |||||||
---|---|---|---|---|---|---|---|
COM0A1 | COM0A0 | COM0B1 | COM0B0 | – | – | WGM01 | WGM00 |
I bit COM0A[1:0] e COM0B[1:0] (Compare Match Output Mode) selezionano il modo in cui le uscite OC0A e OC0B si comportano, secondo le modalità di funzionamento, quando il contatore raggiunge il valore massimo, minimo e viene azzerato.
Non PWM Mode – WGM0[2:0] = 000, 010 | |||||
---|---|---|---|---|---|
COM0A1 | COM0A0 | OC0A | COM0B1 | COM0A0 | OC0B |
0 | 0 | Disconnesso | 0 | 0 | Disconnesso |
0 | 1 | Commuta su Match | 0 | 1 | Commuta su Match |
1 | 0 | 0 su Match | 1 | 0 | 0 su Match |
1 | 1 | 1 su Match | 1 | 1 | 1 su Match |
Fast PWM Mode – WGM0[2:0] = 011, 111 | |||||
COM0A1 | COM0A0 | OC0A | COM0B1 | COM0A0 | OC0B |
0 | 0 | Disconnesso | 0 | 0 | Disconnesso |
0 | 1 | WGM02 = 0: Disconnesso WGM02 = 1: Commuta su Match |
0 | 1 | Disconnesso |
1 | 0 | 0 su Match 1 su TCNT0=0, (non-inverting mode). |
1 | 0 | 0 su Match 1 su TCNT0=0, (non-inverting mode) |
1 | 1 | 1 su Match 0 su TCNT0=0, (inverting mode) |
1 | 1 | 1 su Match 0 su TCNT0=0, (inverting mode) |
Phase Correct PWM Mode – WGM0[2:0] = 001, 101 | |||||
COM0A1 | COM0A0 | OC0A | COM0B1 | COM0A0 | OC0B |
0 | 0 | Disconnesso | 0 | 0 | Disconnesso |
0 | 1 | WGM02 = 0: Disconnesso WGM02 = 1: Commuta su Match |
0 | 1 | Disconnesso |
1 | 0 | 0 su Match quando TCNT0 conta in avanti 1 su Match quando TCNT0 conta in indietro |
1 | 0 | 0 su Match quando TCNT0 conta in avanti 1 su Match quando TCNT0 conta in indietro |
1 | 1 | 1 su Match quando TCNT0 conta in avanti 0 su Match quando TCNT0 conta in indietro |
1 | 1 | 1 su Match quando TCNT0 conta in avanti 0 su Match quando TCNT0 conta in indietro |
I bit WGM0[1:0] (Waveform Generation Mode), assieme al bit WGM02 del registro TCCR0B, selezionano la modalità di lavoro
TCCR0B – Timer/Counter Control Register B
TCCR0B | |||||||
---|---|---|---|---|---|---|---|
FOC0A | FOC0B | – | – | WGM02 | CS02 | CS01 | CS00 |
I bit FOC0x (Force Output Compare) sono validi solo nelle modalità non PWM ed hanno la funzione di forzare un segnale di match. L’uscita OC0x corrispondente si comporterà secondo la modalità selezionata dai bit COM0x[1:0] come se si fosse trattato di un vero match tra TCNT0 ed OCR0x
Il bit WGM02, insieme a WGM0[1:0] del registro TCCR0A selezionano la modalità di lavoro
I bit CS0[2:0] selezionano la sorgente di clock con cui azionare l’incremento del contatore. La sorgente può essere disabilitata per fermare il contatore, il clock interno attraverso il prescaler oppure un clock esterno presente sul pin T0
CS2 | CS1 | CS0 | Sorgente clock |
---|---|---|---|
0 | 0 | 0 | Clock fermo |
0 | 0 | 1 | Clock interno ( prescaler divide per 1 ) |
0 | 1 | 0 | Clock interno / 8 |
0 | 1 | 1 | Clock interno / 64 |
1 | 0 | 0 | Clock interno / 256 |
1 | 0 | 1 | Clock interno / 1024 |
1 | 1 | 0 | Clock esterno T0 sui fronti di discesa |
1 | 1 | 1 | Clock esterno T0 sui fronti di salita |
TCNT0 – Timer/Counter Register
TCNT0 | |||||||
---|---|---|---|---|---|---|---|
– | – | – | – | – | – | – | – |
Questo registro contiene il valore del contatore che viene continuamente incrementato, decrementato o resettato tramite la commutazione della sorgente di clock selezionata e la modalità di lavoro selezionata
OCR0A – Output Compare Register A
OCR0A | |||||||
---|---|---|---|---|---|---|---|
– | – | – | – | – | – | – | – |
Questo registro contiene il valore ad 8 bit con cui viene confrontato il contatore TCNT0. Un match tra i due registri può essere utilizzato per generare una interrupt oppure come sorgente per generare di funzioni d’onda sull’uscita OC0A
OCR0B – Output Compare Register B
OCR0B | |||||||
---|---|---|---|---|---|---|---|
– | – | – | – | – | – | – | – |
Questo registro contiene il valore ad 8 bit con cui viene confrontato il contatore TCNT0. Un match tra i due registri può essere utilizzato per generare una interrupt oppure come sorgente per generare di funzioni d’onda sull’uscita OC0B
TIMSK0 – Timer/Counter Interrupt Mask Register
TIMSK0 | |||||||
---|---|---|---|---|---|---|---|
– | – | – | – | – | OCIE0B | OCIE0A | TOIE0 |
I bit di questo registro mascherano le interrupt generate dagli eventi di match e di overflow del contatore.
OCIE0B (Output Compare Match B Interrupt Enable) impostato ad 1 abilita l’interrupt TIMER0_COMPB_vect quando avviene un match tra TCNT0 e OCR0B
OCIE0A (Output Compare Match A Interrupt Enable) impostato ad 1 abilita l’interrupt TIMER0_COMPA_vect quando avviene un match tra TCNT0 e OCR0A
TOIE0 (Timer/Counter0 Overflow Interrupt Enable) impostato ad 1 abilita l’interrupt TIMER1_OVF_vect quando avviene l’overflow ti TCNT0
TIFR0 – Timer/Counter 0 Interrupt Flag Register
TIFR0 | |||||||
---|---|---|---|---|---|---|---|
– | – | – | – | – | OCF0B | OCF0A | TOV0 |
Questo registro contiene i flag delle rispettive interrupt. Sono impostati ad 1 per tutta l’esecuzione della relativa ISR e possono essere resettati scrivendoci un 1
PRR: Power Reduction Register
PRR | |||||||
---|---|---|---|---|---|---|---|
PRTWI | PRTIM2 | PRTIM0 | – | PRTIM1 | PRSPI | PRUSART0 | PRADC |
L’unico bit che interessa TIMER0 è PRTIM1 che se viene impostato ad 1 disabilita il modulo
Esempi
Timer
In questo esempio realizziamo un timer da utilizzare in un ciclo di ritardo utilizzando Timer0 in normal mode con l’uscita OC0A disconnessa dal generatore di forme d’onda. Utilizziamo una ISR sul match con OCR0A in cui fermiamo il contatore. Attiviamo il timer facendo partire il contatore prima del loop di ritardo, nel loop testiamo che il contatore sia in funzione. Segnaliamo il tempo totale tra la partenza ed il match, al lordo dei cicli macchina necessari ad eseguire il codice frapposto, con due commutazioni del pin PD6.
Vogliamo impostare un ritardo di , con il clock a 16 MHz il contatore viene incrementato di 1 ogni quindi dovremmo fermare il contatore al valore che è un valore troppo alto per un registro a 8 bit. Possiamo però impostare il prescaler ad esempio su una divisione di 64 volte, in questo caso il contatore viene incrementato ogni pertanto dovremmo fermare il contatore al valore . Poichè il valore 0x00 del contatore vale come un conteggio, inseriremo il valore 24
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#include <avr/io.h> #include <avr/interrupt.h> ISR( TIMER0_COMPA_vect ){ // Fermo il contatore TCCR0B &= ~( _BV( CS02 ) | _BV( CS01 ) | _BV( CS00 ) ); TCNT0 = 0x00; } int main( void ){ // Waveform Generation Mode // WGM0[2:0] = 0b000 // Compare Match Output Mode // OC0A Disconnesso // Timer/Counter Interrupt Mask Register // Attivo interrupt comparatore A TIMSK0 |= _BV( OCIE0A ); // Valore Match comparatore A OCR0A = 0x18; // PD5,6 Output DDRD |= ( _BV( DDD6 ) | _BV( DDD5 ) ); // Attivo Interrupt sei(); // Segnale su PD6 PORTD |= _BV( PORTD6 ); PORTD &= ~(_BV( PORTD6 )); // Faccio partire il contatore // Prescaler 64 divisioni TCCR0B |= ( _BV( CS01 ) | _BV( CS00 ) ); // Loop di ritardo while( TCCR0B & ( _BV( CS02 ) | _BV( CS01 ) | _BV( CS00 ) ) ){} // Segnale su PD6 PORTD |= _BV( PORTD6 ); PORTD &= ~(_BV( PORTD6 )); // Loop while( 1 ){} return 0; } |
Il netto dei tempi di esecuzione del codice otteniamo il ritardo voluto
Normal mode con interrupt
In questo esempio utilizziamo le interrupt di overflow e di match con OCR0A per modificare lo stato del pin PD6 impostato come uscita. I limiti di questo generatore di PWM sono i tempi necessari all’esecuzione delle ISR che alterano il periodo ed il duty cicle del segnale
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
#include <avr/io.h> #include <avr/interrupt.h> ISR( TIMER0_COMPA_vect ){ PORTD &= ~(_BV( PORTD6 )); } ISR( TIMER0_OVF_vect ){ PORTD |= _BV( PORTD6 ); } int main( void ){ // Waveform Generation Mode // WGM0[2:0] = 0b000 // Compare Match Output Mode // COM0A[1:0] = 0b00 // COM0B[1:0] = 0b00 // Timer/Counter Interrupt Mask Register // Attivo interrupt overflow e comparatore A // OCIE0B = 0, OCIE0A = 1, TOIE0 = 1 TIMSK0 |= _BV( TOIE0 ); TIMSK0 |= _BV( OCIE0A ); // Valore Match comparatore A OCR0A = 0x40; // PD6 Output DDRD |= _BV( DDD6 ); // Attivo Interrupt sei(); // Faccio partire il contatore // Clock Select // clk I/O (No prescaling) // CS02 = 0, CS01 = 0, CS00 = 1 TCCR0B |= _BV( CS00 ); // Loop while( 1 ){ ; } return 0; } |
Con la soglia del comparatore impostata a 0x40 otteniamo questo segnale su PD6
Con la soglia del comparatore impostata a 0xA0 otteniamo questo segnale su PD6
Normal mode con OC0A e OC0B
In questo esempio generiamo due segnali ad onda quadra sulle uscite OC0A ed OC0B traslati tra loro dalla differenza dei due valori che fanno commutare le due uscite in tempi differenti. A parte la possibilità di impostare il prescaler non abbiamo alcun controllo sulla frequenza dei segnali che valgono e non vengono alterate dai tempi di esecuzione delle ISR come nell’esempio precedente. La combinazione di questi segnali in XOR può essere utilizzata per ottenere un segnale PWM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <avr/io.h> int main( void ){ // Waveform Generation Mode // WGM0[2:0] = 0b000 // Compare Match Output Mode // COM0A[1:0] = 0b01 // COM0B[1:0] = 0b01 TCCR0A |= _BV( COM0A0); TCCR0A |= _BV( COM0B0); // Valore Match comparatore A OCR0A = 0x60; // Valore Match comparatore B OCR0B = 0xA0; // OC0A Output DDRD |= _BV( DDD6 ); // OC0B Output DDRD |= _BV( DDD5 ); // Faccio partire il contatore TCCR0B |= _BV( CS00 ); // Loop while( 1 ){} return 0; } |
Questi sono i segnali generati
Clear Timer on Compare Match (CTC) Mode
Questo esempio è identico al precedente con l’unica differenza che la frequenza del segnale può essere controllata con il valore di OCR0A e vale . Questo valore però influisce anche sulla risoluzione del segnale PWM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <avr/io.h> int main( void ){ // Waveform Generation Mode // WGM0[2:0] = 0b010 TCCR0A |= _BV( WGM01 ); // Compare Match Output Mode // COM0A[1:0] = 0b01 // COM0B[1:0] = 0b01 TCCR0A |= _BV( COM0A0); TCCR0A |= _BV( COM0B0); // Valore Match comparatore A OCR0A = 0x80; // Valore Match comparatore B // OCR0B <= OCR0A OCR0B = 0x10; // OC0A Output DDRD |= _BV( DDD6 ); // OC0B Output DDRD |= _BV( DDD5 ); // Faccio partire il contatore TCCR0B |= _BV( CS00 ); // Loop while( 1 ){} return 0; } |
Questi sono i segnali generati
Fast Pulse Width Modulation
In questo esempio mostriamo le 2 combinazioni relative alla modalità fast PWM con cui generiamo i segnali sulle uscite PD6 (OC0A) e PD5 (OC0B) impostando i bit WGM0[2:0] a 011. Inizializziamo OCR0A ed OCR0B per ottenere i duty cycle pari a e . La frequenza dei segnali vale
Nel primo caso impostiamo i bit COM0A[1:0] e COM0B[1:0] con il valore 10 per ottenere due segnale PWM non invertiti
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <avr/io.h> int main( void ){ // Waveform Generation Mode // WGM0[2:0] = 0b011 TCCR0A |= _BV( WGM01 ); TCCR0A |= _BV( WGM00 ); // Compare Match Output Mode // COM0A[1:0] = 0b10 // COM0B[1:0] = 0b10 TCCR0A |= _BV( COM0A1 ); TCCR0A |= _BV( COM0B1 ); // Valore Match comparatore A OCR0A = 0xA0; // Valore Match comparatore B OCR0B = 0x20; // OC0A Output DDRD |= _BV( DDD6 ); // OC0B Output DDRD |= _BV( DDD5 ); // Faccio partire il contatore TCCR0B |= _BV( CS00 ); // Loop while( 1 ){} return 0; } |
Nel secondo caso modifichiamo i bit COM0A[1:0] e COM0B[1:0] con il valore 11 per ottenere due segnale PWM invertiti
1 2 3 4 5 6 7 |
// Compare Match Output Mode // COM0A[1:0] = 0b11 // COM0B[1:0] = 0b11 TCCR0A |= _BV( COM0A0 ); TCCR0A |= _BV( COM0A1 ); TCCR0A |= _BV( COM0B0 ); TCCR0A |= _BV( COM0B1 ); |
In entrambi i casi i due segnali risultano in fase
Phase Correct Pulse Width Modulation
In questo esempio mostriamo le 2 combinazioni relative alla modalità phase correct PWM con cui generiamo i segnali sulle uscite PD6 (OC0A) e PD5 (OC0B) impostando i bit WGM0[2:0] a 001. Per confronto utilizziamo gli stessi valori di OCR0A ed OCR0B degli esempi relativi alla modalità Fast PWM. La frequenza dei segnali vale ovvero dimezzata rispetto alla modalità Fast PWM
Nel primo caso impostiamo i bit COM0A[1:0] e COM0B[1:0] con il valore 10 per ottenere due segnale PWM non invertiti
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include <avr/io.h> int main( void ){ // Waveform Generation Mode // WGM0[2:0] = 0b001 TCCR0A |= _BV( WGM00 ); // Compare Match Output Mode // COM0A[1:0] = 0b10 // COM0B[1:0] = 0b10 TCCR0A |= _BV( COM0A1 ); TCCR0A |= _BV( COM0B1 ); // Valore Match comparatore A OCR0A = 0xA0; // Valore Match comparatore A OCR0B = 0x20; // OC0A Output DDRD |= _BV( DDD6 ); // OC0B Output DDRD |= _BV( DDD5 ); // Faccio partire il contatore TCCR0B |= _BV( CS00 ); // Loop while( 1 ){} return 0; } |
Nel secondo caso modifichiamo i bit COM0A[1:0] e COM0B[1:0] con il valore 11 per ottenere due segnale PWM invertiti
1 2 3 4 5 6 7 |
// Compare Match Output Mode // COM0A[1:0] = 0b11 // COM0B[1:0] = 0b11 TCCR0A |= _BV( COM0A0 ); TCCR0A |= _BV( COM0A1 ); TCCR0A |= _BV( COM0B0 ); TCCR0A |= _BV( COM0B1 ); |
La porzione di segnale in cui è allo stato logico 1 è centrata sul valore massimo di TCNT0