[ RISOLTO ] Problema con codice il pwm non funziona come vorrei...

Ciao,allego codice per un comportamento del pwm che non riesco a darmi una risposta.
Creo un Pwm variabile tramite due pulsanti ( up - down ) che mi fanno variare l'uscita del pin 3.
Quando vado a settare tramite i due pulsanti una combinazione ( ton=255 e toff=0) in uscita dal pin 3 non mi trovo 5vcc ,ma bensì 4,5vcc,la stessa cosa mi succede con ( ton=0 toff=255 ) nella maniera inversa non mi trovo 0vcc,ma sempre 0,7vcc,come mai??
Quando inserisco il monitor seriale nel codice ton e toff,variano correttamente da 0 a 255.
Dove sbaglio nel codice??
Grazie,Mauro.

// Settaggio delle Variabili
unsigned int input;             // controllo input ton / toff
unsigned int counter;           // contatore lettura stato pulsante
unsigned int ton;               // stato semionda periodo HIGH
unsigned int toff;              // stato semionda periodo LOW
byte pulsanti;                  // combinazione booleana degli input (puls_up || puls_down )
byte puls_up = 12;              // pulsante ( ++ ) incrementa la luminosità
byte puls_down = 11;            // pulsante ( -- ) decrementa la luminosità
byte stripled = 3;              // pin dove viene collegato il mio load ( con oppurtuno driver mosfet )

#define valmax 255              // valore massimo 
#define valmin 0                // valore minimo
#define valoremaxcounter 100    // letture da eseguire prima di cambiare il valore

// Settaggio solo alla 1^ accensione
void setup() {
  pinMode(stripled, OUTPUT);            // al pin  3 è collegato il mio load
  pinMode(puls_up, INPUT_PULLUP);       // al pin 12 è collegato il pulsante ++ luminosità
  pinMode(puls_down, INPUT_PULLUP);     // al pin 11 è collegato il pulsante -- luminosità
}

void controllapulsanti (void) {
  pulsanti = digitalRead(puls_up) * 2 + digitalRead(puls_down) * 1; 
// Verifico la combinazione booleana degli input se :
// 
// byte pulsanti 00000000B  combinazione non accettata     !!
// byte pulsanti 00000001B  combinazione puls_up premuto   !! 
// byte pulsanti 00000010B  combinazione puls_down premuto !!
// byte pulsanti 00000011B  combinazione non accettata     !!

switch (pulsanti) {
  case 0 :
      // entrambi i pulsanti sono premuti !!
      {
        counter = 0;
        break;
      }

      case 2 :
      // solo il pulsante puls_down è premuto !!
      {
        counter++;
        if (counter == valoremaxcounter)
        {
          if (toff != valmax)   // se toff è diverso dal valore valmax !!
          {
            toff++;             // incrementa tramite il puls_down il periodo LOW  dell'onda quadra
            ton--;              // decrementa tramite il puls_down il periodo HIGH dell'onda quadra
            counter = 0;        // resetta counter letture !!
          }
        }
        break;
      }

      case 1 :
      // solo il pulsante puls_up è premuto !!

      {
        counter++;
        if (counter == valoremaxcounter)
        {
          if (ton != valmax)    // se ton è diverso dal valore valmax !!
          {
            ton++;              // incrementa tramite il puls_up il periodo HIGH  dell'onda quadra
            toff--;             // decrementa tramite il puls_up il periodo LOW   dell'onda quadra
            counter = 0;        // resetta counter letture !!
          }
        }
        break;
      }

      case 3 :
      // entrambi i pulsanti non sono premuti !!
      {
        counter = 0;
        break;
      }

    }
  }



// Programma Principale
void loop() {
  digitalWrite(stripled, LOW);                    // metti a LOW l'uscita inizialmente
  counter = 0;                                    // reset iniziale delle letture 
  ton = valmin;                                   // valore iniziale ton
  toff = valmax;                                  // valore iniziale toff

  while(1) {
    
    digitalWrite(stripled, HIGH);                 // imposta il periodo HIGH l'uscita
    for ( input = 0 ; input < ton ; input++ );    // aspetta un periodo prefissato da ton
    controllapulsanti();                          // controlla stato pulsanti
    
    digitalWrite(stripled, LOW);                  // imposta il periodo LOW  l'uscita
    for ( input = 0 ; input < toff ; input++);    // aspetta un periodo prefissato da toff
    controllapulsanti();                          // controlla stato pulsanti
    
  }
}

Non sono riuscito a capire bene cosa vuoi fare :sweat_smile: :sweat_smile:
Potresti spiegarti meglio? Cos'è che sono ton e toff?

Il codice è giusto? Parli di "attese" ma non vedo attese all'interno della funzione richiamata dal for.

Invece di ricreare un PWM simulato, non è meglio se usi la funzione analogWrite() ?
Per rispondere alla domanda bisognerebbe controllare con uno oscilloscopio o con un analizzatore di livelli logici cosa succede effettivamente al segnale.

Inoltre secondo me il compilatore ottimizza i cicli for.
Dovresti aggiungere

// add this to the top of your sketch
#define NOP __asm__ __volatile__ ("nop\n\t")

e nel for

     digitalWrite(stripled, HIGH);                 // imposta il periodo HIGH l'uscita
    for ( input = 0 ; input < ton ; input++ )
        NOP;    // aspetta un periodo prefissato da ton
    controllapulsanti();                          // controlla stato pulsanti
    
    digitalWrite(stripled, LOW);                  // imposta il periodo LOW  l'uscita
    for ( input = 0 ; input < toff ; input++)
        NOP;    // aspetta un periodo prefissato da toff
    controllapulsanti();                          // controlla stato pulsanti

