[RISOLTO] Problema ricezione dati da cellulare via bluetooth (HC-06)

Salve,
mi sto cimentando in un progetto che include l’invio di dati (che nella pratica sarebbero “ordini” che la scheda legge e a cui fa corrispondere delle azioni su attuatori o qualsiasi cosa io voglia attaccare) al mio Arduino UNO tramite un modulo Bluetooth HC-06 (libreria: SoftwareSerial), collegato dunque al telefono con due app principalmente: “Bluetooth Eletronics” e “Blue Terminal”. Dal telefono invio 3 tipi di dati, ciascuno da 1 a 254 (impostati dall’applicazione), per regolare il colore di un LED RGB.
L’applicazione invia dati di questo tipo:
colore rosso: “R” + valore + “A”
verde: “G” + valore + “A”
blu: “B” + valore + “A”
Per poter estrarre il valore pensavo di usare la funzione " byte(byte che arriva dall’HC) ", ma quando stampa sulla seriale i valori che legge, ottengo solo quasi solo 255.
Sostanzialmente, vorrei capire come poter leggere questi valori per usarli poi in qualche modo (in questo caso con il rgb).
Grazie

#include <SoftwareSerial.h>
const int rxpin = 2;
const int txpin = 4;
SoftwareSerial bluetooth(rxpin, txpin);

const int rgbR = 6;
const int rgbB = 5;
const int rgbG = 3;
byte rgbRval = 0;
byte rgbBval = 0;
byte rgbGval = 0;

void setup() {
  Serial.begin(9600);
  bluetooth.begin(9600);
  Serial.println("Serial pronto");
  bluetooth.println("BT pronto!");
  pinMode(rgbR, OUTPUT);
  digitalWrite(rgbR, LOW);
  pinMode(rgbG, OUTPUT);
  digitalWrite(rgbG, LOW);
  pinMode(rgbB, OUTPUT);
  digitalWrite(rgbB, LOW);
}

void loop() {
  if(bluetooth.available()){
    char c = bluetooth.read();
    switch(c){
      case 'R':
        rgbRval=byte(bluetooth.read());
        analogWrite(rgbR, rgbRval);
        Serial.print("Il valore di rosso è: ");
        Serial.println(rgbRval);
        delay(5);
        break;
      case 'B':
        rgbBval=byte(bluetooth.read());
        analogWrite(rgbB, rgbBval);
        Serial.print("Il valore di blu è: ");
        Serial.println(rgbBval);
        delay(5);
        break;
      case 'G':
        rgbGval=byte(bluetooth.read());
        analogWrite(rgbG, rgbGval);
        Serial.print("Il valore di verde è: ");
        Serial.println(rgbGval);
        delay(5);
        break;
      default :
        bluetooth.println("Impostare nuovo valore!");
        analogWrite(rgbR, rgbRval);
        analogWrite(rgbB, rgbBval);
        analogWrite(rgbG, rgbGval);
        break;
    }
    Serial.write(c);
  }
  
if(Serial.available()){
    char c = Serial.read();
    bluetooth.write(c);
    }
}

Ok, i problemi sono stati risolti: adesso riesco a capire quanti byte mi manda ed a leggere il valore che mi interessa! Prima sbagliavo perché immaginavo il dato della stringa mandato come un “unico pacchetto” e non capivo come comportarmi, invece è una serie di byte che Arduino legge uno per volta, quindi ho risolto con una bella stringa e la funzione atoi() :smiley: Grazie a tutti per l’aiuto!
Questo è il codice finale:

#include <SoftwareSerial.h>;
const int rxpin = 2;
const int txpin = 4;
SoftwareSerial bt(rxpin, txpin);

char inizio='R';
char fine='A';
char RX;
const int maxStringa = 4;
char stringaValori[maxStringa+1];
int indice = 0;
int valore;

byte byte_contenuto;
boolean sono_cifre;

void setup (){
Serial.begin (9600);
bt.begin(9600);
}

void loop(){
while(bt.available()){
  RX=bt.read();
    if (RX==inizio){
      Lettura();
    }
}
Serial.print("I byte sono: ");
Serial.println(byte_contenuto);
Serial.print("Se sono cifre 1, se non lo sono 0: ");
Serial.println (sono_cifre);
Serial.print("Il valore letto è: ");
Serial.println(valore);
}

