Pages: 1 2 [3] 4 5   Go Down
Author Topic: PWM VELOCE  (Read 4963 times)
0 Members and 1 Guest are viewing this topic.
Camisano Vicentino (VI), Italy
Offline Offline
God Member
*****
Karma: 5
Posts: 956
ƎR like no other.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

il timer sarebbe il 3 dell'atmega2560, volevo provare ad una frequenza di 3khz, perchè a 8 sembra troppo alta...
Logged

Riccardo Ertolupi of the Vicenza Thunders Team: http://www.VicenzaThunders.com

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 333
Posts: 22996
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Secondo i miei calcoli, basta mettere un prescaler di /8 e si ottiene una frequenza di 3049 Hz senza dover modificare il contatore, quindi senza ISR aggiuntive.

Fai così:
Code:
cli(); //fermi gli interrupt
//prescaler a /8
TCCR3B |= (1<<CS31);
TCCR3B &= ~((1<<CS30) | (1<<CS32));
sei();
Adesso basta fare un analogWrite(pin, 127) per avere un'onda a 3 Khz circa con duty cicle al 50%. Prova e fammi sapere.
Logged


Camisano Vicentino (VI), Italy
Offline Offline
God Member
*****
Karma: 5
Posts: 956
ƎR like no other.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Secondo i miei calcoli, basta mettere un prescaler di /8 e si ottiene una frequenza di 3049 Hz senza dover modificare il contatore, quindi senza ISR aggiuntive.

Fai così:
Code:
cli(); //fermi gli interrupt
//prescaler a /8
TCCR3B |= (1<<CS31);
TCCR3B &= ~((1<<CS30) | (1<<CS32));
sei();
Adesso basta fare un analogWrite(pin, 127) per avere un'onda a 3 Khz circa con duty cicle al 50%. Prova e fammi sapere.
grazie mille! appena ho tempo provo smiley-wink
Logged

Riccardo Ertolupi of the Vicenza Thunders Team: http://www.VicenzaThunders.com

Camisano Vicentino (VI), Italy
Offline Offline
God Member
*****
Karma: 5
Posts: 956
ƎR like no other.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

finalmente l'ho provato, mi viene una frequenza di 3,92khz
una curiosità, il pezzo di programma che hai fatto tu equivale a scrivere
Code:
TCCR3B = (TCCR3B & 0xF8) | 0x02 ;
che è quello che fanno anche qui: http://sobisource.com/?p=195 no? si cambia solo il prescaler?
Logged

Riccardo Ertolupi of the Vicenza Thunders Team: http://www.VicenzaThunders.com

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 333
Posts: 22996
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

finalmente l'ho provato, mi viene una frequenza di 3,92khz
una curiosità, il pezzo di programma che hai fatto tu equivale a scrivere
Code:
TCCR3B = (TCCR3B & 0xF8) | 0x02 ;
che è quello che fanno anche qui: http://sobisource.com/?p=195 no? si cambia solo il prescaler?
Sì, si cambia solo il prescaler. Solo che io l'ho fatto manipolando i singoli bit, ottenendo un codice più leggibile.

PS:
avevo scritto che avresti ottenuto una frequenza di circa 3 KHz perché ho invertito i numeri, avevo letto 3,092 invece di 3,902 Khz. Scusa  smiley-sweat
Ti va bene lo stesso oppure vuoi 3 KHz precisi?
Logged


Camisano Vicentino (VI), Italy
Offline Offline
God Member
*****
Karma: 5
Posts: 956
ƎR like no other.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

per adesso va bene, devo ancora capire cosa non va sul driver motori quindi mi serve solo per provare smiley-yell
Logged

Riccardo Ertolupi of the Vicenza Thunders Team: http://www.VicenzaThunders.com

Camisano Vicentino (VI), Italy
Offline Offline
God Member
*****
Karma: 5
Posts: 956
ƎR like no other.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

adesso sto riprovando, il mio driver non riesce neanche a stare dietro ai 980hz di default del pwm abbinato al TIMER0... se abbasso la frequenza di quel pwm rischio di avere problemi con i delay, millis, pulseIn e tutte le altre funzioni che si basano su quel timer... c'è una soluzione "indolore" per diminuire la frequenza di quel PWM senza andare a dare problemi alle altre funzioni?
grazie
Logged

