Pagina 1 di 2

Utilizzo Timer0.

MessaggioInviato: 13 giu 2019, 16:35
da lucaking
Ciao a tutti, cercando di fare un poco di pratica con l' utilizzo dei microcontrollori, mi sono dedicato all' uso dei timer e degli interrupt.
L' idea iniziale era: vediamo di capire come far lampeggiare due led a diversa velocità, anzi, vediamo se riesco a generare due onde quadre con frequenze diverse (e prestabilite :D ).
Ho cominciato usando un solo timer e tutto sembrava funzionare, alchè ho scritto il codice pari pari cambiando sol il numero del timer da 0 a 2, e qui mi sono accorto che qualcosa non quadra.
Il codice che ho scritto è il seguente:
Codice: Seleziona tutto
const int led1 = 3;
const int led2 = 5;

void setup() {
        DDRD = B11111111;
        noInterrupts();           // disable all interrupts
        TCCR0A = 0;
        TCCR0B = 0;
        TCNT0  = 0;
        TIMSK0 = 0;
        TIFR0 = 0;
        OCR0A = 30;                // compare match register
//        TCCR0A |= (1 << WGM01);          // CTC mode
        TCCR0A = B00000010;
//        TCCR0B |= (1 << CS00);    // prescaler
//        TCCR0B |= (1 << CS02);    // prescaler 256
        TCCR0B = B00000100;
//        TIMSK0 |= (1 << OCIE0A);  // enable timer compare interrupt
        TIMSK0 = B00000010;
       
        TCCR2A = 0;
        TCCR2B = 0;
        TCNT2  = 0;
        TIMSK2 = 0;
        TIFR2 = 0;
        OCR2A = 30;
//        TCCR2A |= (1 << WGM21);   // CTC mode
        TCCR2A = B00000010;
//        TCCR2B |= (1 << CS20);   // prescaler
//        TCCR2B |= (1 << CS22);    // prescale 256
        TCCR2B = B00000100;
//        TIMSK2 |= (1 << OCIE2A);  // enable timer compare interrupt
        TIMSK2 = B00000010;
        interrupts();             // enable all interrupts
}

ISR(TIMER0_COMPA_vect){          // timer compare interrupt service routin
        PORTD ^= _BV(led1);        //macro _BV setta il bit relativo al valore (bit to val)
}                                  // al posto di fare (1 << val)

ISR(TIMER2_COMPA_vect){
        PORTD ^= _BV(led2);
}

void loop() {
}


Ho utilizzato i due timer a 8 bit, settando i prescaler a clock/256 ed i registri di comparazione OCRnA allo stesso valore, ma cio che viasualizzo all' oscilloscopio è questo:
SDS00003.jpg
SDS00003.jpg (53.71 KiB) Osservato 9304 volte


Mi aspettavo di avere due forme d' onda identiche, al massimo leggermente sfasate ma con identica frequenza.
Ho fatto un po di prove ma nulla.
Non capisco cosa sbaglio.

Re: Utilizzo Timer0.

MessaggioInviato: 13 giu 2019, 17:31
da xyz
Scusa ma stai mischiando API di Arduino con la programmazione diretta dei registri del microcontrollore, o una o l'altra altrimenti si interferiscono a vicenda.

Se leggi la documentazione ufficiale del API di Arduino scopri che il timer0 è usato per tutte le funzioni sul tempo:

...
Timer0 is a 8bit timer.
In the Arduino world Timer0 is been used for the timer functions, like delay(), millis() and micros(). If you change Timer0 registers, this may influence the Arduino timer function.
...

Se vuoi programmare direttamente il micorocontrollore puoi farlo, non usare nessun include di Arduino, nessuna sua funzione, nessuna sua libreria. Puoi usare il compilatore GCC per AVR e la libreria standard C per gli AVR tutte e due presenti tra i file del IDE di Arduino.

La programmazione diretta del microcontrollore in C la funzione di partenza è la classica "main" nessun "setup" e "loop".

Re: Utilizzo Timer0.

