Go Down

Topic: PWM 38Khz (Read 2503 times) previous topic - next topic

Etan

Ciao a tutti,
per una barriera IR, sto cercando di ottenere un segnale pwm a 38Khz.
Sto utilizzando un Arduino Mega.
Ho trovato questo codice per ottenere tale segnale sul pin digitale 10, lavorando a livello dei registri.
Code: [Select]

const byte LED = 10;  // Timer 2 "A" output: OC2A

void setup() {
  pinMode (LED, OUTPUT);
 
  // set up Timer 2
  TCCR2A = _BV (COM2A0) | _BV(WGM21);  // CTC, toggle OC2A on Compare Match
  TCCR2B = _BV (CS20);   // No prescaler
  OCR2A =  209;          // compare A register value (210 * clock speed)
                         //  = 13.125 nS , so frequency is 1 / (2 * 13.125) = 38095

}  // end of setup

void loop() { }


Non ho dimestichezza con la gestione dei registri, così al fine di ottenere il segnale sul pin 6 ho visto che bisogna agire sul timer4.
Ho quindi modificato il codice banalmente come segue, ma non funziona.
Potete aiutarmi?

Code: [Select]
const byte LED = 6; 

void setup() {
  pinMode (LED, OUTPUT);
 
  // set up Timer 4
  TCCR4A = _BV (COM4A0) | _BV(WGM41); 
  TCCR4B = _BV (CS40);   // No prescaler
  OCR24 =  209;          // compare A register value (210 * clock speed)
                         //  = 13.125 nS , so frequency is 1 / (2 * 13.125) = 38095
}  // end of setup

Michele Menniti

Ma che frequenza ottieni?
Se cerchi "barriera ad infrarossi" trovi un mio Topic con il suggerimento di Astro che con tre righe mi ha fatto ottenere i 38KHz (circa... precisi non li avrai mai), però mi pare si trattasse del timer 2.
Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

qsecofr

#2
Jan 07, 2013, 09:11 pm Last Edit: Jan 07, 2013, 09:13 pm by qsecofr Reason: 1

Ciao a tutti,
per una barriera IR, sto cercando di ottenere un segnale pwm a 38Khz.
Sto utilizzando un Arduino Mega.
Ho trovato questo codice per ottenere tale segnale sul pin digitale 10, lavorando a livello dei registri.
Code: [Select]

const byte LED = 10;  // Timer 2 "A" output: OC2A

void setup() {
 pinMode (LED, OUTPUT);
 
 // set up Timer 2
 TCCR2A = _BV (COM2A0) | _BV(WGM21);  // CTC, toggle OC2A on Compare Match
 TCCR2B = _BV (CS20);   // No prescaler
 OCR2A =  209;          // compare A register value (210 * clock speed)
                        //  = 13.125 nS , so frequency is 1 / (2 * 13.125) = 38095

}  // end of setup

void loop() { }


Non ho dimestichezza con la gestione dei registri, così al fine di ottenere il segnale sul pin 6 ho visto che bisogna agire sul timer4.
Ho quindi modificato il codice banalmente come segue, ma non funziona.
Potete aiutarmi?

Code: [Select]
const byte LED = 6;  

void setup() {
 pinMode (LED, OUTPUT);
 
 // set up Timer 4
 TCCR4A = _BV (COM4A0) | _BV(WGM41);  
 TCCR4B = _BV (CS40);   // No prescaler
 OCR24 =  209;          // compare A register value (210 * clock speed)
                        //  = 13.125 nS , so frequency is 1 / (2 * 13.125) = 38095
}  // end of setup



non funziona ma cosa fa?
la cosa che mi viene in mente è che il timer 2 è a 8 bit mentre il 4 è a 16...

poi l'ocr24... forse intendevi ocr4a?

leo72

Probabile che intendesse OCR4A.



leo72

Cmq prova queste righe di codice messe nel setup.
Dovrebbero impostare il timer 4 dell'Atmega2560 in modalità Phase Correct PWM ad 8 bit con top fissato da OCR4A. se non ho fatto male i conti, hai i tuoi 38095 Hz sul pin D6.

TCCR4A = ((1<<COM4A0) | (1<<WGM40));
TCCR4B = (1<<CS40);
OCR4A = 105;


Etan

Code: [Select]

TCCR4A = ((1<<COM4A0) | (1<<WGM40));
TCCR4B = (1<<CS40);
OCR4A = 105;


Grazie mille!
Li proverò domattina appena rimetto le mani sul sistema.

Ti andrebbe di dettagliare meglio il codice in modo da capire i valori che metti nei registri e come hai fatto i conti?

Grazie ancora

Etan


Ma che frequenza ottieni?
Se cerchi "barriera ad infrarossi" trovi un mio Topic con il suggerimento di Astro che con tre righe mi ha fatto ottenere i 38KHz (circa... precisi non li avrai mai), però mi pare si trattasse del timer 2.


Grazie Michele per il suggerimento.
Sono a corto di pin ed il 6 era perfetto.
In ogni caso mi metto a studiarmi anche il tuo post.


Michele Menniti



Ma che frequenza ottieni?
Se cerchi "barriera ad infrarossi" trovi un mio Topic con il suggerimento di Astro che con tre righe mi ha fatto ottenere i 38KHz (circa... precisi non li avrai mai), però mi pare si trattasse del timer 2.