Riccardo Ertolupi of the Vicenza Thunders Team: http://www.VicenzaThunders.com

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 333
Posts: 22996
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

adesso sto riprovando, il mio driver non riesce neanche a stare dietro ai 980hz di default del pwm abbinato al TIMER0... se abbasso la frequenza di quel pwm rischio di avere problemi con i delay, millis, pulseIn e tutte le altre funzioni che si basano su quel timer... c'è una soluzione "indolore" per diminuire la frequenza di quel PWM senza andare a dare problemi alle altre funzioni?
grazie
Premesso che il timer 0 non va toccato più di tanto perché è configurato in modo da lavorare con quella frequenza (976 Hz) pena l'alterazione delle funzioni temporali (come hai giustamente evidenziato), ci potrebbe essere una soluzione "rustica".
Si potrebbe modificare la ISR dell'overflow del timer 0 ed inserire alla fine la generazione di un segnale PWM su un pin predeterminato con frequenza dimezzata (quindi 488 Hz).
Per semplificare molto la cosa affinché la routine non pesi sul resto della ISR così che i tempi rimangano il più possibile esenti da alterazioni si dovrebbe rendere il codice molto snello, quindi niente impostazioni avanzate selezionabili da codice ecc.. giusto le istruzioni per fare ciò che deve su un pin preimpostato.
Logged


Camisano Vicentino (VI), Italy
Offline Offline
God Member
*****
Karma: 5
Posts: 956
ƎR like no other.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

ogni volta che parli di modificare l'ISR non capisco mai dove è il codice nel quale devo andare a mettere le mani... smiley-sweat

ero partito con l'idea del pwm veloce e adesso mi trovo a dover fare un pwm lento, se avessi a disposizione un generatore di funzione vorrei proprio fare uno sweep per vedere a che frequenza taglia questo driver motori, sul datasheet non l'ho visto... domani provo a farlo con l'arduino...

ho un'altra domanda: se io vario la frequenza di un pwm di conseguenza vario anche quella di tutti i pwm legati a quel timer? o dipende come lo vario?
Logged

Riccardo Ertolupi of the Vicenza Thunders Team: http://www.VicenzaThunders.com

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 333
Posts: 22996
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

ogni volta che parli di modificare l'ISR non capisco mai dove è il codice nel quale devo andare a mettere le mani... smiley-sweat
Beh, avendo passato un pò di ore a guardare tutti i file del core di Arduino, poi le cose so dove cercarle  smiley-wink

Quote
ho un'altra domanda: se io vario la frequenza di un pwm di conseguenza vario anche quella di tutti i pwm legati a quel timer? o dipende come lo vario?
Partiamo a monte. C'è un timer. Un timer è un circuito che contiene un contatore aggiornato da un circuito collegato ad un prescaler, ossia un divisore di clock posto sull'ingresso. Grazie a questo divisore, posso variare il segnale d'ingresso per cui posso diminuire a mio piacimento la frequenza con la quale viene aggiornato il contatore. Il contatore poi è un registro in RAM per cui posso anche variarne il contenuto. In questo modo posso ottenere overflow molto rapidi oppure molto lenti, a seconda di come imposto il tutto.

Ora vediamo come possiamo usare il timer. Lo possiamo usare essenzialmente in 3 modi: per generare un segnale di interrupt, per cambiare lo stato di un pin oppure per sollevare entrambi gli eventi.
Se lo uso solo per sollevare un interrupt, il timer diventa un semplice contatore. Se invece lo collego materialmente ad un pin esso diventa un generatore di segnale PWM, la cui frequenza e duty cicle varia in base a come lo impostiamo (se in modalità FastPWM, Phase Correct PWM, con controllo sul valore massimo e/o sul valore minimo ecc.... ci sono una dozzina di modi differenti per sistemarlo).

E' ovvio che il timer 0 è "delicato", nel senso che essendo già stato impostato dal core di Arduino per determinate funzioni, se vai a toccare il prescaler, il valore del contatore, il duty cicle o la modalità di generazione del segnale PWM, alteri tutto quello che c'è a valle.

Fin qui è chiaro, no?

