Salve a tutto il forum,
volevo usare in maniera più specifica i pwm di arduino uno sfruttando il compare del pwm per modulare l'uscita e scrivere un regolatore pid.
Per quanto riguarda il regolatore non ho grossi problemi...volevo però capire come fare per usare l'nterrupt del pwm e sfruttare il compare per cambire il valore scritto dal pwm....
Non so se mi sono spiegato....
all'interno del main, che farà cose generali (es. cmunicazione seriale...etc) vorrei poter scatenare l'interrupt del pwm ad ogni ciclo di pwm e scrivere nella routine dell'interrupt il regolatore sopra citato in modo che il regolatore giri ad ogni ciclo di pwm.
Il comando analogwrite() non è adatto per fare tutto ciò e non conosco molto l' Atmega per potermici addentrare.
So, se qualcuno di voi avesse già affrontato e lo volesse condividere con me...
alexsgv:
vorrei poter scatenare l'interrupt del pwm ad ogni ciclo di pwm e scrivere nella routine dell'interrupt il regolatore sopra citato in modo che il regolatore giri ad ogni ciclo di pwm.
Sto andando a memoria, da verificare sul data sheet, non mi pare sia possibile avere l'interrupt sul periodo del pwm, è possibile solo su ogni cambio di stato dell'out il che non va bene per il pid che richiede un ciclo preciso e senza jitter.
Molto meglio se leghi il ciclo pid ad un timer dedicato dove imposti il periodo che ti serve, in questo modo sei certo di eseguire il pid con il giusto intervallo.
Sto andando a memoria, da verificare sul data sheet, non mi pare sia possibile avere l'interrupt sul periodo del pwm, è possibile solo su ogni cambio di stato dell'out il che non va bene per il pid che richiede un ciclo preciso e senza jitter.
Molto meglio se leghi il ciclo pid ad un timer dedicato dove imposti il periodo che ti serve, in questo modo sei certo di eseguire il pid con il giusto intervallo.
[/quote]
Boia, io pensavo si potesse legare l'interrupt al ciclo del pwm...come nei DSP....
Mi stavo documentando sull'uso dell'overflow dei timer per lanciare l'interrupt...e oltre al fato che il timer0 gestisce le varie funzioni di temporizazione tipo mills() e delay().... se si modifica uno qualsiasi dei timer, cambia anche la funzionalità dell' analogwite().
Ho detto una boiata o è vero? in tal caso come impatta il timer con la funzione analogwrite()?
Sto cercando di capire sta cosa...
Ok, ho modificato il prescaler del timer2 e faccio togglare il pin 11...
solo non mi funziona più l'analogWrite() sul pin 3 che è l'altra uscita gestita dal Timer2
La mia idea era modificare il tmr e far scattare l'interrupt sull'azzeramento e poi fare le mie cose e impostare il valore di uscita sul pin 3.
in questo modo ho una regolazione ciclo-ciclio.
Ma ovviamente non va.... =(
Sotto posto il codice di prova!
/*
Codice di prova per PID interno all'interrupt del Timer2
*/
boolean toggle2 = 0;
void setup(){
//set pins as outputs
pinMode(3, OUTPUT);
pinMode(11, OUTPUT);
cli();//stop interrupts
//setto timer2 interrupt a 8kHz
TCCR2A = 0;// set entire TCCR2A register to 0
TCCR2B = 0;// same for TCCR2B
TCNT2 = 0;//initialize counter value to 0
// set compare match register for 8khz increments
OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
// turn on CTC mode
TCCR2A |= (1 << WGM21);
// Set CS21 bit for 8 prescaler
TCCR2B |= (1 << CS21);
// enable timer compare interrupt
TIMSK2 |= (1 << OCIE2A);
sei();//allow interrupts
}
ISR(TIMER2_COMPA_vect){//timer1 interrupt 8kHz toggles pin 9
analogWrite(3, 50);
if (toggle2){
digitalWrite(11,HIGH);
toggle2 = 0;
}
else{
digitalWrite(11,LOW);
toggle2 = 1;
}
}
void loop(){
}
Se cambi un timer, alteri ovviamente la funzione analogWrite.
Sulla questione interrupt, non ho capito bene cosa vuoi fare.
Il timer 2 ha 3 interrupt. 2 sono quelli per il matching fra il valore del contatore interno e OCR2A/B, cioè quello che stai usando tu.
Ce n'è un terzo sull'overflow del contatore, ma non credo ti serva perché usando OCR2A come registro di comparazione, il contatore non andrebbe mai in overflow.
Poi non capisco la cosa di mettere un analogWrite all'interno di una ISR collegata al timer.
L'analogWrite altro non fa che impostare un timer per lavorare in un certo modo e produrre un'onda quadra con un certo duty cycle. Questa onda altro non è che un'alternanza di segnali alti/bassi. Se vuoi un PWM particolare, puoi creartelo tu via software, semplicemente mettendo un pin qualunque alto o basso ogni volta che viene chiamata l'ISR. Se hai bisogno di un duty cycle particolare, puoi esempio mettere High il pin 3 volte su 4 (d.c. 75%) oppure 1 volta su 4 (d.c. 25%) ecc..
leo72:
Se cambi un timer, alteri ovviamente la funzione analogWrite.
Sulla questione interrupt, non ho capito bene cosa vuoi fare.
Il timer 2 ha 3 interrupt. 2 sono quelli per il matching fra il valore del contatore interno e OCR2A/B, cioè quello che stai usando tu.
Ce n'è un terzo sull'overflow del contatore, ma non credo ti serva perché usando OCR2A come registro di comparazione, il contatore non andrebbe mai in overflow.
Poi non capisco la cosa di mettere un analogWrite all'interno di una ISR collegata al timer.
L'analogWrite altro non fa che impostare un timer per lavorare in un certo modo e produrre un'onda quadra con un certo duty cycle. Questa onda altro non è che un'alternanza di segnali alti/bassi. Se vuoi un PWM particolare, puoi creartelo tu via software, semplicemente mettendo un pin qualunque alto o basso ogni volta che viene chiamata l'ISR. Se hai bisogno di un duty cycle particolare, puoi esempio mettere High il pin 3 volte su 4 (d.c. 75%) oppure 1 volta su 4 (d.c. 25%) ecc..
Cerco di spiegarmi ancora meglio...forse non mi era chiaro neanche a me.
vorrei modulare il duty del pwm comparando il comparatore con un valore di riferimento che viene ricalcolato ogni volta all'interno dell'interrupt generato dal pwm (ad ogni ciclo)
non mi è molto chiaro come fare però!
Siccome il PWM è generato dal timer usando proprio l'OCR2A, basta che tu nella ISR assegni al registro un nuovo valore per la successiva comparazione. Oppure usi un altro timer che faccia la modifica all'OCR2A in base ai parametri che monitori.
leo72:
Siccome il PWM è generato dal timer usando proprio l'OCR2A, basta che tu nella ISR assegni al registro un nuovo valore per la successiva comparazione. Oppure usi un altro timer che faccia la modifica all'OCR2A in base ai parametri che monitori.
quindi se ho capito...variando il registro OCR2A cambio il duty e variando il prescaler vario la frequenza del pwm.
Ma per scrivere l'output?!cioè per buttare fuori il duty?!... mi sfugge qualcosa... I'm so sorry...
alexsgv:
quindi se ho capito...variando il registro OCR2A cambio il duty
Sì
e variando il prescaler vario la frequenza del pwm.
Anche, ma non solo (la frequenza la puoi aggiustare variando anche il valore di partenza del contatore).
Ma per scrivere l'output?!cioè per buttare fuori il duty?!... mi sfugge qualcosa... I'm so sorry...
Che vuol dire?
C'è un registro che regola come il timer deve gestire l'inversione di stato del pin. Per "buttare fuori" il duty immagine tu voglia dire far uscire il segnale su un pin. Basta mettere quel pin in output con un pinMode(pin, OUTPUT).
alexsgv:
quindi se ho capito...variando il registro OCR2A cambio il duty
Sì
e variando il prescaler vario la frequenza del pwm.
Anche, ma non solo (la frequenza la puoi aggiustare variando anche il valore di partenza del contatore).
Ma per scrivere l'output?!cioè per buttare fuori il duty?!... mi sfugge qualcosa... I'm so sorry...
Che vuol dire?
C'è un registro che regola come il timer deve gestire l'inversione di stato del pin. Per "buttare fuori" il duty immagine tu voglia dire far uscire il segnale su un pin. Basta mettere quel pin in output con un pinMode(pin, OUTPUT).
Capito! Cerco di fare qualche prova e poi ti faccio sapere che tiro fuori! Grazie mille per la tua spiegazione.
Alex
Mi sono spiegato male. Non parlavo di quello a cui hai accennato tu ma del fatto che puoi affinare la frequenza generata da un timer lavorando sul valore di partenza del registro, che inserisci nel registro stesso dall'interno della ISR di gestione dell'overflow: impostando un valore di partenza diverso per il registro, puoi cambiare la frequenza generata dal timer perché ne cambi in pratica il valore massimo.
sì , impostanto TCNTx , avevo intuito ma bisogna impostarlo per ogni ciclo, per ogni impulso, quindi ogni impulso DEVE generare interrupt,
mentre modificando OCR1x come duty e modificando ICR1 come TOP in modalità 10 o 14 non serve neppure l'interrupt, bisogna comunque riservare particolare cura quando si abbassa ICR1 per evitare il wrap a FFFF del ciclo in corso
quindi si userà la tecnica 'leo72' o 'icio' a seconda dell'utilizzo, del range di frequenza del pwm e delle disponibili nel micro.
anche nella modifica di TCNT bisogna controllare il valore di OCR affinchè non si perda l'impulso in corso e inoltre ridimensionare OCR proporzionalmente per mantenere lo stesso duty