Problema con PWM

Ciao a tutti, volevo controllare per esercitarmi l'intensità di luce di un led leggendo il valore attraverso porta seriale, ho scritto questo codice:

const int led = 9;  //Pin del led (PWM OK)
int valore_letto = 0;   //Variabile che memorizza il valore letto     

void setup()
{
  Serial.begin(9600);  //Impostazione del baud-rate
}

void loop() 
{
  valore_letto = Serial.read(); //Legge un valore dalla seriale e lo memorizza in valore_letto
  analogWrite(led, valore_letto);  //Accende il led secondo il valore          
  Serial.print("\t output = ");    //Restituisce in uscita la scritta  
  Serial.println(valore_letto);    //Restituisce in uscita il valore 
}

peccato che non funzioni, tramite il serial monitor visualizzo sempre il valore -1 in valore_letto, il led rimane acceso e per qualsiasi numero che do in input sempre attraverso il serial monitor (fino a 255) valore_letto incrementa fino a 49 per un secondo e il led lampeggia

devi usare Serial.available()

void loop() {

      // send data only when you receive data:
      if (Serial.available() > 0) {
            // read the incoming byte:
            incomingByte = Serial.read();

            // say what you got:
            Serial.print("I received: ");
            Serial.println(incomingByte, DEC);
      }
}

ciao Matti157
comunque sappi che Serial read prende solo un carattere; se vuoi ricevere dei valori fino a 255 devi fare diversamente:

char Data[4];
int PWM =0;
int i =0;

...


do {      // aspetta di leggere 3 Byte e li mettere nella stringa Data.
     if (Serial.available()) {
       Data[i] = Serial.read();
     i++;
     }
   } while (i<3);  
   
Data[i] = 0;    // aggiunge un zero finale per chiudere la stringa
i=0;
   
PWM = atof(Data);  // trasforma la stringa in un numero

....

Ciao Uwe

Come già ti hanno detto SerialRead legge un solo byte che comunque può valere al massimo 128 a meno che da parte del computer non usi un sistema diverso dal SerialMonitor che tratta solo caratteri ascii. Da parte dell'Arduino il dato andrebbe letto come unsigned char per arrivare a 255.
Quel "-1" che leggi significa "non ci sono dati" e questo succede perché il computer dovrebbe mandare il byte proprio mentre l'Arduino esegue il SerialRead... alquanto difficile.
Per ovviare devi mettere l'Arduino a fare un "polling" della seriale con la funzione SerialAvailable... che semplicemente restituisce true quando in ingresso c'è un dato diverso da "-1".
La tua applicazione è semplice e non ci sono problemi a farlo, ma per applicazioni più complesse il polling è un vero problema perché il processore deve starsene ad ascoltare la seriale senza fare nient'altro, in questi casi si dovrebbe assegnare un interrupt alla porta ma sull'Arduino non so ancora come si fa, probabilmente bisogna ricorrere all'AVR-C o all'asm... boh!
ciao

@MGuruDC
per gli interrupt http://www.arduino.cc/en/Reference/AttachInterrupt

Ragazzi non complicarsi la vita sparando in alto;
Pe il momento la soluzione da me proposta va bene per il problema di matti157 . Se ci fossero altre esigenze cambierá il codice.
Ciao Uwe

grazie a tutti per le risposte molto precise :wink:
sono rimasto molto contento di Arduino e del vostro forum che leggo quotidianamente e ne approfitto magari per fare una proposta:
si dovrebbe aprire un thread ufficiale di Arduino sui maggiori forum di informatica (tipo hwupgrade) per farlo conoscere un po' di più, io ci ho già messo del mio!

domani poi proverò il codice, comunque ora i valori li invio via serial monitor e poi tramite un'interfaccia in visual basic semplice da fare.

ok ho provato il codice:

char Data[4];
int pwm =0;
int i =0;
const int led = 9;  //Pin del led (PWM OK)

void setup()
{
  Serial.begin(9600);  //Impostazione del baud-rate
}