Adesso come possiamo variarlo? Se noi inseriamo una piccola routine alla fine della funzione che intercetta l'overflow del timer 0, che sull'Arduino è usata per la gestione del contatore di millisecondi, possiamo fargli eseguire delle operazioni. Ad esempio, possiamo variare lo stato di un pin a nostro piacimento, alternandolo LOW/HIGH con una frequenza dimezzata rispetto a quella del timer. Per far ciò basta cambiare lo stato di questo pin ogni 2 chiamate della ISR così che se la ISR lavora a 976 Hz il nostro generatore di PWM lavori ad una frequenza di (976/2)=488 MHz.

Fai questo test. Apri il file /arduino-1.0.2/hardware/arduino/cores/arduino/wiring.c
Intorno alla posizione 44 la funzione che intercetta l'overflow del contatore del timer (che usa una parola chiave, SIGNAL, che sui compilatori avr-gcc sta andando in "deprecato", sostituita appunto dalla parola chiave ISR)

Il codice è questo:
Code:
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
SIGNAL(TIM0_OVF_vect)
#else
SIGNAL(TIMER0_OVF_vect)
#endif
{
// copy these to local variables so they can be stored in registers
// (volatile variables must be read from memory on every access)
unsigned long m = timer0_millis;
unsigned char f = timer0_fract;

m += MILLIS_INC;
f += FRACT_INC;
if (f >= FRACT_MAX) {
f -= FRACT_MAX;
m += 1;
}

timer0_fract = f;
timer0_millis = m;
timer0_overflow_count++;
}

Tu modificalo così:
Code:
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
SIGNAL(TIM0_OVF_vect)
#else
SIGNAL(TIMER0_OVF_vect)
#endif
{
volatile static uint8_t _tempBitStatus = 0; //MOD

// copy these to local variables so they can be stored in registers
// (volatile variables must be read from memory on every access)
unsigned long m = timer0_millis;
unsigned char f = timer0_fract;

m += MILLIS_INC;
f += FRACT_INC;
if (f >= FRACT_MAX) {
f -= FRACT_MAX;
m += 1;
}

timer0_fract = f;
timer0_millis = m;
timer0_overflow_count++;

if (_tempBitStatus & 1) { //MOD
PORTD |= (1<<7); //MOD
} else { //MOD
PORTD &= ~(1<<7); //MOD
} //MOD
_tempBitStatus++; //MOD
}

Adesso carica questo sketch sul tuo Arduino:
Code:
void setup() {
}

void loop() {
    //accende e spenge il PWM sul pin 7 ogni 5 sec
    pinMode(7, OUTPUT);
    delay(5000);
    pinMode(7, INPUT);
    delay(5000);
}
Controlla il segnale sul pin 7: avrai un PWM con frequenza dimezzata rispetto a quella solita generata dal timer 0, che viene accesa e spenta ogni 5 secondi.
Logged


Camisano Vicentino (VI), Italy
Offline Offline
God Member
*****
Karma: 5
Posts: 956
ƎR like no other.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

ok grazie mille per la spiegazione! smiley-wink ora ho capito smiley

nella prova pratica però ho dei dubbi, premetto che ho sistemato i codice perchè io ho solo un arduino mega e il pin 7 della porta D è il pin 38, comunque la frequenza è giusta, circa 476Hz, ho provato col mio oscilloscopio... ma c'è una cosa che non capisco: quando metto com input resta comunqe acceso un po' il led... smiley-roll-blue
ma così non posso variare il pwm, no?
Logged

Riccardo Ertolupi of the Vicenza Thunders Team: http://www.VicenzaThunders.com

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 333
Posts: 22996
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

nella prova pratica però ho dei dubbi, premetto che ho sistemato i codice perchè io ho solo un arduino mega
Scusa, ma hai finito i pin PWM Per caso?
Perché altrimenti non capisco per quale motivo vuoi alterare il timer 0.
Lo sai, vero, che a parte il timer 0 gli altri timer sono impostati per avere una frequenza di ~488 Hz e che solo il timer 0 è impostato per avere ~976 Hz? Se il tuo problema era avere un PWM a bassa frequenza, allora è un "non problema".  smiley-wink

Quote
e il pin 7 della porta D è il pin 38, comunque la frequenza è giusta, circa 476Hz, ho provato col mio oscilloscopio...
Non avevi specificato della Mega, per cui ho preso per buono il fatto di una Arduino Uno/2009. Comunque il tutto è facilmente adattabile, basta modificare il bit ed il registro della porta.