MessaggioInviato: 13 giu 2019, 17:50
da IlGuru
Vedo la programmazione di arduino tramite i registri del micro.
Sono commosso. Davvero.
Non abbandonare questa strada per favore.

Re: Utilizzo Timer0.

MessaggioInviato: 13 giu 2019, 18:18
da speedyant
Ottimo Foto Utentelucaking!

Adesso una pausa, respiro profondo e studio del datasheet del micro e delle api di arduino!

Attenzione che il Timer0, Timer1 e Timer2 hanno delle "specifiche funzioni" all'interno dell'ecosistema arduino...

Re: Utilizzo Timer0.

MessaggioInviato: 13 giu 2019, 19:12
da lucaking
In realtà stavo solo facendo qualche prova, pensavo che "saltare qualche passaggio" non comportasse grossi problemi, invece il gioco si complica....

Sapevo che il timer0 di arduino fosse usato per quelle funzioni, ma credevo che non essendo presenti nel mio codice non dovessero influire, quindi mi confermate che il problema è questo?

xyz ha scritto:Se vuoi programmare direttamente il micorocontrollore puoi farlo.

Eh, lo so, basterebbe essere capaci.... :oops: :D

xyz ha scritto:.... non usare nessun include di Arduino, nessuna sua funzione, nessuna sua libreria. Puoi usare il compilatore GCC per AVR e la libreria standard C per gli AVR tutte e due presenti tra i file del IDE di Arduino.

La programmazione diretta del microcontrollore in C la funzione di partenza è la classica "main" nessun "setup" e "loop".

In realtà essendo abbastanza profano, sono partito proprio da li, in effetti nei file dell' ide di arduino ho trovato il main.cpp, che non fa altro che chiamare una funzione init(), controllare qualcosa sull' USB, chiamare setup() e infine loop() che ad ogni ciclo controlla se c' è qualcosa sulla seriale, il problema è che poi mi perdo e non trovo ad esempio dov'è definito cosa fa init().

Re: Utilizzo Timer0.

MessaggioInviato: 13 giu 2019, 20:43
da xyz
lucaking ha scritto:Sapevo che il timer0 di arduino fosse usato per quelle funzioni, ma credevo che non essendo presenti nel mio codice non dovessero influire..

Anche se non sono presenti nel tuo codice funzioni sul tempo, API di Arduino inizializza hardware prima di chiamare "setup" e "loop" in base alle sue esigenze.

Non devi mischiare codice concepito per mascherare la complessità della programmazione diretta del micro-controllore, come le API di Arduino o la programmazione diretta di un micro-controllore.

il problema è che poi mi perdo e non trovo ad esempio dov'è definito cosa fa init().

Arduino è open source qui trovi i sorgenti ufficiali, poi cercare cosa fanno le varie parti:

https://github.com/arduino/Arduino

Re: Utilizzo Timer0.

MessaggioInviato: 14 giu 2019, 7:47
da lucaking
xyz ha scritto:Non devi mischiare codice concepito per mascherare la complessità della programmazione diretta del micro-controllore, come le API di Arduino o la programmazione diretta di un micro-controllore.


Uffa, però così mi rovini tutto il divertimento.... :D
Comunque non mi sento di promettertelo. :D

Ieri sera ho trovato la definizione della funzione init() nel file wiring.c, della suite di arduino, e non fa altro che settare i registri riguardanti i timer e gli interrupt ad essi collegati.
Quello che non capisco è perché se successivamente, con la funzione setup() io li setto a mio piacere qualcosa fallisce.

Esiste un modo per "debuggare" il codice di arduino?
Forse debug è una parola grossa, intendo eseguirlo riga a riga e se serve richiedere il valore dei vari registri del micro?

Re: Utilizzo Timer0.

MessaggioInviato: 14 giu 2019, 9:02
da IlGuru
Quando compili uno sketch tra i vari file che vengono generati ce n'è uno che contiene l'assembly che viene prodotto dal compilatore. Meglio di quello per debuggare e capire cosa fa non c'è niente

Re: Utilizzo Timer0.

