Inviare e ricevere testo tramite bluetooth

Ciao ragazzi :slight_smile: Ho un problema con Arduino e seedstudio bluetooth shield. Ho creato un app tramite AppInventor che deve inviare dei comandi ad arduino. Esso li deve eseguire e poi reinvia al bluetooth una risposta. Con appinventor ho vari modi per inviare dei comandi: Send1ByteNumber, Send2ByteNumber, Send4ByteNumber, SendBytes e SendText..
E posso ricevere dei dati tramite questi comandi: ReceiveSigned1ByteNumber, ReceiveSigned2ByteNumber, ReceiveSigned4ByteNumber, ReceiveSignedBytes, ReceiveText, ReceiveUnsigned1ByteNumber, ReceiveUnsigned2ByteNumber, ReceiveUnsigned4ByteNumber..

Questo è il mio codice di arduino:

void loop(){
  char recvChar;
  if(blueToothSerial.available()){
    recvChar = blueToothSerial.read();
    Serial.print(recvChar);
  }
  if(Serial.available()){
    recvChar  = Serial.read();
    blueToothSerial.print(recvChar);
  }
}

In questo modo controllo se ci sono scambi di dati..
I comandi che vorrei inviare tramite l'app sono dei semplici testi (non numeri): curva_dx, curva_sx, avanti, indietro.
I comandi che ricevo tramite bluetooth invece sono sia testo che numeri: motore_in_movimento, motore_fermo, 36.4, 23.2
Come posso fare? Con char non posso confrontare un testo.
Esempio:

if(blueToothSerial.available()){
    recvChar = blueToothSerial.read();
    Serial.print(recvChar);
    if (recvChar == "curva_dx"){
         //Curva a destra
    }
  }

Qualche idea per non complicarmi la vita?

utentespastico:
Qualche idea per non complicarmi la vita?

SI, che ti studi la classe Serial (che è la stessa applicata alla SoftwareSerial) ... ]:smiley:

L'avremo detto non so più quante volte che la Serial.read() legge UN solo carattere e non una stringa ...

