Go Down

Topic: PWM push pull....help! [RISOLTO] (Read 2145 times) previous topic - next topic

leo72

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.

ekjk

#16
Dec 26, 2012, 03:27 pm Last Edit: Dec 26, 2012, 03:50 pm by ekjk Reason: 1
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

ekjk

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

leo72


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.

Quote

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

ekjk

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

astrobeed


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.

leo72


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  :smiley-sweat:

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?


astrobeed


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.

niki77

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.
Vi è una spiegazione scientifica a tutto.
La fede è solo quell'anello che si porta al dito dopo il matrimonio.

astrobeed


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.


leo72


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.

ekjk

#27
Dec 28, 2012, 08:19 pm Last Edit: Dec 29, 2012, 10:40 am by ekjk Reason: 1
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.

Code: [Select]

#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%
       }
     

}

Go Up