Go Down

Topic: Problema con PWM (Read 1 time) previous topic - next topic

matti157

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

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

uccio

devi usare Serial.available()

Code: [Select]
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);
     }
}

uwefed

#2
Jul 25, 2010, 11:18 am Last Edit: Jul 25, 2010, 11:21 am by uwefed Reason: 1
ciao Matti157
comunque sappi che Serial read prende solo un carattere; se vuoi ricevere dei valori fino a 255 devi fare diversamente:

Code: [Select]


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

MGuruDC

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
Linux User #503422 | Linux Machine #414597-8 | Ubuntu User #30132

uccio


uwefed

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

matti157

grazie a tutti per le risposte molto precise  ;)
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.

matti157

#7
Jul 26, 2010, 10:28 pm Last Edit: Jul 26, 2010, 10:54 pm by matti157 Reason: 1
ok ho provato il codice:
Code: [Select]

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)

uwefed

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

matti157

ok grazie! non ci arrivavo mica  :-[

MGuruDC

Quote
@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
Linux User #503422 | Linux Machine #414597-8 | Ubuntu User #30132

MGuruDC

Quote
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.

Code: [Select]
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
Linux User #503422 | Linux Machine #414597-8 | Ubuntu User #30132

Go Up