void Lettura (){
  byte_contenuto=0;
  sono_cifre=LOW;
  while(bt.available()){
    RX=bt.read();
      if(RX==fine){
         stringaValori[indice] = 0;
         valore = atoi(stringaValori);
         indice = 0;
         break;
       }
  byte_contenuto++;
  if(isDigit(RX) && indice < maxStringa){
    sono_cifre=HIGH;
    stringaValori[indice] = RX;
    indice = indice + 1;    
    }
  }
}

docsavage: C è un po di confusione, non capisco

L'applicazione la puoi modificare?

Perché trasmetti un terminatore ma non ne tieni conto?

Tu controlli available una volta sola, Ma fai due letture, cosa ti garantisce che il secondo byte è realmente già arrivato?

Hai pensato come fare se per caso resetti come valore un numero che per caso corrisponde al codice ascii di una lettera valida?

Dell'applicazione posso modificare la gamma di valori da inviare e le lettere di inizio e fine della stringa che invia quando rilascio il tocco.

Che significa che trasmetto un terminatore ma non ne tengo conto?

Io so che l'applicazione mi invia un qualcosa del tipo "R178A", che sta a significare un valore di 178 per il colore rosso ed A è la lettera di fine stringa, ma non so trattare questo dato.

docsavage:
Aspetta, non è la stessa cosa che hai detto prima

R178A significa
carattere ‘R’
carattere ‘1’ ovvero
carattere ‘7’ ben
carattere ‘8’ tre byte
carattere ‘A’

oppure
carattere ‘R’
numero 178 (ovvero un solo byte)
carattere ‘A’

da qui dipende tutto il resto

invece per non tenere conto del terminatore intendo che l’applicazione trasmette ‘A’, ma che lo trasmetta oppure no, nel programma non cambia nulla

In realtà l’applicazione mi dice solo che invia una stringa di valori fatta così “R (se il colore è il rosso) + valore + A”, senza specificare altro. Ho letto il topic che mi hai linkato e non so se ho capito bene, ma agirei in questo modo (ipotizzando che sia una stringa del tipo R + valore (es.:178, quindi tutto “intero”) + A):

if(arriva il carattere R){
leggo il valore che segue R con valore=char(bluetooth.read) e ne estrapolo il numero, che immagazzino in una variabile globale e lo uso sul led, non ci dovrebbe essere bisogno di map() o constrain(), in quanto l’app si autolimita diciamo; a questo punto, metto un altro if(), per quando arriva il carattere di fine stringa, cioè la lettera A e faccio stampare sulla seriale dell’applicazione e del pc i valori ricevuti
}
Faccio due funzioni praticamente uguali, una per il verde e una per il blu.

Dici che in questo modo può andare? Questo varrebbe ovviamente se è fatto " R + valore + A ".

Perdonami se rispondo a singhiozzo e grazie dell’aiuto importante che mi dai!

Hai ragione, se il valore é codificato in un solo byte allora va bene come dici tu, ma se fosse codificato in più byte il tuo metodo non funzionerebbe. Di conseguenza va saputo come é codificato, PRIMA di qualsiasi altra cosa. Ecco un programmino che (scritto su Seriale) potrebbe tornarci utile allo scopo. Non accendiamo nessuna luce qui.

char inizio='I';
char fine='F'!
chat RX;
byte byte_contenuto;
boolean sono_cifre;
void setup ()
{
Serial.begin (9600);
}
void loop()
{
while (Serial.available())
{
rx=Serial.read();
if (RX==inizio)
{
Lettura ();
}
}
Serial.print (byte_contenuto);
Serial.println (sono_cifre);
}
void Lettura ()
{
byte_contenuto=0;
sono_cifre=FALSE;
while (Serial.available())
{
RX=Serial.read();
if (RX==fine)
{
return;
}
byte contenuto++;
if (RX-'0'>-1 &&RX-'0'<10)
{
sono_cifre=TRUE;
}
}
}

Scritto al volo qui, non so se va o se fa quello che vorrei che faccia

giovepluvio:
Hai ragione, se il valore é codificato in un solo byte allora va bene come dici tu, ma se fosse codificato in più byte il tuo metodo non funzionerebbe. Di conseguenza va saputo come é codificato, PRIMA di qualsiasi altra cosa. Ecco un programmino che (scritto su Seriale) potrebbe tornarci utile allo scopo. Non accendiamo nessuna luce qui.

char inizio='I';

char fine=‘F’!
chat RX;
byte byte_contenuto;
boolean sono_cifre;
void setup ()
{
Serial.begin (9600);
}
void loop()
{
while (Serial.available())
{
rx=Serial.read();
if (RX==inizio)
{
Lettura ();
}
}
Serial.print (byte_contenuto);
Serial.println (sono_cifre);
}
void Lettura ()
{
byte_contenuto=0;
sono_cifre=FALSE;
while (Serial.available())
{
RX=Serial.read();
if (RX==fine)
{
return;
}
byte contenuto++;
if (RX-‘0’>-1 &&RX-‘0’<10)
{
sono_cifre=TRUE;
}
}
}



Scritto al volo qui, non so se va o se fa quello che vorrei che faccia

Ma questo sketch dovrei però testarlo sulla comunicazione col modulo bluetooth, cioè sulla comunicazione dal telefono, no? Intendo di usare la SoftwareSerial e quindi fare queste cose, ma con i dati che manda il telefono ed usando le lettere R per l’inizio ed A per la fine, perché è quella stringa particolare che devo capire, quindi non vale la pena mettermi subito su quella?
Poi, scusa eh ma è giusto per essere sicuro, gli “rx” sarebbero tutti maiuscoli, giusto?

Si, va testato sul bluetooth, io lo ho scritto sulla seriale perche non so usarlo il bluetooth. Solo se ultime righe Vanni tenute su seriale, perché sono le informazioni che devi avere tu.
Non mi ricordavo, poi, le lettere, quindi ho un po inventato, ma va testato su quello che dici tu.
Poi, per semplificare un po l’ultimo if() della lettura può diventare

if (isdigit (RX))
{
}
else 
{
sono_cifre=FALSE;
}

E poi si, RX dovrebbero essere tutte minuscole (essendo variabili il codice dice così, non che ci sia problema). A questo telefono rx scritto minuscolo non piace, e dopo una certa ora non sono stato abbastanza attento a cambiarle tutte

giovepluvio: Si, va testato sul bluetooth, io lo ho scritto sulla seriale perche non so usarlo il bluetooth. Solo se ultime righe Vanni tenute su seriale, perché sono le informazioni che devi avere tu. Non mi ricordavo, poi, le lettere, quindi ho un po inventato, ma va testato su quello che dici tu. Poi, per semplificare un po l'ultimo if() della lettura può diventare

if (isdigit (RX))
{
}
else 
{
sono_cifre=FALSE;
}

E poi si, RX dovrebbero essere tutte minuscole (essendo variabili il codice dice così, non che ci sia problema). A questo telefono rx scritto minuscolo non piace, e dopo una certa ora non sono stato abbastanza attento a cambiarle tutte

Perfetto, stasera quando torerò da lezione testerò il tutto e vi farò sapere!

giovepluvio:
Hai ragione, se il valore é codificato in un solo byte allora va bene come dici tu, ma se fosse codificato in più byte il tuo metodo non funzionerebbe. Di conseguenza va saputo come é codificato, PRIMA di qualsiasi altra cosa. Ecco un programmino che (scritto su Seriale) potrebbe tornarci utile allo scopo. Non accendiamo nessuna luce qui.

char inizio='I';

char fine=‘F’!
chat RX;
byte byte_contenuto;
boolean sono_cifre;
void setup ()
{
Serial.begin (9600);
}
void loop()
{
while (Serial.available())
{
rx=Serial.read();
if (RX==inizio)
{
Lettura ();
}
}
Serial.print (byte_contenuto);
Serial.println (sono_cifre);
}
void Lettura ()
{
byte_contenuto=0;
sono_cifre=FALSE;
while (Serial.available())
{
RX=Serial.read();
if (RX==fine)
{
return;
}
byte contenuto++;
if (RX-‘0’>-1 &&RX-‘0’<10)
{
sono_cifre=TRUE;
}
}
}