MessaggioInviato: 14 giu 2019, 13:18
da xyz
lucaking ha scritto:Esiste un modo per "debuggare" il codice di arduino?

Non esiste il codice di Arduino, si programma con un subset del C/C++. Arduino è una famiglia di board, un API di programmazione e un IDE programmato in Java, nulla di più.

Se per debug intendi l'esecuzione passo passo del codice sulla board questo è possibile solo sui micro-controllori compatibili col JTAG o DebugWire (non tutti i micro-controllori Atmel hanno questa funzione), con una interfaccia hardware via JTAG o DebugWire e con un software in grado di interfacciarsi. Per un utente normale questa strada non è praticabile.

Di solito chi programma una board Arduino usa come debug la stampa via seriale, con delle "printf" di dati significativi messi nel codice (rimossi nella versione finale).

Se vuoi vedere il codice assembler del tuo codice in C/C++ con il compilatore GCC per AVR con l'opzione "-S" puoi salvare il file assembler, dalla documentazione ufficiale:

https://gcc.gnu.org/onlinedocs/gcc-9.1. ... ml#index-S

Re: Utilizzo Timer0.

MessaggioInviato: 14 giu 2019, 15:07
da lucaking
Intanto grazie a tutti per le risposte e la pazienza.


speedyant ha scritto:Adesso una pausa, respiro profondo e studio del datasheet del micro .....

Avevi ragione Foto Utentespeedyant, la risposta ai miei insuccessi era li, e neanche tanto nascosta.
22. TC2 - 8-bit Timer/Counter2 with PWM and Asynchronous Operation

22.1. Features

• Channel Counter
• Clear Timer on Compare Match (Auto Reload)
• Glitch-free, Phase Correct Pulse Width Modulator (PWM)
• Frequency Generator
• 10-bit Clock Prescaler
• Overflow and Compare Match Interrupt Sources (TOV2, OCF2A, and OCF2B)
• Allows Clocking from External 32kHz Watch Crystal Independent of the I/O Clock

Bastava leggere in maniera un po' meno superficiale per capire che i bit per la configurazione del prescaler nel Timer2 sono diversi da quelli dello 0 e dell' 1. :oops:

Beh, alla fine funziona:
SDS00006-100+100.jpg
SDS00006-100+100.jpg (45.48 KiB) Osservato 9181 volte

Codice: Seleziona tutto
const uint8_t led1 = 3;
const uint8_t led2 = 5;

void setup() {
        DDRD = B00101000;        //set pin 3 and 5 as output
        cli();                // noInterrupts();

        TCCR0A = B00000010;        //set CTC mode (clear timer on compare match)
        TCCR0B = B00000101;        //set prescaler 1024
        OCR0A = 77;                // compare match register (16Mhz/1024)/77 = 200 per-sec
        TIMSK0 = B00000010;
        TCNT0  = 0;
       
        TCCR2A = B00000010;
        TCCR2B = B00000111;        //set prescaler 1024 (different bits from Timer0)
        OCR2A = 77;
        TIMSK2 = B00000010;
        TCNT2  = 0;

        sei();                //interrupts();
}

ISR(TIMER0_COMPA_vect){          // timer compare interrupt service routin
        PORTD ^= _BV(led1);        //macro _BV setta il bit relativo al valore (bit to val)
}                                  // al posto di fare (1 << val)

ISR(TIMER2_COMPA_vect){
        PORTD ^= _BV(led2);
}

void loop() {
}

Ovviamente così facendo, in setup() ho riscritto alcuni dei registri che la funzione init() definita nel file wiring.c dell' API di arduino aveva precedentemente settato mandando a spasso tutte le funzioni che fanno uso di questi timer.

Sono consapevole del fatto che siano esperienze fine se stesse, ma sono comunque soddisfatto perché a mio modo di vedere aprono un minimo gli occhi su cio che spesso usiamo senza capirci un H.
Probabilmente partendo da un approccio piu pragmatico non avrei mai perso alcune serate a spulciare il datasheet del micro ne tantomeno i file dell' API di arduino o i vari file header dell' AVR per provare a capirci qualcosa.