void loop() 
{
  do {      // aspetta di leggere 3 Byte e li mettere nella stringa Data.
     if (Serial.available()) {
       Data[i] = Serial.read();
     i++;
     }
   } 
   while (i<3); 
  {
    Data[i] = 0;    // aggiunge un zero finale per chiudere la stringa
    i=0;
  }
  
 pwm = atof(Data);  // trasforma la stringa in un numero


  analogWrite(led, pwm);           //Accende il led secondo il valore          
  Serial.print("\t output = ");    //Restituisce in uscita la scritta  
  Serial.println(pwm);    //Restituisce in uscita il valore 
}

solo che ci sono problemi:
-apro il serial monitor, digito 20 per fare accendere il led in modo lieve, a questo punto succede che la prima volta che do il numero non cambia nulla, il led rimane spento e non si visualizza il messaggio di risposta da arduino, la seconda volta il valore viene letto ma viene interpretato come un 202, facendo accendere così il led ad una forte intensità, la terza volta che do il 20 in input funziona tutto bene

-provo con 50, la prima volta mi viene restituito valore di 305, la seconda niente, la terza un 505 e la quarta finalmente 50

-PER FARE ANDARE I NUMERI A 3 CIFRE HO MODIFICATO IL TUO CODICE METTENDO 2 PARENTESI GRAFFE DOPO IL CICLO WHILE, SPERO DI AVER FATTO GIUSTO, ALTRIMENTI AI NUM. DI 3 CIFRE VENIVA TRONCATA L'ULTIMA CIFRA

(scusate il maiuscolo)

devi scrivere 020 e 050; devi sempre trasmettere 3 numeri
Ciao Uwe

ok grazie! non ci arrivavo mica :-[

@MGuruDC
per gli interrupt http://www.arduino.cc/en/Reference/AttachInterrupt

Grazie, conosco attach e detach interrupt, ma queste funzioni assegnano interupt a un pin, mica a una porta!
Il problema è far partire l'interrupt quando la porta segna !=-1... boh

solo che ci sono problemi:
-apro il serial monitor, digito 20 per fare accendere il led in modo lieve, a questo punto succede che la prima volta che do il numero non cambia nulla, il led rimane spento e non si visualizza il messaggio di risposta da arduino, la seconda volta il valore viene letto ma viene interpretato come un 202, facendo accendere così il led ad una forte intensità, la terza volta che do il 20 in input funziona tutto bene

-provo con 50, la prima volta mi viene restituito valore di 305, la seconda niente, la terza un 505 e la quarta finalmente 50

-PER FARE ANDARE I NUMERI A 3 CIFRE HO MODIFICATO IL TUO CODICE METTENDO 2 PARENTESI GRAFFE DOPO IL CICLO WHILE, SPERO DI AVER FATTO GIUSTO, ALTRIMENTI AI NUM. DI 3 CIFRE VENIVA TRONCATA L'ULTIMA CIFRA

Io uso questa funzione che mi permette di leggere numeri anche senza mandare gli zeri prima.

void acquis(){
  for(i = 0; i < 10; i ++) {  //pulisce il buffer
    buf[i] = 0;
  }
  for(i = 0; Serial.available() > 0; i ++) {  //in caso di errore segnala e esce dalla funzione
    if (i > 10) {
      Serial.println("Errore");
      Serial.flush();
      return;
    }
    buf[i] = Serial.read();  //memorizza nel buffer i dati in arrivo
  }
  if (i > 0){
    T = 0;
    i --;
    for (esp = 0; i >= 0; i --) {  //converte i caratteri del buffer in un numero intero
      T += (buf[i] - 48)*pow(10, esp);
      esp++;
    }
  }

L'ultimo ciclo for può essere sostituito con la funzione atoi(quando ho scritto questo codice non sapevo della sua esistenza).
I problemi che avevi in pratica sono legati al fatto che non pulivi il buffer prima si usarlo e al fatto che non ti affidavi alla velocità della porta per scrivere il buffer.
ciao