PWM push pull....help! [RISOLTO]

Ma che modalità usi per il timer 2? Non è che forse il contatore incrocia 2 volte OCR2A e quindi generi 2 interrupt?

Dovrebbe essere la CTC.
Questo è quello che uso, preso pari pari da internet

// 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 = 159; // inizializzo il top level match a 159 ->f_PWM=100kHz

Se qualcuno poi mi potesse spiegare gentilmente il significato di 0x23 e 0x09 gli sarei molto grato. Non capisco che bit si vadano a settare in questo modo

ekjk:
Dovrebbe essere la CTC.

La CTC non interagisce con i pin esterni. Si sfrutta per gestire il timer come semplice contatore. Sei sicuro?

Questo è quello che uso, preso pari pari da internet

Ah.. ecco...
quindi non sai com'è stato configurato il timer? Io sinceramente non mi sono messo a recuperare la modalità partendo dai registri modificati, pensavo avessi già fatto il setup tu :wink:

// 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 = 159; // inizializzo il top level match a 159 ->f_PWM=100kHz

Qui c'è scritto "configurazione del Timer 2 per funzionare in modo fast PWM", quindi non è la CTC...

Se qualcuno poi mi potesse spiegare gentilmente il significato di 0x23 e 0x09 gli sarei molto grato. Non capisco che bit si vadano a settare in questo modo

Beh, devi aprire il datasheet, prendere quei valori "infilati" nei registri e recuperare i bit che modificano. Solo così sai come viene impostato il timer.

Intanto grazie per la pazienza :slight_smile:

Mi sono sforzato più volte di leggere il datasheet ma faccio fatica coi timer.

Ho necessità di generare due quadre complementari tutto qua. La frequenza e il duty vorrei poterli impostare.
Ovviamente se aumenta il duty di una quello dell'altra deve diminuire.

Ho controllato, effettivamente il timer viene impostato in Fast PWM con OCRA come top.

Ti consiglio la lettura di questa pagina:

spiega come manipolare i timer in generale, il 2 nello specifico.
Ti sarà d'aiuto.

Grazie mille, ci riprovo.

Se hai bisogno di 2 segnali simili ma invertiti, perché non li fai entrambi con la tecnica del bit-banging?
Imposti il timer 2 in modalità contatore (la CTC, appunto) e ad ogni overflow del timer scambi i livelli dei 2 pin che ti servono.

ciao, ho guardato il link ma non ci ho capito tanto di più, nel senso che non capisco tutti quei simboli usati tipo la tilde o _BV() ecc.

Nel caso del modo CTC, non con overflow ma con compare register, a che frequenza posso arrivare? Mi accontento di 100KHz.

Ho provato ma non mi funziona con il timer 2.

No esiste una libreria in cui ti danno metodi per impostare il pin di uscita, freq e duty?
Io ci sto sclerando con sti timer

Ho passato 3 ore su questi timer ma non mi funziona nulla.
Dovrebbe essere semplice creare due uscite invertite tra loro...non vorrei usare un componente in più per forza

ekjk:
ciao, ho guardato il link ma non ci ho capito tanto di più, nel senso che non capisco tutti quei simboli usati tipo la tilde o _BV() ecc.

~ è il simbolo di inversione, quindi ~1 equivale a 0. Per cui se io faccio ~(1<<TOIE2) significa che metto ad 1 il bit TOIE2 in un byte di registro, e poi ne inverto il valore, quindi diventa tutto ad 1 ed a 0 solo il bit TOIE2. Facendo un AND logico poi spengo quel bit.

No esiste una libreria in cui ti danno metodi per impostare il pin di uscita, freq e duty?
Io ci sto sclerando con sti timer

Usa la PWM Frequency, è una lib che permette di avere un segnale PWM di una determinata frequenza su un qualsiasi pin:
http://playground.arduino.cc/Code/PwmFrequency

Grazie, ma per invertire poi tale segnale generato su un pin utilizzando quella libreria?

ekjk:
Ho necessità di generare due quadre complementari tutto qua. La frequenza e il duty vorrei poterli impostare.
Ovviamente se aumenta il duty di una quello dell'altra deve diminuire.

Scordati di farlo direttamente col 328 a meno che non ti accontenti di bassi valori di frequenza, poche centinaia di Hz.
Il solo modo è utilizzare un inverter esterno che ti fornisce il valore negato del PWM e di conseguenza i due pwm tra loro complementari.

astrobeed:
Scordati di farlo direttamente col 328 a meno che non ti accontenti di bassi valori di frequenza, poche centinaia di Hz.
Il solo modo è utilizzare un inverter esterno che ti fornisce il valore negato del PWM e di conseguenza i due pwm tra loro complementari.

Ubi major minor cessat :sweat_smile:

Quindi non esiste il modo con fastpwm per avere su un pin l'uscita che ne so a 40Khz e su un altro invertita?

ekjk:
Quindi non esiste il modo con fastpwm per avere su un pin l'uscita che ne so a 40Khz e su un altro invertita?