Quote
ma c'è una cosa che non capisco: quando metto com input resta comunqe acceso un po' il led... smiley-roll-blue
Mettendo il pin in input, nel momento in cui viene scritto il segnale HIGH si accende la pull-up interna, che viene spenta quando il segnale viene messo su LOW.
Come ti avevo spiegato, per ridurre al minimo l'impatto sui calcoli del tempo, ho messo una routine più semplice possibile.
Volendo si può rivedere il codice affinché stacchi proprio il segnale dal pin quando lo metti in input. Però si torna a quanto ti ho chiesto prima, e cioè: ma hai finito i pin PWM?

Quote
ma così non posso variare il pwm, no?
Col codice che ti ho dato no. E' minimale che di più non si può. Fa solo ON/OFF con frequenza dimezzata rispetto a quella impostata dal timer, tutto qui.
Per alterare il PWM devi alterare le impostazioni del timer, e si torna al discorso che ti facevo nel precedente post.
Logged


Camisano Vicentino (VI), Italy
Offline Offline
God Member
*****
Karma: 5
Posts: 956
ƎR like no other.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

ok ok no problem, grazie delle spiegazioni
purtroppo non pensavo di avere questi problemi con le frequenze dei pwm e avendo il circuito su pcb non mi resta che mettere mano al software smiley-sad
allora se non è possibile modificare la frequenza del pwm del timer 0 devo fare in modo che anche gli altri pwm abbiano lo stesso comportamento, cioè raddoppio le frequenze degli altri pwm che mi interessano, e questo dovrei riuscire a farlo da solo smiley-wink
non mi è chiara ancora una cosa, se io nel timer 2 voglio che un pwm vada a 980hz e un'altro a 18KHz, si può o devo fare una cosa tipo quella che suggerivi di fare per il timer 0?
Grazie smiley-wink
Logged

Riccardo Ertolupi of the Vicenza Thunders Team: http://www.VicenzaThunders.com

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 333
Posts: 22996
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

allora se non è possibile modificare la frequenza del pwm del timer 0 devo fare in modo che anche gli altri pwm abbiano lo stesso comportamento,
In teoria il timer 0 puoi modificarlo come ti pare. Ricordati solo che poi non hai più le funzioni temporali dell'Arduino.
Se la cosa non è fondamentale, puoi farlo.

Quote
cioè raddoppio le frequenze degli altri pwm che mi interessano, e questo dovrei riuscire a farlo da solo smiley-wink
Ma il problema è avere un PWM con frequenza bassa o alta?  smiley-sweat
Prima dici che vuoi una frequenza alta, poi dici che i 976 Hz del timer 0 sono troppi e vuoi dimezzarli, ora invece vuoi raddoppiare la frequenza degli altri timer... deciditi  smiley-yell
Spiega per bene cosa vuoi fare, vediamo se riesco a darti una mano concreta  smiley-wink

Quote
non mi è chiara ancora una cosa, se io nel timer 2 voglio che un pwm vada a 980hz e un'altro a 18KHz, si può o devo fare una cosa tipo quella che suggerivi di fare per il timer 0?
Grazie smiley-wink
Non si può fare. O vai a 18 KHz o vai a 980 Hz.
Però puoi usare un "trucco" come quello che ti ho illustrato per inserire un prescaler software ed avere su un pin un segnale con una frequenza inferiore.
Logged


Camisano Vicentino (VI), Italy
Offline Offline
God Member
*****
Karma: 5
Posts: 956
ƎR like no other.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

ok, il problema è che ho un motore che ha un comportamento diverso dagli altri 3...
però non ho chiaro quale sia la souluzine ideale, vorrei che sul pin 2 ci fosse un pwm con una frequenza di quasi 20KHz, mentre sul 3,4,5 e 6 un pwm di frequenza arbitraria uguale per tutti questi 4 pin... ma da questo link http://sobisource.com/?p=195 vedo che i pin 2, 3 e 5 sono tutti collegati al timer 3 e quindi mi crea problemi smiley-yell
oggi volevo provare a fare lo sweep per vedere a che frequenza taglia ma non mi va più lo schermo del robot e sto ancora lavorando su quello... smiley-yell in un altro topic mi suggerivi di andare a fare un giro a Lourdes, forse sarebbe proprio il caso...
Logged

Riccardo Ertolupi of the Vicenza Thunders Team: http://www.VicenzaThunders.com

Pages: 1 2 [3] 4 5   Go Up
Jump to: