Consiglio sul codice: Controllo PWM tramite la porta seriale

Salve,

mi trovo davanti a un problema quanto sciocco (per voi) quanto complicatissimo (per me). Dovrei accendere un pwm con i valori che invio tramite la seriale.

Ho elaborato questo codice:

int a;
int Pin = 10;

void setup{
  Serial.begin(9600);
  pinMode(Pin, OUTPUT);   
}

void loop{
  while(Serial.available() >0)
  {
    a = Serial.read();
    Serial.flush();
    digitalWrite(Pin, a);
}

Ma purtroppo non funziona. Mi sapete aiutare?

Grazie a tutti

è un errorino di sintassi :slight_smile: o almeno creo si solo quello ora attaccol la board e verifico.... :slight_smile:

int a;
int Pin = 10;

void setup(){
  Serial.begin(9600);
  pinMode(Pin, OUTPUT);   
}

void loop(){
  while(Serial.available() >0)
  {
    a = Serial.read();
    Serial.flush();
    analogWrite(Pin, a);
}

correggo il codice, ho omesso due particolari. Però, non funziona ancora:

int a;
int Pin = 10;

void setup () {
  Serial.begin(9600);
  pinMode(Pin, OUTPUT);   
}

void loop () {
  while(Serial.available() >0)
  {
    a = Serial.read();
    Serial.flush();
    analogWrite(Pin, a);
  }
}

Anche tre :slight_smile: sto provando ....

Poi, mi legge i valori come separati. Ho messo un println e vedo che se mando 255, è come se ricevesse 2, 5, 5.

a me da 40 e 50 sempre :cold_sweat:
mi sto rivedendo la lista dei comandi così vedo se trovo qualcosa....
quel Seril.flush(); non mi convince....

Ho trovato quest'esempio sul playground ma non va'.....

/*
  Dimmer
 
 Demonstrates the sending data from the computer to the Arduino board,
 in this case to control the brightness of an LED.  The data is sent
 in individual bytes, each of which ranges from 0 to 255.  Arduino
 reads these bytes and uses them to set the brightness of the LED.
 
 The circuit:
 LED attached from digital pin 9 to ground.
 Serial connection to Processing, Max/MSP, or another serial application
 
 created 2006
 by David A. Mellis
 modified 14 Apr 2009
 by Tom Igoe and Scott Fitzgerald
 
 This example code is in the public domain.
 
 http://www.arduino.cc/en/Tutorial/Dimmer
 
 */

const int ledPin = 9;      // the pin that the LED is attached to

void setup()
{
  // initialize the serial communication:
  Serial.begin(9600);
  // initialize the ledPin as an output:
  pinMode(ledPin, OUTPUT);
}

void loop() {
  byte brightness;

  // check if data has been sent from the computer:
  if (Serial.available()) {
    // read the most recent byte (which will be from 0 to 255):
    brightness = Serial.read();
    // set the brightness of the LED:
    analogWrite(ledPin, brightness);
  }
}

Aggiornamento....
Se comando l'arduino con un altro arduino inviando BYTE funziona....

No ragazzi, non ci siamo...
Studiate bene la documentazione:

  • Serial.read legge 1 e 1 solo solissimo e singolo byte, ovvero un valore che può andare da 0 255.
  • Il Serial monitor di Arduino invia delle stringhe, quindi quando scrivete "255", l'Arduino riceverà i byte corrispondenti ai caratteri ASCII che compongono la stringa "255", ovvero 50, 53 e 53.
  • Per ricostruire sull'Arduino la stringa "255" e poi finalmente usarla per analogWrite... ci sono tonnellate di esempi in giro...

Potete far funzionare i vostri codici (o quello del playground)accedendo alla porta seriale dal lato PC a più basso livello e inviando singoli byte anziché stringhe. Chiedete a San Google...
Ciao

D'OH è vero !!!
Ma come si può fare il casting in arduino ? non l'ho mai fatto in C e con il metodo che si usa in java non va.....
ho trovato questa cosa qui...
int val = atoi(Serial.read());
mi da un errore di conversione con i puntatori ....
Che oo uff.....

Non va bene...

atoi vuole una stringa, tu continui a dargli un singolo byte...

Il C è fortemente tipizzato... non c'è casting tra stringhe è valori numerici, ci vuole una vera e propria conversione.

Prova anche con sscanf e vedi quale delle due versioni occupa di meno.

Lo scanf lo usavo sul pc.. peccato che non mi accetta Serial.scanf(); .....

sscanf, con 2 s.
Non fa parte della classe Serial, è nella libreria standard.
Ciao

sscanf? ragazzi la classe String è la soluzione più immediata. Date un'occhiata al reference per sapere come funziona.

La cosa migliore è atoi che è già usata da qualche parte da processing quindi non viene linkata una nuova funzione.
La classe string è molto facile ma occupa circa 500B (e credo usi atoi in fin dei conti). Se non ci sono molte operazioni sulle stringhe non conviene usarla.
"sscanf" è versatilissima e potentissima... ma da sola richiede più di 1KB...
Ci vuole una scelta
Ciao

un'array di 3 char dovrebbe bastare, in combinazione con atoi

lesto:
un'array di 3 char dovrebbe bastare, in combinazione con atoi

Non ce ne vuole 4? 3 caratteri per le 3 cifre più 1 carattere per "\0" finale.

atoi() sembra praticissimo, anche se nella realtà anch'io ho difficoltà a farla funzionare a dovere.

Un'altro metodo sempliciotto che potresti usare per leggere 3 caratteri e trasformarli in un numero, partendo dall'array di 3 caratteri dalla seriale, potrebbe essere:

byte variabilePerPWM;

variabilePerPWM = (byte)((array[0] - 48)*100 + (array[1] - 48)*10 + (array[2] - 48));

analogWrite(pin, variabilePerPWM);

Sottrarre 48 serve come trasformazione da "numeri in formato carattere" ad un valore intero, se guardi quanto vale il carattere 0 nella tabella ASCII noterai che vale proprio 48

Senza usare atoi per convertire numeri inferiore a 100 dovresti mandare stringhe come "089" oppure "004" e poi...

char inp[4] = "255";
int pwn = atoi(inp);

beh, è semplice.

Comunque, non sta ancora venendo fuori come accumulare nella stringa i dati in ingresso, che sarebbe attinente a topic.
Ciao

leo72:

lesto:
un'array di 3 char dovrebbe bastare, in combinazione con atoi

Non ce ne vuole 4? 3 caratteri per le 3 cifre più 1 carattere per "\0" finale.

hai ragione!

anche il metodo di Federico Vanzati è buono (credo sia più o meno quello che fa atoi dietro le quinte)

@MGuruDC: come hai fatto a calcolare quanti byte occupa una funzione? semplicemente includendo la sua libreria in uno sketch noto? oppure devi chiamare per forza la funzione, e quindi in realtà il calcolo si sballa un minimo?

Comunque, non sta ancora venendo fuori come accumulare nella stringa i dati in ingresso, che sarebbe attinente a topic.

hai ragione.

usiamo il metodo "senza librerie esterne", visto che il compito non è così difficile. Usiamo il metodo di Federico leggertmente modificato. Il numero dovrà essere seguito da un invio(\n), in oltre tutti i valori che non sono compresi tra 0 e 9 (quindi lettere e caratteri speciali) sono automaticamente scartati.

int leggiNumero(){
  char lettera;
  int risultato=0;
  int numeroCifra=0;
  do{
    lettera = Serial.read();
    if (lettera >='0' && lettera <= '9'){
      risultato = (10*numeroCifra) + lettera-'0';
      numeroCifra++;
    }
  }while (lettera!='\n');
  return risultato;
}

Il problema è che questa lettura è bloccante, ovvero se provi a leggere un numero quando non è arrivato, si ferma l'esecuzione bloccandosi nel while fichè non arriva qualcosa.
Puoi risolvere scrivendo il while così:
while (lettera!='\n' || (lettera==-1 && numeroCifra==0) );
che vuol dire: la lettere deve essere -1, che significa che non ci sono caratteri disponibili nel buffer della seriale, ed in oltre NON devi aver già letto una o più cifre, perchè in quel caso bisogna finire di leggere il numero prima di proseguire.

Miglioramenti attuabili:
gestione dell'errore, sia quando viene letta una lettera, sia quando viene letta una lettera ma si è già lette alcune cifre.
Rendere la funzione non bloccante anche quando si è letto parzialmente un numero.
Leggere numeri negativi.
leggere numeri con la virgola.

come hai fatto a calcolare quanti byte occupa una funzione? semplicemente includendo la sua libreria in uno sketch noto? oppure devi chiamare per forza la funzione, e quindi in realtà il calcolo si sballa un minimo?

Bisogna chiamare almeno una funzione per vedere cambiare la grandezza del file compilato, altrimenti il compilatore non linka niente.
Se la chiamata alla funzione ha pochi argomenti l'errore di lettura è di pochi byte(3 o 4).

usiamo il metodo "senza librerie esterne", visto che il compito non è così difficile. Usiamo il metodo di Federico leggertmente modificato...

Speravo in uno sforzo da parte di chi ha aperto il topic...
È argomento fondamentale, meglio evitare la solita "pappa pronta" XD
Ciao