PWM VELOCE

Prova con il dealayMicroseconds dentro i for...

Non ho capito una cosa, ma il segnale lo devi modulare visto che parli di trasportare informazioni, oppure ti basta un segnale PWM ad una determinata frequenza?

Ad esempio, il codice qui sotto genera un segnale PWM sul pin 3 a 200 kHz esatti con duty cicle 50% (se non ho sbagliato i calcoli):

pinMode(3, OUTPUT);
TCCR2A |= ((1<<COM2B1) | (1<<WGM21) | (1<<WGM20));
TCCR2B |= ((1<WGM22) | (1<<CS21));
TCCR2B &= (~(1<<CS22) | ~(1<<CS20));
OCR2A = 9;
OCR2B = 4;

Per gestirlo, ti basta mettere in output in pin quando devi iniziare la trasmissione, e metterlo in input per terminarla.

EDIT: questo dovrebbe andare - 200 kHz/50% (se può servire a qualcuno)

Non si modulano in PWM per mandare informazione sulla rete 230V. Sono sistemi diversi.
Un segnale PWM ha una frequenza fissa di base, ma come durata del impulso in certi casi corrisponde a delle frequenze molto piú alte.
per esempio un segnale PWM al 50% corrisponde alla frequenza di ripetizione. Un PWM di 1/256 corrisponde a una frequenza 128 volta piú alta di quella base. Hai della atenuazioni variabili a seconda della percentuale PWM.

Inoltre hai il problema che devi isolare il sitema dalla tensione di rete.

Ci sono varie discussione riguardante powerline. per esempio:
arduino.cc/forum/index.php/topic,85592.0.html

Ciao Uwe

PS:
cmq ho fatto male i conti.. quel codice genera un PWM a 2 MHz.... :sweat_smile:
Ora lo correggo...

Anzitutto grazie per le risposte tutte interessanti.

leo 72: uhm... Mi par bene che tu abbia agito direttamente sui timer ed è una buona idea sicuramente risolutiva. Mi chiedevo però, tornando alla procedura che ho scritto, come mai un loop annidato dopo una scrittura diretta su registro non producesse alcun ritardo... Come se non esistesse, come se non venisse tradotto in linguaggio macchina.

uwefed: mah, quello che sto cercando di fare è un giochetto: il segnale PWM modulato in digitale (0 logico 20% 1 logico 80%) corre assieme all'alternata di alimentazione a 12 volt 50Hz dopo il secondario di un trasformatore che alimenta dei faretti in bassa tensione. Su ogni punto luce viene utilizzata la 50Hz per accendere la lampada e viene filtrata l'onda quadra modulata in PWM con un passaalto (l'onda quadra è appunto a 100kHz) Di quest'onda quadra viene ricavato il valor medio e dunque l'informazione che serve ad accendere, con un codice, una determinata lampada. Così in effetti le lampade si trovano su un bus che porta sia l'alimentazione sia il segnale.

Buona giornata a tutti e a presto.

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()!

Cari saluti.

Qui forse trovi del materiale che potrebbe esserti utile...

http://arduino.cc/forum/index.php/topic,41869.0.html

http://arduino.cc/forum/index.php/topic,84366.0.html

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? :wink:

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.

Grazie Burt.

Ti consiglio questo documento:

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

Grazie a tutti,

ho bazzicato un po' sui link che mi avete suggerito e sono veramente tutti molto interessanti.

A presto sentirci.

Burt

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);
}

Alessiof76:

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

OCR0A=160; //frequenza 100 kHz

for (;:wink:
{
OCR0B=10; //duty cycle basso
delay(1000);
OCR0B=100; //duty cycle elevato
delay(1000);
}

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!

La definizione della funzione delay la trovi nel file wiring.c nella cartella hardware/arduino/cores/arduino/..
Usa il timer 0.

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.

Grazie molte e a presto.

Usa il timer 2, è a 8 bit come lo 0.

... Infatti ho provato proprio con il timer 2 e tutto funziona correttamente.

Grazie mille e a presto!

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

void setup()
{
 TCCR2B = (TCCR2A & 0xF8) | 0x01 ;
 pinMode(9, OUTPUT);
 analogWrite(9,127);
}

void loop(){}

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.