modifica frequenza pwm arduino mega senza usare i prescale

Ciao a tutti,
grazie in anticipo per l'aiuto, vi espongo il mio problema:

vorrei creare un pwm modificabile in frequenza e in periodo, ma andando a poter utilizzare delle frequenze diverse da quelle dei prescale, es: 2,7kHz 1,5kHz e via dicendo, al momento non sono riuscito a trovare una libreria che riesca a fare questo, non voglio usare dei delayMicroseconds() perchè mi bloccherebbe il programma.

grazie mille

Ciao, ti posto un codice sul fast pwm, non prenderlo come oro colato perchè l'ho trovato in giro e non mi ricordo neanche se l'ho modificato in qualche modo.

Provato al volo genera 45kHz sul pin 4 e 90kHz sul pin 3, ArduinoUNO.

Magari prendi spunto

int variabile_timer2 = 0;
int duty = 25; //duty cycle 25%
void setup() {
  DDRD |= (1 << DDD3); // pin 3 come output
  DDRD |= (1 << DDD4); // pin 4 come output
  TCCR2A = 0x23; // 00100011
  TCCR2B = 0x09; // 00001001
  OCR2A = 176; // inizializzo il top level match a 176 ->f_PWM=90kHz


  variabile_timer2 = (OCR2A * duty) / 100; //calcolo il duty cycle voluto in base al top level match inserito
  OCR2B = variabile_timer2;
  TIMSK2 = 0b00000010; // abilito tinterrupt sul compare matchA
}

void loop() {

}

ISR(TIMER2_COMPA_vect)
{
  bitSet(PIND, 4); // toggla il pin
}

edit:

QUA il codice originale

grazie, provo e ti dico

Ciao,

non funziona, non vedo un segnale valido sull'oscilloscopio, purtroppo l'unico programma che mi funziona rimane questo

#include <PWM.h>

void setPwmFrequency(int pin, int divisor)
{
 byte mode;
 if(pin == 5 || pin == 6 || pin == 9 || pin == 10)
 {
 switch(divisor) 
 {
 case 1: mode = 0x01; break;
 case 8: mode = 0x02; break;
 case 64: mode = 0x03; break;
 case 256: mode = 0x04; break;
 case 1024: mode = 0x05; break;
 default: return;
 }
 if(pin == 5 || pin == 6) 
 {
 TCCR0B = (TCCR0B & 0b11111000) | mode;
 } 
 else 
 {
 TCCR1B = (TCCR1B & 0b11111000) | mode;
 }
 } 
 else if(pin == 3 || pin == 11) 
 {
 switch(divisor) 
 {
 case 1: mode = 0x01; break;
 case 8: mode = 0x02; break;
 case 32: mode = 0x03; break;
 case 64: mode = 0x04; break;
 case 128: mode = 0x05; break;
 case 256: mode = 0x06; break;
 case 1024: mode = 0x7; break;
 default: return;
 }
 //TCCR2B = (TCCR2B & 0b11111000) | mode;
 TCCR3B = TCCR3B & 0b11111000 | mode;
 }
 
}

void setup(void) 
{
 pinMode(3, OUTPUT);
 setPwmFrequency(3,8);
 //byte mode;
 //mode = 0x01;    // inserire qui il valore del timer desiderato
 //TCCR3B = TCCR3B & 0b11111000 | mode;   // temporizzatore da settare
}

void loop()
{
 analogWrite(3,129);
}

elfuse79:
Ciao,

non funziona, non vedo un segnale valido sull'oscilloscopio, purtroppo l'unico programma che mi funziona rimane questo

Perchè è basato su una UNO, per la Mega il pwm l'hai sul pin 9. Ricordati di impostarlo nel setup come output

Posso solo consigliarti una vecchia applicazione (multipiattaforma) che scrivemmo Leo ed io parecchi anni fa, ma che, per il calcolo del PWM, è ancora valida ... se ne parlava, a suo tempo, QUI ... vedi se può esserti utile ...

Guglielmo

Mi sono riguardato un po' il codice e l'ho sistemato , ora dovrebbe essere un po più chiaro:

ad esempio questo genera una frequenza di 10kHz, duty cycle 25% con prescaler 8

int variabile_timer2 = 0;
int duty = 25; //duty cycle 25%

void setup() {
  pinMode(9,OUTPUT);

 // VEDI DATASHEET PER CONFIGURAZIONE REGISTRI TIMER 2
/*
    CS22     CS21     CS20                Description
      0      0         0           No clock source (Timer/Counter stopped)
      0      0         1           clk T2S /(No prescaling)
      0      1         0           clk T2S /8 (From prescaler)
      0      1         1           clk T2S /32 (From prescaler)
      1      0         0           clk T2S /64 (From prescaler)
      1      0         1           clk T2S /128 (From prescaler)
      1      1         0           clk T 2 S /256 (From prescaler)
      1      1         1           clk T 2 S /1024 (From prescaler)

   OCR2A = (256/f_finale)*(f_clk/(N*510))  con N valore prescaler -- !! OCR2A max val 255 !!
*/
  TCCR2A = 0b00100001; //   COM2A1 COM2A0 COM2B1 COM2B0   –      –   WGM21 WGM20
  TCCR2B = 0b00001010; //   FOC2A  FOC2B    –      –    WGM22  CS22  CS21  CS20
  
  OCR2A = 100; // inizializzo il top level match --> DETERMINO FREQUENZA
  
  variabile_timer2 = (OCR2A * duty) / 100; //calcolo il duty cycle voluto in base al top level match inserito
  OCR2B = variabile_timer2;

}

void loop() {

}

per rispondere alla domanda iniziale: dai prescaler non scappi, però modificando il valore di OCR2A puoi giocare lo stesso sulla frequenza e con OCR2B cambi il duty cycle