Scritto al volo qui, non so se va o se fa quello che vorrei che faccia

Ho testato il programma che mi hai consigliato, corretto così (nota che arduino non prendeva TRUE e FALSE):

#include <SoftwareSerial.h>;
const int rxpin = 2;
const int txpin = 4;
SoftwareSerial bt(rxpin, txpin);

char inizio='R';
char fine='A';
char RX;

byte byte_contenuto;
boolean sono_cifre;

void setup (){
Serial.begin (9600);
bt.begin(9600);
}

void loop(){
while (bt.available()){
  RX=bt.read();
    if (RX==inizio){
      Lettura();
    }
}
Serial.print("I byte sono: ");
Serial.println(byte_contenuto);
Serial.print("Se sono cifre 1, se non lo sono 0: ");
Serial.println (sono_cifre);
}

void Lettura (){
  byte_contenuto=0;
  sono_cifre=LOW;
  while (bt.available()){
    RX=bt.read();
      if(RX==fine){
         break;
       }
  byte_contenuto++;
  if (isDigit(RX)){
    sono_cifre=HIGH;
    }
  }
}

Dalla seriale vedo che a numeri di 1 cifra corrisponde 1 byte, di 2 cifre 2 byte e 3 cifre 3 byte (sebbene ci siano state volte in cui ha un po’ scazzato, cioè vedeva i numeri a 3 cifre con 2 byte o viceversa, per esempio).
A questo punto so che l’applicazione manda dati del tipo:" R + 1 + 7 + 8 + A "; questo significa che poter usare quel 178 devo immagazzinarlo in una stringa? Però poi come faccio ad estrapolare un numero al suo interno?

Edit: ho messo “break” dove prima c’era return ed ho sostituito anche " RX-‘0’>-1 && RX-‘0’<10 " con " isDigit(RX) "

David_Inginiar: ... nota che arduino non prendeva TRUE e FALSE ...

... bastava dare un occhiata al reference di Arduino per vedere che ... vanno scritti in [u]minuscolo[/u]: true e false :smiling_imp:

Il 'C' è case-sensitive quindi, per qualsiasi cosa, anche una sola maiuscola o una sola minuscola, cambia tutto !

Guglielmo

P.S.: Ah, nel reference c'è anche una nota in merito :

Note that the true and false constants are typed in lowercase unlike HIGH, LOW, INPUT, and OUTPUT.

gpb01: ... bastava dare un occhiata al reference di Arduino per vedere che ... vanno scritti in [u]minuscolo[/u]: true e false :smiling_imp:

Quanto a "vedeva numeri di 3 cifre con 2 byte" POTREBBE essere che le cifre siano in base 16, parlando di luci colorate nulla di più facile. Sono_cifre era sempre vera? Nel caso allora non preoccuparti, ma metti in conto errori di lettura. Se fosse stata falsa farei una prova con 15 (in base 16 mi aspetto 1 byte non cifra). Fai sapere, la base é importante per trovare i numeri

giovepluvio: Quanto a "vedeva numeri di 3 cifre con 2 byte" POTREBBE essere che le cifre siano in base 16, parlando di luci colorate nulla di più facile. Sono_cifre era sempre vera? Nel caso allora non preoccuparti, ma metti in conto errori di lettura. Se fosse stata falsa farei una prova con 15 (in base 16 mi aspetto 1 byte non cifra). Fai sapere, la base é importante per trovare i numeri

sono_cifre era sempre vera, sì, quindi ci può stare, comunque succede sempre più di rado.

gpb01: ... bastava dare un occhiata al reference di Arduino per vedere che ... vanno scritti in [u]minuscolo[/u]: true e false :smiling_imp:

Il 'C' è case-sensitive quindi, per qualsiasi cosa, anche una sola maiuscola o una sola minuscola, cambia tutto !

Guglielmo

Accidenti è vero eheheh, scusate la mia inesperiemza che mi fa fare questi errori :D poi se ci penso ora, tante volte ho usato true e false, solo che ieri sera proprio non ci ripensavo.

docsavage: Quindi sei esattamente nella situazione che discutevamo nei link che ti ho messo

vedrai che ti saranno d'ispirazione

Esatto, grazie ancora!