ratto93: Ho provato con la funzione delayMicroseconds(): non funzione perché abbassa notevolmente la frequenza dell'onda quadra a valori non accettabili per la mia applicazione.
Anzi, e questa è una questione che pongo un po' a tutti: la sopracitata funzione sembra non lavorare in modo opportuno per ritardi inferiori a qualche decina di microsecondi. In effetti, oltre alla frequenza che non è rispettata con precisione, si può notare sull'onda generata dell'instabilità forse dovuta alle chiamate ad interrupt interne al micro.
La cosa certa è che se si vuole viaggiare spediti è impossibile usare la funzione digitalwrite()!
Ho usato direttamente i timer per evitare ritardi e/o altri problemi introdotti dal codice, sfruttando l'HW direttamente.
PS:
Perché mettere tutto in un loop infinito fatto con un for quando la routine loop() è essa stessa un ciclo infinito?
leo72: mah, io per non avere le mani legate e anche per questioni di controllo e leggibilità ho modificato la funzione main() togliendo il loop infinito. Naturalmente ho dovuto aggiungerlo nella procedura che ho scritto.
Oggi provo a realizzare il codice che mi hai inviato. La generazione di un'onda quadra a 100kHz e D.C. fisso è solo un primo esperimento per vedere come si comporta Arduino e se genera un'onda stabile e ben formata. In seguito devo certamente modulare il D.C. in digitale ovvero su due livelli.
spiega bene i vari PWM disponibili sul micro. Purtroppo si sofferma molto sui timer ad 8 bit: quelli a 16 sono molto più complessi da gestire, anche se più precisi e con maggiori potenzialità.
Ciao, è il mio primo messaggio in questo forum, abbiamo un problema in comune, generare un segnane e modularlo nelle frequenze dei 100KHz (a dir la verità a me basterbbero (10-40KHz);
Studiando le librerie ho trovato la libreria FrequencyTimer2 (Arduino Playground - FrequencyTimer2) ; nonchè Timer1 e Timer3 ( Arduino Playground - Timer1)
Con queste librerie, se ho capito bene è possibile, con la funzione setPeriod , generare una frequenza impostata su un pin, esiste anche la relativa funzione pwm (che verrà applicata su altri pin connessi al timer)
dacci un occhiata...
spero possa esserti utile
se vuoi questo è un programmino che genera una frequenza variabile in funzione della posizione del potenziometro, con poche modifiche lo adatti al tuo scopo
int variabile=0;
static char mode=0; #define potPin 2 //Pin di ingresso per il potenziometro
int val = 0; //Variabile per salvare lo stato proveniente dal potenziometro
int divisore = 0; //Variabile per definire il numero di cicli di clock che comporranno un periodo d'onda
void setup()
{
// Configurazione del Timer2 per funzionare in modo fast PWM su OC2B (pin 3 di Arduino)
// set pin high on overflow, clear on compare match with OCR2B
TCCR2A = 0x23; // imposto “pin high on overflow”, e “clear on compare match with OCR2B
TCCR2B = 0x09; // seleziono come sorgente di clock I 16MHz di sistema senza prescaler
OCR2A = 1590; // inizializzo il top level match a 159 ->f_PWM=10kHz la frequenza sarà data da 16000000 : il valore di OCR2A
pinMode(3, OUTPUT); // abilito come uscita il pin 3.
}
void loop()
{
val = analogRead(potPin); //leggo il valore dal potenziometro tra 0 e 1023
divisore = 400+val; //assegno un periodo d'onda che andraà da 400 a 1423 ovvero da 40KHz a 11KHz
OCR2A=divisore; //regolo la frequenza in uscita
OCR2B=divisore/2 ; //imposto il duty cicle al 50%
delay(1000);
}
mah, io sono un po' perplesso, ho realizzato il seguente codice utilizzando l'uscita OC0B del micro ovvero la sezione B del timer 0 per avere un'onda quadra da 100 kHz con duty cycle variabile tra un minimo e un massimo:
TCC0A=B00100011; //fast PWM mode non invertito e TOP OCRA anziché FF
TCC0B=B00001001; //no prescaling TOP OCRA anziché FF
il programma lavora correttamente ma la funzione delay non risulta operativa e il duty cycle varia tra un valore ed un altro rapidissimamente come se non ci fosse delay! In teoria dovrei avere un'alternanza di duty cycle alto e basso con un periodo di 1 secondo.
Fosse che la funzione delay utilizza lo stesso timer (timer0) e pertanto viene in qualche modo inibita?
Questo per me è un problema!
PaoloP:
A ecco, allora forse è per quello che non lavora correttamente. Oggi vado a vedere e provo se riesco a risolvere il problema utilizzando un altro timer.
mi collego a questo topic perchè il mio problema è simile, io volevo fare dei segnali pwm ad una frequenza compresa tra 15 e 20 khz per controllare dei motori... io uso un arduino mega quindi i registri dei timer abbinati ai pin sono un po' diversi e mi sono ispirato a quello che ho trovato qui: SobiSource.com is for sale | HugeDomains per scrivere questo codice che mi da circa 31khz sul pin 9
per me però sono troppi perchè ho degli integrati che sopra i 20khz non vanno e quindi quello è il mio limite massimo...
ho provato a leggere vari post per capire come "giocare" con i timer e ho provato varie cose, come dicono qua: http://it.emcelettronica.com/fast-pwm-su-arduino-valida-alternativa-all’istruzione-analogwrite#_ che cambiano la frequenza diminuendo la sensibilità del pwm, ma non sto ottenendo risultati...
Imposta il timer 2 in modalità Phase Correct PWM ad 8 bit.
La frequenza in questa modalità la calcoli così:
Fclk/(2prescalermax_val_cont)
Ora se metti un prescaler di 8 ed usi un valore massimo del contatore di 56 ottieni
160000000/(2856)=17857,qualcosa e ci saresti pienamente.
Per ottenere un valore max del contatore di 56 basta farlo partire da 200, dato che (256-56)=200.
Quindi metti una ISR che reimposta il contatore a 200 ad ogni overflow.
leo72:
Imposta il timer 2 in modalità Phase Correct PWM ad 8 bit.
La frequenza in questa modalità la calcoli così:
Fclk/(2prescalermax_val_cont)
Ora se metti un prescaler di 8 ed usi un valore massimo del contatore di 56 ottieni
160000000/(2856)=17857,qualcosa e ci saresti pienamente.
Per ottenere un valore max del contatore di 56 basta farlo partire da 200, dato che (256-56)=200.
Quindi metti una ISR che reimposta il contatore a 200 ad ogni overflow.
ok grazie mille teoricamente ho capito cosa dovrei riuscire a fare, cos' quando vado a fare l'analogWrite posso arrivare solo fino a 56? o devo partire da 200? o posso andare direttamente sui registri OCRnB?
vale lo stesso processo anche per tutti gli altri timer? per il timer 0 che ha una frequenza doppia mi basta raddoppiare il range del pwm da 56 a 112?
grazie ancora
No no...il 200 lo devi impostare come base nel timer all'interno della ISR. 56 sono gli aggiornamenti che il contatore farà prima di andare in overflow. All'overflow, rimetti il contatore a 200.
Con l'analogWrite gestisci il duty cicle e basta.
Se non hai bisogno di modificare il duty cicle, puoi semplicemente agganciare o sganciare il segnale mettendo il pin in output o input, rispettivamente.
leo72:
No no...il 200 lo devi impostare come base nel timer all'interno della ISR. 56 sono gli aggiornamenti che il contatore farà prima di andare in overflow. All'overflow, rimetti il contatore a 200.
Con l'analogWrite gestisci il duty cicle e basta.
Se non hai bisogno di modificare il duty cicle, puoi semplicemente agganciare o sganciare il segnale mettendo il pin in output o input, rispettivamente.
io devo gestire dei motori, è quindi ho bisogno di poterlo variare da 0 al massimo... nell'analogWrite mi basta mettere valori da 0 a 255 come al solito?
Sì, nell'analogWrite metti valori da 0 a 255. Il mio "no no.." era riferito alla tua precedente domanda in cui chiedevi se dovevi mettere un valore max di 56 nell'analogWrite.
leo72:
Sì, nell'analogWrite metti valori da 0 a 255. Il mio "no no.." era riferito alla tua precedente domanda in cui chiedevi se dovevi mettere un valore max di 56 nell'analogWrite.
ok grazie mille domani provo se riesco a fare qualcosa