Credo che il motivo sia legato al fatto che il codice in esecuzione prende del tempo CPU. Inoltre da un PWM non puoi aspettarti la minima tensione 0Vdc e la massima 5Vdc ma una tensione nei dintorni a queste.

Anche il PWM di Arduino è affetto dallo stesso "problema", e per ovviare nel codice interno assegnare un PWM massimo equivale a mettere il Pin relativo High, stessa cosa per Low.

Ciao.

Ciao,in questa risposta spero di spiegare meglio il problema che mi trovo ad'affrontare.
Allora ton = semiperiodo dove il mio segnale è Alto del periodo T dell'onda quadra
toff = semiperiodo dove il mio segnale è Basso del periodo T dell'onda quadra
Quando tengo premuto l'input ( puls_up) incremento il semiperiodo ton e di conseguenza decremento il semiperiodo toff,invece quando tengo premuto l'input (puls_down ) incremento il semiperiodo toff e di conseguenza decrementoil semiperiodo ton.
Quindi quando mi trovo sul monitor seriale ( ton=255 e toff=0 ,e lo vedo che la lavora correttamente)mi dovrei ritrovare in uscita un segnale sul pin 3 di +5Volt,Giusto??Invece mi ritrovo 4,3Volt ( misurati col multimetro ),stessa cosa mi succede nella versione inversa,ton=0 e toff=255 mi ritrovo 0,7Volt e non 0Volt,ma come mai??
Magari per creare un PWM ho utilizzato un metodo un pò strano,ma l'idea mi è nata così nella testa e ho scritto il codice in questa maniera,potrei sicuramente scrivere il codice in un'altra maniera,ma adesso volevo solo capire dove sbaglio,solo questo.Grazie comune per le risposte precedenti e future.Ciao Mauro

ps= scusate ma spiegare le cose su tastiera non è il mio forte... :~

Questo è uno di quei casi in cui in teoria il codice deve funzionare ma nella pratica non funziona.

Il perché non funziona....ma chi dice che c'è un solo motivo, anzi è raro che ci sia un solo motivo e se per caso se ne trova uno solo ci sono buone probabilità che c'è ne siano altri che però ancora non sono saltati fuori.

Quindi, parti dal presupposto che non funziona, cioè fidati dei fatti.

I fatti:
Chi ti dice che il tuo tester è in grado di fare il calcolo corretto del valore medio di una grandezza alternata, con rapporto pausa impulso variabile e forma d'onda quadra?
In pratica solo pochi multimetri sono in grado di dare risultati concreti, e questi strumenti in genere non sono economici.

Il codice imposta un pin, es PIND0 high, poi inizia un ciclo for senza corpo, con l'obbiettivo di creare un ritardo variabile, poi viene eseguito del codice per intercettare la pressione o meno dei tasti, codice che richiede del tempo che si somma volente o nolente al codice di ritardo voluto.

Poi viene posto il PIND0 low e questo rimane in questo stato per un tempo dato dalla somma del tempo CPU per eseguire il ritardo voluto e quello introdotto dalla routine della intercettazione pressione tasti.

Quindi anche in presenza di un tempo on massimo e un tempo off uguale a 0 (zero) tra i due stati c'è il ritardo introdotto dalla routine di intercettazione tasti.

Solitamente l'alimentazione proveniente dalla USB non è precisamente di 5.0V, con alcuni PC la tensione misurata è inferiore e molto vicina al valore di 4.3Vdc, quindi verificherei la tensione di uscita della USB del tuo PC misurando la tensione direttamente sui pin della scheda Arduino.

Cicli for o while ecc senza corpo possono essere ottimizzati dal compilatore in modo del tutto singolare, come interviene il compilatore dipende appunto dal compilatore usato e dalle flags di ottimizzazione. L'ottimizzazione massima viene risolta dal compilatore in: tolgo totalmente il ciclo for senza corpo.

ps= scusate ma spiegare le cose su tastiera non è il mio forte... smiley-confuse

Si, capisco, ma il codice parla chiaro, molto più chiaro di quanto possa essere io o qualunque altra
persona nota per la propria capacità di spiegarsi, semplicemente perché noi umani usiamo un linguaggio
ricco e molto ambiguo.

Ciao.

Ciao,ringraziando tutti coloro che mi hanno cercato di dare un loro pensiero o un loro suggerimento ,allego le modifiche che ho implementato ( grazie all'aiuto di un mio collega ) nel codice nella parte del "programma principale ".

// Programma Principale
void loop() {
  digitalWrite(stripled, LOW);                    // metti a LOW l'uscita inizialmente
  counter = 0;                                    // reset iniziale delle letture 
  ton = valmin;                                   // valore iniziale ton
  toff = valmax;                                  // valore iniziale toff

  while(1) {
    
    if( ton != 0){                                // se ton  è diverso da 0 setta pin 3 HIGH !!!
    digitalWrite(stripled, HIGH);                 // imposta il periodo HIGH l'uscita
    for ( input = 0 ; input < ton ; input++ );    // aspetta un periodo prefissato da ton
    }
    controllapulsanti();                          // controlla stato pulsanti
    
    if( toff != 0){                               // se toff è diverso da 0 setta pin 3 LOW !!!
    digitalWrite(stripled, LOW);                  // imposta il periodo LOW  l'uscita
    for ( input = 0 ; input < toff ; input++);    // aspetta un periodo prefissato da toff
    }
    controllapulsanti();                          // controlla stato pulsanti
    
  }
}

Mi è stato suggerito di inserire un if prima del digitalWrite,per capire se ton e toff sono diversi dal valore 0.In questo modo il codice funziona una Meraviglia,e mi ritrovo +5volt ( con ton=255 e toff=0 ) e 0volt ( con ton=0 e toff=255 ).
Ciao,Mauro