Col PWM hardware no, col PWM software si però vale solo per frequenze molto basse, poche centinaia di Hertz.
Hai solo due possibilità, soluzione semplice usare un inverter sul pin pwm per sdoppiare il segnale e ottenere la sua versione negata, soluzione complicata usare un micro che prevede la modalità complementare per il pwm, non mi pare esista su nessuno degli AVR utilizzati per Arduino.

Mi intrometto per un chiarimento semi off topic, che alla fine non lo è.

Mi sono sempre domandato una cosa, una porta logica invertente non altera in alcun modo (anche se trascurabile) il timing del segnale?
Mi riferisco ad un leggero ritardo sui fronti di salita e discesa.

niki77:
Mi sono sempre domandato una cosa, una porta logica invertente non altera in alcun modo (anche se trascurabile) il timing del segnale?

Il timing no, inteso come frequenza portante e durata del duty cycle, però introduce un piccolo delay, dovuto al tempo di propagazione della porta, nei cambi fronte della porzione di segnale che passa attraverso la porta.
In pratica il pwm che passa attraverso l'inverter cambia di stato con un delay di svariati nanosecondi rispetto al segnale originale, a seconda della frequenza del pwm questa cosa può essere trascurabile oppure può essere necessario compensare con una qualche tipo di linea di ritardo sul pwm originale.

astrobeed:
usare un micro che prevede la modalità complementare per il pwm, non mi pare esista su nessuno degli AVR utilizzati per Arduino.

L'Attiny85 ha 4 uscite PWM di cui 2 collegate allo stesso timer ed invertite l'una rispetto all'altra. Come si vede dalla figura qui sotto, i pin OC1B e /OC1B sono collegati al timer 1 ma con uscita invertita.

Forse possiamo dire TOPIC RISOLTO

Ho trovato un codice in rete di un tizio inglese penso, che ha fatto un modulazione pwm in push pull...allora copio lo sketch e vedo in realtà con l'oscilloscopio che effettivamente una uscita è dritta e una negata...molto bene, ma la frequenza intorno ai 16Khz.

Così smanetto un pò e riesco a modificare la frequenza portandola a 50Khz ed inoltre controllo il duty di entrambe in modo indipendente, non come se avessi una sola uscita e l'avessi negata perchè in quel caso avrei che se il duty di una è 90% l'altra è 10%.
Invece così vario il duty tramite la variabile count da un minimo di 2% ad un max di 95% circa...aggiustabile a piacimento...però bisogna avere un oscillo perchè se non lo avevo col cavolo che riuscivo solo via software a far combaciare i valori dei reigistri OCR1A e B..

Questo è un semplice controllo pwm molto abbozzato...comunque la parte di variazione di duty funziona.

#define PIN_PRI_A   9    // OCR1A - high-active primary drive
#define PIN_PRI_B   10   // OCR1B - low-active primary drive


#define PUSH_PULL   true // false = OCR1A only, true = OCR1A + OCR1B


#define TIMER1_PRESCALE   1     // clock prescaler value
#define TCCR1B_CS20       0x01  // CS2:0 bits = prescaler selection


#define PERIOD_US   20
#define PERIOD_TICKS (microsecondsToClockCycles(PERIOD_US / 2) / TIMER1_PRESCALE)



int count=0;
int duty=2;
float Verror=0;

float Vset=512.0;
float Vact;

unsigned long last=0;
unsigned long wait=20;
boolean first=true;

void setup()
{
  
  pinMode(A0, INPUT); //input tensione
  digitalWrite(A0, LOW);
  
  
  analogWrite(PIN_PRI_A,128);    // let Arduino setup do its thing
  analogWrite(PIN_PRI_B,128);

  TCCR1B = 0x00;                 // stop Timer1 clock for register updates
  
    // Clear OC1A on match, P-F Corr PWM Mode: lower WGM1x = 00
  TCCR1A = 0x80 | 0x00;

// Configure Timer 1 for Freq-Phase Correct PWM
//   Timer 1 + output on OC1A, chip pin 15, Arduino PWM9
//   Timer 1 - output on OC1B, chip pin 16, Arduino PWM10


// If push-pull drive, set OC1B on match

 TCCR1A |= 0x30;


 ICR1 = PERIOD_TICKS;           // PWM period
 OCR1A = duty;      // ON duration = drive pulse width//ucita 9
 OCR1B = duty+156;      //  ditto - use separate load due to temp buffer reg //usita 10
 TCNT1 = OCR1A - 1;             // force immediate OCR1x compare on next tick

// upper WGM1x = 10, Clock Sel = prescaler, start Timer 1 running
 TCCR1B = 0x10 | TCCR1B_CS20;
}

void loop()
{
   OCR1A = duty+count;      // con count vario il duty delle due uscite nello stesso modo
   OCR1B = duty+156-count;  
      
      if(first)
      {
          delay(2000);
          first=false;
      }
      
      Vact=analogRead(A0);
   
      
      Verror=100.0*(Vset-(float)(Vact))/Vset;
         
     
        if(millis()-last>=wait)
        {
          last=millis();
          
            if(Verror<0) count--;
            if(Verror>0) count++;

          if(count<0) count=0; //min duty 2%
          if(count>=70) count=70; //max duty 95%
        }
      

}