Grazie Michele per il suggerimento.
Sono a corto di pin ed il 6 era perfetto.
In ogni caso mi metto a studiarmi anche il tuo post.

ho trovato il mio sketch di prova: (c'è anche il metodo per il calcolo, il suggerimento è di Astrobeed, non mio :))
Quote
Quote

#define TX 11
void setup()
{                
  pinMode(TX, OUTPUT);     
    
  OCR2A = 209;
  TCCR2A = 0b01000011; 
  TCCR2B = 0b00001001;
  /*
  Ad OCR2A si deve associare il risultato di
  (clock/frequenza_da_ottenere/2)-1
  Esempio (Arduino a 16MHz)
  per 38000Hz: 16000000/38000/2=210-1=209
  per 40000Hz: 199
  */
}

void loop()
{
 } 

Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

leo72


Code: [Select]

TCCR4A = ((1<<COM4A0) | (1<<WGM40));
TCCR4B = (1<<CS40);
OCR4A = 105;


Grazie mille!
Li proverò domattina appena rimetto le mani sul sistema.

Ti andrebbe di dettagliare meglio il codice in modo da capire i valori che metti nei registri e come hai fatto i conti?

Grazie ancora


La prima cosa da fare è scegliere la modalità di generazione dell'onda.
In questo caso ho scelto la Phase Correct PWM ad 8 bit del timer 4, che, ricordo, è a 16 bit ma può essere configurato appunto per lavorare anche ad 8/9/10 bit in alcune modalità. La Phase Correct PWM, rispetto alla Fast PWM che viene spesso scelta, permette di avere un segnale perfettamente quadro, con le fasi High e Low perfettamente simmetriche.
Per far ciò ho settato ad 1 il bit WGM40 nel registro TCCR4A.
Scelta la modalità, ho scelto il canale ed il comportamento. Volevi agire sul pin D6, che è il pin OC4A, per cui ho scelto di cambiare lo stato del pin (da alto a basso e viceversa) ogni volta che il valore del contatore del timer raggiungesse il valore del registro OCR4A. Per fare ciò ho settato ad 1 il bit COM4A0 sempre nel registro TCCR4A.
Adesso arriviamo al valore di OCR4A.

Per la modalità Phase Correct PWM, la formula da usare per calcolare la frequenza è
Fpwm = Fsys/(2*PRESCALER*VALORE_MAX*2)

Il PRESCALER è il fattore di divisione del clock di sistema. Ho usato un fattore /1, quindi nessuna divisione del clock. Per selezionare questa voce ho settato ad 1 il bit CS40 nel registro TCCR4B.
VALORE_MAX è il valore massimo del registro o, in alternativa, il valore di OCR4A.
Avendo messo PRESCALER ad 1, con Fsys pari a 16 MHz, la formula è
Fpwm = 16.000.000/(2*OCR4A*2)
Da cui
38000 = 16.000.000/(2*OCR4*2)
Da cui
OCR4A = 16.000.000/(38000*4)

Ed ecco OCR4A a 105.

Etan

Seguendo il tuo ragionamento con il datasheet dell'ATmega2560 sono riuscito a capire un pò meglio la sequenza di istruzioni.

Domani potrò caricare il nuovo firmware e verificare con l'oscilloscopio cosa accade.

grazie ancora.

Michele Menniti

Leo, prova a riguardare le ultime tre formule, a me pare di vedere almeno due errori :smiley-roll-sweat:
Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

leo72


Leo, prova a riguardare le ultime tre formule, a me pare di vedere almeno due errori :smiley-roll-sweat:

A parte l'aver tralasciato una "A (OCR4 al posto di OCR4A) e l'aver approssimato 38095 a 38000?  :smiley-sweat:

Michele Menniti

sì, un ulteriore inghippo è strano per me ma non per lui,  evidentemente, inutile parlarne :D
Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

Etan


sì, un ulteriore inghippo è strano per me ma non per lui,  evidentemente, inutile parlarne :D


Michele non ho risposto per mancanza di interesse ma per assenza di connessione.
E' ovvio che ho posto il quesito e che mi interessano molto i vostri commenti e aiuti.
Purtroppo non sono riuscito a rilevare gli inghippi di cui parlavi, ti sarei grato se me li facessi rilevare.
Anche perchè il codice di Leo non mi funziona.
Code: [Select]
TCCR4A = ((1<<COM4A0) | (1<<WGM40));
TCCR4B = (1<<CS40);
OCR4A = 105;


Sul pin 6, dichiarato come output non accade nulla e non riesco a spiegarmi il perchè.

Spero ancora nel vostro aiuto.
Grazie

Michele Menniti

XD XD :smiley-sweat: ma no Etan, mica mi riferivo a te! il "lui" è il programma che si comporta a prescindere dal mio ragionamento. Spiego l'errore che ho fatto: dalle mie reminiscenze elementari ricordavo che una serie di * e / portevano essere invertire tra loro senza che cambiasse il risultato, invece era una mia confusione; allora facevo 16.000.000/38000*4 ignorando la parentesi e non mi usciva (OVVIAMENTE) 105, poi ci sono arrivato, volevo evitare di parlarne ma ora mi hai costretto ad uscire allo scoperto :D
Sul resto devi aspettare Leo, il mago è lui in queste cose....
Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

Go Up