...
recvChar = blueToothSerial.read();
if (recvChar == "curva_dx") {
...

... come pensi di ricevere un testo con una singola lettura di un carattere ??? :roll_eyes:

Guglielmo

P.S. : E comunque in C non si può fare l'IF che vorresti fare tu ... esistono delle funzioni in <string.h> per farli ...

Innanzitutto grazie per la risposta. Ho letto i link che mi hai fornito :wink:
Ho trovato due soluzioni per inviare comandi da bluetooth ad arduino:

  1. Utilizzo Send1ByteNumber e ogni numero faccio corrispondere un'azione. Esempio:
byte comando = blueToothSerial.read();
switch(comando){
     case 1:
            //Curva a destra
     break;
     case 2:
            //Curva a sinistra
      break;
//ecc..
}
  1. Tramite questo ciclo unisco i vari caratteri e leggo l'intera stringa..
String readString;
void loop() 
{
  while (blueToothSerial.available()) 
  {
    delay(10);
    char c = blueToothSerial.read();
  readString += c; 
  }
 
  if (readString == "prova") 
  {
    if(digitalRead(13) == LOW)
    {
      digitalWrite(13, HIGH);
      delay(100);
      Serial.println(1);
    }
    else if(digitalRead(13) == HIGH)
    {
      digitalWrite(13, LOW);
      delay(100);
      Serial.println(0);
    }
  readString="";
  }
}

Voi avete altre soluzioni? Qual è la migliore delle due? E per inviare i dati da arduino al bluetooth come posso fare?

Ho cercato altre soluzioni ma senza riuscirci =( Inoltre la soluzione 1 ha un problema. Quando il cellulare si collega al modulo del bluetooth, esso invia sulla seriale del bluetooth (blueToothSerial) lo stato del modulo (ad esempio se si è connesso, se si è disconnesso ecc..) quindi può capitare che questi byte possano interagire con lo switch(comando) e di conseguenza causare un problema.

Se proprio vuoi/devi usare la classe String (che, ti preannuncio, a seconda di come la usi, ti potrà dare problemi ed errori difficilmente diagnosticabili ... per esaurimento della SRAM), prova anche a guardare le altre funzioni della classe Serial ...

... tipo la readBytes() o la readBytesUntil(). Io le sconsiglio sempre, sono altamente diseducative e non ti insegnano nulla su come si gestisce una comunicazione seriale, però ... se vuoi la "pappa fatta" ... con i loro limiti, quelle dovrebbero andarti bene :~

Guglielmo

La classe String la userei come da esempio, ovvero leggere tutti i caratteri nella seriale finchè non trovo il nome di un comando. A quel punto eseguo il comando e resetto la stringa. Avrei problemi con la SRAM?
In un altro posto ho notato che utilizzi pure tu l'HC-05: tu che metodo utilizzi per inviare e ricevedere dei dati/informazioni?

utentespastico:
La classe String la userei come da esempio, ovvero leggere tutti i caratteri nella seriale finchè non trovo il nome di un comando. A quel punto eseguo il comando e resetto la stringa. Avrei problemi con la SRAM?

Di sicuro ... ]:smiley:

Purtroppo sei su una MCU e non c'è un sistema operativo che fa "garbage-collection" ... quindi ...
... ogni volta che cambi la lunghezza della stringa viene fatto un dealloc() e un realloc() ... creando facilmente buchi nella memoria sino all'esaurimento !

utentespastico:
In un altro posto ho notato che utilizzi pure tu l'HC-05: tu che metodo utilizzi per inviare e ricevedere dei dati/informazioni?

Lavoro con le stringhe di tipo "char array" (null terminated) e le funzioni di string.h ...
... come già ti ho detto ... :roll_eyes:

Guglielmo

gpb01:
Purtroppo sei su una MCU e non c'è un sistema operativo che fa "garbage-collection" ... quindi ...
... ogni volta che cambi la lunghezza della stringa viene fatto un dealloc() e un realloc() ... creando facilmente buchi nella memoria sino all'esaurimento !

L'ATmega328 ha 2kb di SRAM. Penso che sia sufficiente per eseguire almeno 30 volte il comando.. :smiley: Oppure potrei spedire un singolo byte cercando di inviare byte che non possano interferire con l'invio di informazioni da parte del modulo BT e poi leggerlo tranquillamente..

gpb01:
Lavoro con le stringhe di tipo "char array" (null terminated) e le funzioni di string.h ...
... come già ti ho detto ... :roll_eyes:

Guglielmo

Potresti postare un banalissimo esempio?

utentespastico:
L'ATmega328 ha 2kb di SRAM. Penso che sia sufficiente per eseguire almeno 30 volte il comando...

Non è detto ...
... un sistema per limitare i danni è inizialmente allocare subito il massimo spazio occorrente (... anche con una stringa piena di spazi), così, se la ridimensioni, no deve allocarne altro.

utentespastico:
Potresti postare un banalissimo esempio?

Guada, ne avrò postati sul forum un'infinità ... se fai una ricerca trovi vari esempi ... anche perché dipende cosa devi esattamente leggere.

Un conto è, ad esempio, leggere un numero fisso di caratteri, un altro è leggere caratteri sino all'arrivo di un certo carattere (... tipicamente il CR), un altro è tenere conto di eventuali timeout ... insomma la casistica è varia, anche se alla fine è sempre un WHILE che gira finché non si verifica una delle suddette condizioni ... :roll_eyes:

Piuttosto ... ti sei letto le varie pagine di QUESTO thread dedicato proprio all'uso dei moduli BT ?

Guglielmo

Esempio banalissimo e ... senza controllo dell'overflow (... che DEVE invece essere implementato) e senza il controllo di tante altre cose ... :roll_eyes:

Mi aspetto al massimo 10 caratteri terminati da CR (0x0D) :

char inpBuffer[11];
char inpChar;
byte idxBuffer;
...
...
idxBuffer = 0;
while ( Serial.available() ) {
  inpChar = Serial.read();
  if (inpChar == 0x0D) break;
  inpBuffer[idxBuffer] = inpChar;
  idxBuffer++;
  inpBuffer[idxBuffer] = 0x00
  delay(1);
}

Nota che il buffer dove metti i caratteri deve essere un carattere più lungo per permettere l'inserimento dell'indicatore di fine stringa (0x00) !

Ripeto ... questo è solo un punto di partenza ... da estendere ... :wink:

Guglielmo

Grazie per il codice anche se avevo trovato questo:

char inData[20]; // Allocate some space for the string
char inChar=-1; // Where to store the character read
byte index = 0; // Index into array; where to store the character

void setup(){
  Serial.begin(9600);
  Serial.println("Power On");
}

char Comp(char* This){
  while(Serial.available() > 0) // Don't read unless
    // there you know there is data
  {
    if(index < 19) // One less than the size of the array
    {
      inChar = Serial.read(); // Read a character
      inData[index] = inChar; // Store it
      index++; // Increment where to write next
      inData[index] = '\0'; // Null terminate the string
    }
  }

  if(strcmp(inData,This)  == 0){
    for(int i=0;i<19;i++){
      inData[i]=0;
    }
    index=0;
    return(0);
  }
  else{
    return(1);
  }
}


void loop()
{
  if(Comp("m1 on")==0){
    Serial.write("Motor 1 -> Online\n");
  }
  if(Comp("m1 off")==0){
    Serial.write("Motor 1 -> Offline\n");
  }
}

Il problema è che se leggo una scritta diversa, non riesco più a leggere nessuna stringa. Devo mettere un controllo: ad esempio cercando un carattere prima e dopo la stringa (#m1 on!)..
Come faccio ad evitare che il modulo bluetooth scriva di default sulla seriale bluetooth alcune sue informazioni quali il suo stato, se è connesso, se è disconnesso, ecc..?

... con un HC-05 sarebbe banale, con il tuo ... non so ... :roll_eyes:

SE è QUESTO, allora ti devi studiare quello che dicono QUI ed i comandi QUI e ... vedere se puoi programmarlo in modo da evitare quanto dici :wink:

Guglielmo

Questo è il codice che utilizzo per configurarlo:

#include <SoftwareSerial.h>
#define RxD 6
#define TxD 7

SoftwareSerial blueToothSerial(RxD,TxD);

void setup(){
  Serial.begin(9600);
    pinMode(RxD, INPUT);
    pinMode(TxD, OUTPUT);
    setupBlueToothConnection();
}

void setupBlueToothConnection(){
  blueToothSerial.begin(38400); //Set BluetoothBee BaudRate to default baud rate 38400
  blueToothSerial.print("\r\n+STWMOD=0\r\n"); //set the bluetooth work in slave mode
  blueToothSerial.print("\r\n+STNA=SeeedBTSlave\r\n"); //set the bluetooth name as "SeeedBTSlave"
  blueToothSerial.print("\r\n+STOAUT=1\r\n"); // Permit Paired device to connect me
  blueToothSerial.print("\r\n+STAUTO=0\r\n"); // Auto-connection should be forbidden here
  delay(2000); // This delay is required.
  blueToothSerial.print("\r\n+INQ=1\r\n"); //make the slave bluetooth inquirable
  Serial.println("The slave bluetooth is inquirable!");
  delay(2000); // This delay is required.
  blueToothSerial.flush();
}

... mi spiace ma non conosco quel modulo e non posso certo mettermi a studiare il set di comandi per vedere cosa si può e non si può fare ... :~

Bisogna che, come ti ho già detto, ti studi tutti i comandi AT e vedi se c'è quello che fa per te !

Guglielmo

Non c'è nessun comando purtroppo =(
Dal sito:

  1. Return status \r\n+BTSTA:xx\r\n
    xx status:

0 - Initializing
1 - Ready
2 - Inquiring
3 - Connecting
4 - Connected

(Note: This is not a command, but the information returned from the module after every command)

... allora ho idea che dovrai filtrare queste risposte da software e, se non ti occorrono, scartarle... :roll_eyes:

Guglielmo

Per curiosità: tu che comando utilizzi?
A cosa serve il comando AT "Close echo"/"open echo"?

Gli HC-05 non rompono le scatole con tutte quelle indicazioni (salvo se non sei MASTER), se vuoi vai a chiedergliele, ma normalmente ti passano quello che ricevono e trasmettono quello che gli mandi XD XD XD

Guglielmo

Per quale motivo se invio un carattere (o anche una stringa) il modulo bluetooth si avvia correttamente e diventa rilevabile ma subito dopo non funziona più?

#include <SoftwareSerial.h>
#define RxD 6
#define TxD 7

SoftwareSerial blueToothSerial(RxD,TxD);

void setup(){
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  pinMode(RxD, INPUT);
  pinMode(TxD, OUTPUT);
  blueToothSetup();
}

void blueToothSetup(){
  blueToothSerial.begin(38400);
  blueToothSerial.print("\r\n+STWMOD=0\r\n"); 
  blueToothSerial.print("\r\n+STNA=SmartHome\r\n");
  blueToothSerial.print("\r\n+STOAUT=1\r\n");
  blueToothSerial.print("\r\n+STAUTO=0\r\n");
  delay(2000);
  blueToothSerial.print("\r\n+INQ=1\r\n");
  Serial.println("Dispositivo BlueTooth rilevabile!");
  delay(2000);
  blueToothSerial.flush();
}

void loop(){
  blueToothSerial.write("A");
}

Il problema si presenta anche cambiando

blueToothSerial.write("A");

in

blueToothSerial.print("A");