Interpretare un codice inviato da smartphone via Bluetooth

Ciao.
Tramite Bluetooth il mio Arduino riceve dei codici alfanumerici a 3 caratteri. Il primo carattere è sempre una lettera, mentre gli altri due caratteri servono per rappresentare i decimali da 1 a 99.

Esempio:
A1
Z12
D99

da allocare in una stringa del tipo char datoinricezione[4] (3 caratteri piu’ carattere di terminazione)

Tramite questi codici Arduino deve fare delle operazioni.
La lettera mi serve per discriminazione il tipo di azione che chiedo da cellulare col bluetooth (A: accendi led, B: accendi motore etcc) mentre il numero indica “l’intensità” di quell’azione (99: intensità al 99%).

Esempio:
A1: accendi led per 1 secondo
Z12: accendi motore al 12% della potenza
D37: fai un delay di 37 secondi

  1. Potete dirmi se sto impostando correttamente il codice?
  2. Inoltre, come faccio ad estrarre i due decimali dalla stringa, per assegnare una variabile alla cifra, per poterci lavorare? Esempio, da “D37” voglio ricavarmi una variabile int n = 37 per farci un delay da 37 secondi.
  3. utilizzo un Attiny85V a 1mhz. Il programma è abbastanza leggero. Può comunque dare problemi lavorare con le stringhe?

Segue porzione di codice attuale con commenti:

#include <SoftwareSerial.h>
SoftwareSerial ble_device(0, 1); // RX\TX
char datoinricezione[4]; // initialize string to contain receiving data from smartphone bluetooth

void setup() {
  ble_device.begin(9600); // start BLE device
  ble_device.println("AT+NAMEATtiny85_BLE"); // change device name
  delay(500); // wait for change
  ble_device.println("AT+RESET"); // reset module to save name change
  delay(1000); // wait for reset
}

void loop() {
  if (Serial.available()) { //[b]entra nell'if quando invio dati da seriale del cellulare[/b]
    datoinricezione = Serial.read(); // legge il dato 
    switch (datoinricezione[1]) {// legge il primo carattere 
      
case A: //accendi luce 
      // qui vorrei dire al programma di leggere gli altri due caratteri per far accendere la luce per tot secondi
      break;

      case Z: //accendi motore
      // qui vorrei dire al programma di leggere gli altri due caratteri per far accendere il motore all'xx% di potenza
      break;

      case D: //effettua un delay
      //qui vorrei dire al programma di leggere gli altri due caratteri per fare una pausa di tot secondi
      break;
     
      default:
        // statements
       break;
    }

Ma la trasmissione è già definita come hai scritto ? o è modificabile secondo nostri consigli ?

In linea generale la ricezione è errata, la Serial.read() legge 1 solo dei caratteri inviati, non tutta la stringa.
Devi avere un contatore che dice quanti ne hai ricevuti e quindi dove lo vai a posizionare nell'array
Gli array in C iniziano da 0 e non da 1

nid69ita:
Ma la trasmissione è già definita come hai scritto ? o è modificabile secondo nostri consigli ?

In linea generale la ricezione è errata, la Serial.read() legge 1 solo dei caratteri inviati, non tutta la stringa.
Devi avere un contatore che dice quanti ne hai ricevuti e quindi dove lo vai a posizionare nell'array
Gli array in C iniziano da 0 e non da 1

Modificabilissima.
Considera che nella app bluetooth android ho degli slider, che posso smuovere da 0 a N (n= numero intero a scelta). Se ad esempio rilascio lo slider a, che ne so, 50, l'app invia 50 al bluetooth. Così come è.

Posso poi impostare nella app l'aggiunta automatica di un prefisso e un suffisso e dirgli quindi di inviare ad Arduino"A50C".

Sono tutto orecchie.

l'alterinativa a cui pensavo era di usare una mia codifica interna con soli numeri interi e a 3 cifre.
La prima cifra, mi serve per indicare il tipo di azione: accendere una luce, fare una pausa, accendere un motore.
Le altre due cifre l'intensità dell'azione.
Mettiamo che nella app android ho 3 slider che vanno da 0 a 99 e decido che il primo slider, per la luce, invia come prefisso 1, il secondo slider, per indicare una pausa, invia come prefisso 2, il terzo slider per pilotare un motore, invia come prefisso 3.

esempio
134: accendi led al 34%
21: fai una pausa di un secondo
399: accendi mnotore al 50%

Quindi il codice sarebbe.. (scrivo spicciolo):

if (Serial.available()) { //
int datoinricezione = Serial.read(); // legge il dato numero, esempio 134
int datoinricezione_primacifra = datoinricezione \100 //dividendo per 100 ottengo i centesimi e dichiarando la nuova variabile tronco i decimali, nel nostro esempio otterremmo quindi 134... 1,34.... 1
int datoinricezione_secondaterzacifra = datoinricezione %100 //ottengo e memorizzo il resto della divisione, esempio 134...1,34... 34

switch (datoinricezione_primacifra) {
case 1: //accendi luce
// digitalWrite (pin, datoinricezione_secondaterzacifra)

case 2: //fai un delay
// delay(datoinricezione_secondaterzacifra)

etc..
}

Così leggeresti solo valori da 0 a 255 (singoli byte ricevuti con Serial.read)

Guarda, per i protocollo avere una cifra o lettera x il comando non ti cambia nulla.
Semplifica molto invece avere un prefisso, un suffisso
E sarebbe anche utile avere una lunghezza fissa. ovvero se devi inviare comando e poi valore 1 invii A01 invece di A1

All'arrivo del prefisso sai che ti arriveranno altri 4 char (comando, valore 00-99) e suffisso
Leggerai quindi comando e valore e al suffisso analizzi quello che è arrivato.

Convertire 2 cifre in numero da 2 char è banale, atoi() oppure primo char*10+secondo char (tieni conto che '0'=48 quindi togli 48)

Per la lettura fai lettura 1 char alla volta, usando Serial.read() oppure usando la Serial.readStringUntil() e leggi in attesa del suffisso. Inoltre il comando ha un timeout

Concordo con tutto quello che dice nid69ita. Io userei comunque almeno un suffisso/terminatore (magari direttamente i classici \r\n) perché se lavori su lunghezza fissa ossia "pacchetti" sempre da 3 byte, non hai la certezza della sincronizzazione.
Personalmente ho sempre progettato ed implementato i miei protocollini (perché questi sono in pratica dei piccolissimi protocolli) con un prefisso ed un suffisso, entrambi composti da un carattere mai compreso nel messaggio/payload.
Per capirci, una cosa del tipo:

#A1\r\n

Inizio a leggere appena ricevo il primo '#', da questo leggo ed accumulo nel mio buffer tutti i caratteri ricevuti, fino a ricevere '\n' (ed ignorando l'eventuale '\r') al che elaboro il pacchetto ricevuto.

Certamente se implementi pacchetti di lunghezza fissa potresti anche evitare il suffisso ossia il terminatore:

#A01

in tal caso inizio a leggere appena ricevo il primo '#', da questo leggo ed accumulo nel mio buffer solamente i successivi 3 caratteri, ed interpreto ed eseguo il comando appena ho i 3 caratteri.

Ma dato che amo lasciare la maggiore flessibilità possibile per i protocolli per eventuali future estensioni, preferisco sempre usare anche il terminatore. Se poi il mittente è un programma, si possono evitare i caratteri ed usare direttamente valori come semplici byte, risparmiando non solo caratteri di trasmissione ma soprattutto conversioni tra stringa e valore numerico.

PS: dimenticavo, il codice che hai postato oltre a non essere completo (mancano un paio di graffe) è anche indentato in modo poco coerente: prima di postare il prossimo, premi Ctrl-T nell'IDE e fattelo indentare correttamente, che è più facile da leggere sia per te sia per noi.. :wink: Inoltre all'interno del tag "code" non puoi formattare nulla, ossi non serve provare a mettere "b" per il grassetto, non funziona :smiley:

nid69ita:
Semplifica molto invece avere un prefisso, un suffisso

Si, posso inserire un prefisso e anche un suffisso. Qual'è lo scopo del prefisso e del suffisso? Il prefisso dice al bluetooth che il pacchetto che trova è "per lui" e quindi deve iniziare a "leggere", mentre il suffisso gli dice quando deve smettere di leggere?

nid69ita:
E sarebbe anche utile avere una lunghezza fissa.

Ok.
1.E' indispensabile? Quali sono le opzioni?
2.E se adotto il suffisso?
In mente mi viene: anzichè impostare su android uno slider che va da 0 a 50, lo setto da 10 a 60. Poi trasformo il dato grezzo dentro arduino semplicemente sottraendo 10.
Che ne pensi?
Ovviamente il giochetto vale finchè sto nelle due cifre, poichè uno slider settato, ad esempio, a 0-99 diventerebbe 10-110. Al momento un range a tre cifre non mi necessita quindi no problema ma preferirei la soluzione più adatta per sviluppi futuri.

nid69ita:
Convertire 2 cifre in numero da 2 char è banale, atoi() oppure primo char*10+secondo char (tieni conto che '0'=48 quindi togli 48)

vorrei provare atoi(), ma l'ho provato e se nella stringa di tipo char gli do in pasto esempio "A17" da terminale, atoi mi restituisce 0 come numero. Ho capito che è perchè atoi vuole l'ascii. Arduino riceverà dal bluetooth i caratteri in formato ascii?

nid69ita:
Per la lettura fai lettura 1 char alla volta, usando Serial.read() oppure usando la Serial.readStringUntil() e leggi in attesa del suffisso. Inoltre il comando ha un timeout.

Userò la prima tecnica penso, con un ciclo for.

docdoc:
Concordo con tutto quello che dice nid69ita. Io userei comunque almeno un suffisso/terminatore (magari direttamente i classici \r\n) perché se lavori su lunghezza fissa ossia "pacchetti" sempre da 3 byte, non hai la certezza della sincronizzazione.

metto quindi un ciclo do..while che legge tutti i caratteri ed esce quando rileva il terminatore?

docdoc:
Personalmente ho sempre progettato ed implementato i miei protocollini con un prefisso ed un suffisso,
Per capirci, una cosa del tipo:

#A1\r\n

Inizio a leggere appena ricevo il primo '#', da questo leggo ed accumulo nel mio buffer tutti i caratteri ricevuti, fino a ricevere '\n' (ed ignorando l'eventuale '\r') al che elaboro il pacchetto ricevuto.

Dato che amo lasciare la maggiore flessibilità possibile per i protocolli per eventuali future estensioni, preferisco sempre usare anche il terminatore. Se poi il mittente è un programma, si possono evitare i caratteri ed usare direttamente valori come semplici byte, risparmiando non solo caratteri di trasmissione ma soprattutto conversioni tra stringa e valore numerico.

Non ho capito quest'ultima parte. Intanto confermo che dal programma Android posso scegliermi i prefissi e i suffissi.
Mi stai suggerendo di creare un protocollo senza lettere, del tipo:
#133\n, dove stabilisco che 1 significa accendere la luce.
#250\n, dove stabilisco che 1 significa accendere un motorino.
#307\n, dove stabilisco che 3 significa suonare il clacson.

Grazie mille in anticipo.

squizzy91:
vorrei provare atoi(), ma l'ho provato e se nella stringa di tipo char gli do in pasto esempio "A17" da terminale, atoi mi restituisce 0 come numero. Ho capito che è perchè atoi vuole l'ascii. Arduino riceverà dal bluetooth i caratteri in formato ascii?

atoi() vuole un puntatore ad array di char, il nome dell'array per il C è già un puntatore
se l'array di chiama pippo già lui è un puntatore quindi se passi ad atoi(pippo+1) salti il primo carattere e gli passi solo il numero

squizzy91:
metto quindi un ciclo do…while che legge tutti i caratteri ed esce quando rileva il terminatore?

No, evita i do…while che ti bloccano il flusso. Nel loop() (che è già di per sé un while) metti che se hai Serial.available leggi il carattere nel buffer con Serial.read e se questo è il terminatore elabori il pacchetto, se è ‘\r’ lo ignori, tutti gli altri caratteri li accumuli in un buffer.

Una cosa del genere (estratto da un mio programma e ritoccato per te, ovviamente prendilo con le molle comunque, devi provarlo):

...
#define MAXBUF 40
char inputBuf[MAXBUF];
byte pBuf = 0;
...
void loop() 
{
  inputCheck();
...

void inputCheck() {
  char c = 0;
  if ( mySer.available() )
    c = mySer.read();
  if ( c > 0 ) {
    if ( c == '\n' || pBuf == MAXBUF) {
      // Fine comando
      if ( pBuf > 0 )
        execCommand();
      pBuf = 0;
    }
    else if ( c != '\r' && pBuf < MAXBUF-1 ) {
      inputBuf[pBuf++] = c;
      inputBuf[pBuf] = 0;
    }
  }
}
...
void execCommand() }
  // Qui leggo in "inputBuf" i caratteri ricevuti e faccio quello che serve...
  // Ad esempio prima verifico il prefisso
  if ( inputBuf[0] != '#' ) {
    // Pacchetto ignorato
    Serial.println("Pacchetto ignorato");
    return;
  }
  // Interpreto il comando ed estraggo il parametro
  char cmd = inputBuf[1];
  char args[MAXBUF - 1];
  strcpy(args, inputBuf + 2);
  switch (cmd) {
    // ------------------------------
    case 'V':
      // Eseguo...
      break;
...
  }
}
...

Mi stai suggerendo di creare un protocollo senza lettere, del tipo:

No, puoi usare tutti i caratteri che vuoi, usare solo i numeri ti limiterebbe a 10 comandi, e come ho detto non mi piace progettare qualcosa di limitato. Quindi puoi anche usare il tuo protocollo esistente.

Qual’è lo scopo del prefisso e del suffisso?

Se usi prefisso (che serve per essere certi della sincronizzazione) e suffisso (per avere parametri di lunghezza a piacere, a seconda del comando) non devi fare nulla di più di quello che ti ho scritto.

(lunghezza fissa) E’ indispensabile? Quali sono le opzioni?

Non è affatto indispensabile, perché come detto dipende da cosa vuoi farci col tuo protocollo. Impostare una lunghezza fissa significa dover sempre specificare “qualcosa” e della lunghezza stabilita: se hai (ora o in futuro) un comando che non richiede parametri devi comunque “riempire” il pacchetto con qualcosa di inutile, se il comando richiede un parametro di lunghezza inferiore come un valore di 2 cifre contro le 3 del protocollo devi fare un “padding” aggiungendo uno zero o uno spazio a sinistra o a destra, e, infine, se una volta dovessi voler avere un parametro di più caratteri semplicemente non potresti (a meno di non complicar ela routine di lettura del pacchetto).

Insomma, per me assolutamente non ti conviene. Quando crei un protocollo rendilo sempre più flessibile possibile.

anzichè impostare su android uno slider che va da 0 a 50, lo setto da 10 a 60. Poi trasformo il dato grezzo dentro arduino semplicemente sottraendo 10.Che ne pensi?

Non vedo perché tu debba fare una cosa del genere, comunque si può fare, tanto quando entri in quel comando specifico “sai” che devi sottrarre 10. Ma, ripeto: a che serve?..

Ovviamente il giochetto vale finchè sto nelle due cifre, poichè uno slider settato, ad esempio, a 0-99 diventerebbe 10-110. Al momento un range a tre cifre non mi necessita quindi no problema ma preferirei la soluzione più adatta per sviluppi futuri.

Appunto per questo ti consiglio di usare il terminatore, con una routine come quella che ti ho postato. Tra l’altro come parametro avresti una stringa, quindi teoricamente potresti passare anche più valori allo stesso comando adottando un altro separatore (una virgola ad esempio), diciamo ad esempio un comando che imposta un range, ossia i limiti minimo e massimo per un parametro:

#R50,140\r\n

Con la mia routine puoi fare tutto questo, con un pacchetto a lunghezza fissa no, o almeno non così semplicemente…

EDIT: corretta una “if” nel codice, invece di:

  • else if ( c != ‘\r’ && pBuf < MAXBUF ) {*
    doveva essere:
    _ else if ( c != ‘\r’ && pBuf < MAXBUF**-1** ) {_

Grazie a nid69ita per avermelo fatto notare :wink:

docdoc:
Insomma, per me assolutamente non ti conviene. Quando crei un protocollo rendilo sempre più flessibile possibile

A proposito di flessibile, recentemente me gusta mucho questo (sopra la stringa da trasmettere, sotto la trasmissione):

trasmetti.png

Lunghezza dati a piacere, si possono trasmettere byte qualsiasi, e non serve stare attenti a prefissi e suffissi (nella stringa da trasmettere possono essere tranquillamente incluse le sequenze di start e stop). Il trucco è escapare tutti i backslash nei dati trasmettendoli doppi. Poi eventualmente aggiungere uno o due byte di chek dopo lo stop è un attimo.

trasmetti.png

Ciao docdoc,
grazie per la risposta esauriente.

In rosso le mie domande

#define MAXBUF 40
char inputBuf[MAXBUF];
byte pBuf = 0; \ se ho capito bene è il contatore della stringa inputBuf


void loop()
{
inputCheck();

void inputCheck() {
char c = 0;
if ( mySer.available() )
c = mySer.read();
if ( c > 0 ) { \ a che serve questo controllo?
if ( c == ‘\n’ || pBuf == MAXBUF) {
// Fine comando \ok, quindi qui io uscirei da inputCheck presumo
if ( pBuf > 0 )
execCommand();
pBuf = 0;
}
else if ( c != ‘\r’ && pBuf < MAXBUF ) { \non ho capito bene, \r serve per…? posso farne a meno?
inputBuf[pBuf++] = c;
inputBuf[pBuf] = 0;
}
}
}

void execCommand() }
// Qui leggo in “inputBuf” i caratteri ricevuti e faccio quello che serve…
// Ad esempio prima verifico il prefisso
if ( inputBuf[0] != ‘#’ ) {
// Pacchetto ignorato
Serial.println(“Pacchetto ignorato”); \non ci va invece MySer.println?
return;
}
// Interpreto il comando ed estraggo il parametro
char cmd = inputBuf[1];
char args[MAXBUF - 1];
strncpy(args, inputBuf + 2); \non conosco questa funzione, sto copiando dentro la variabile char args i miei parametri? (esempio… 37)
switch (cmd) {
// ------------------------------
case ‘V’:
// Eseguo… \ok, ora se voglio accendere esempio un led con pwm a 37 → analogWrite(pin, args)… giusto?
break;

}
}

char cmd = inputBuf[1];
char args[MAXBUF - 1];
strncpy(args, inputBuf + 2)

La strncpy() copia da secondo parametro al primo, con quel +2 dici di non iniziare dal primo char di inputBuf ma dal terzo. Un po come se scrivessi inputBuf[2] ricorda indice parte da 0
Occhio che strncpy() richiede un terzo parametro, quanti caratteri copiare. E qui manca.
Se non sai quanti caratteri copiare usi strcpy()

if ( c > 0 ) { \\ a che serve questo controllo?

Troppi dimenticano che Serial.read() può eventualmente ritornare -1 in caso di errore
Questo if verifica che Serial.read() non abbia dato -1

\\non ho capito bene, \r serve per..? posso farne a meno?

Quel pezzo serve per non scrivere nel buffer l'eventuale carattere speciale \r

\\non ci va invece MySer.println?

Solo se rimandi al programma che spedisce l'informazione che i dati sono stati ricevuti male.
Invece su Serial come fatto lo vedi tu da serial monitor per fare debug

 \\ok, ora se voglio accendere esempio un led con pwm a 37 -> analogWrite(pin, args).. giusto?

Devi convertire quel testo in numero. Puoi usare atoi()

@nid69ita: grazie per le risposte, sto sistemando il programma.

Domanda:
la funzione void execCommand() messa così non restituisce niente.
Vorrei con questa funzione aggiornare delle variabili globali integer.
Quale è la corretta sintassi?

Qui inserisco il programma, contenente certamente errori e mancante di atoi per trasformare la stringa args in decimale.
p, d, w sono le tre variabili integer globali da aggiornare.
In rosso le parti dove ho i dubbi sulla sintassi e alcune note:

[color=red]void [/color]execCommand[color=red]()[/color] {
  // Qui leggo in "inputBuf" i caratteri ricevuti e faccio quello che serve...
  // Ad esempio prima verifico il prefisso
  if ( inputBuf[0] != 'A' ) {
    // Pacchetto ignorato
    HM10.println("Pacchetto ignorato");
    return;
  }
  // Interpreto il comando ed estraggo il parametro
  char cmd = inputBuf[1];
  char args[MAXBUF - 1];
  strcpy(args, inputBuf + 2, 2); // copia 2 caratteri da inputBuf +2 alla stringa args (arguments)
  switch (cmd) {
    case 'P':
      p = args; // [color=red]devo inserire return p? [/color]
      break;
    case 'D':
      d = args; // [color=red]devo inserire return d? [/color]
      break;
    case 'W':
      w = args; // [color=red]devo inserire return w? [/color]
      break;
  }
}

NOTA: magari non cambia molto la sostanza ma nel dubbio te lo dico: comunque questa funzione, execCommand, si trova dentro un’altra funzione, inputCheck.

Qui sotto il programmino intero, per completezza:

// Arduino code to communicate with smartphone via BLE
// note: da android posso inviare qualsiasi carattere. Dentro Arduino deve essere considerato come codice ascii, es, terminale 0, Arduino legge 48
#include <SoftwareSerial.h>
#define MAXBUF 40
SoftwareSerial HM10(3, 4); // RX\TX .. BLE TX-> ATtiny85 PB0, BLE RX-> ATtiny85 PB1
char inputBuf[MAXBUF];
byte pBuf = 0;
int ledpin = 1; // define pin for led
char inData;
int p, d, w; // parametri per definire i tempi in secondi

void setup() {
  HM10.begin(9600); // start BEL device
  delay(500); // wait until BLE device starts
  HM10.println("AT+NAMEATtiny85_BLE"); // change device name
  delay(500); // wait for change
  HM10.println("AT+RESET"); // reset module to enact name change
  delay(1000); // wait for reset
  pinMode(3, INPUT);
  pinMode(4, OUTPUT);
  pinMode(ledpin, OUTPUT);
  analogWrite(ledpin, 100);

}

void loop() {
  inputCheck();
}

void inputCheck() {
  char c = 0;
  if ( HM10.available() ) {
    c = HM10.read();
    if ( c > 0 ) {
      if ( c == '\n' || pBuf == MAXBUF) {
        // Fine comando
      }
      if ( pBuf > 0 ) {
        execCommand();
        pBuf = 0;
      }
      else if (pBuf < MAXBUF ) {
        inputBuf[pBuf++] = c;
        inputBuf[pBuf] = 0;

      }
    }
  }
}

void execCommand() {
  // Qui leggo in "inputBuf" i caratteri ricevuti e faccio quello che serve...
  // Ad esempio prima verifico il prefisso
  if ( inputBuf[0] != 'A' ) {
    // Pacchetto ignorato
    HM10.println("Pacchetto ignorato");
    return;
  }
  // Interpreto il comando ed estraggo il parametro
  char cmd = inputBuf[1];
  char args[MAXBUF - 1];
  strcpy(args, inputBuf + 2, 2); // copia 2 caratteri da inputBuf +2 alla stringa args (arguments)
  switch (cmd) {
    case 'P':
      p = args;
      break;
    case 'D':
      d = args;
      break;
    case 'W':
      w = args;
      break;
  }
}

Se sono variabili globali, puoi fare come hai fatto
Però ti ripeto che args lo devi convertire in numero prima di assegnarlo a quelle globali int
perchè:

  1. non puoi fare assegnazione tra vettore di char a numero, non converte da solo come farebbe un VB
  2. se p fosse un puntatore, assegni a p un puntatore a zona di memoria locale, che viene distrutta quando la funzione finisce

devi usare: p=atoi(args);

P.S. togli quel ,2 alla strcpy !!

squizzy91:
Qui inserisco il programma

Ok, ma per prima cosa prova ad indentare il codice (premi Ctr-T entro l'IDE, te lo sistema lui) perché quella "if ( c == '\n' || pBuf == MAXBUF)" ha il corpo senza alcun comando, inoltre esegui "execCommand()" ad ogni carattere ricevuto (perché hai aggiunto il controllo "if ( c > 0 )"?).

Comunque sia, per rispetto del regolamento, dovresti modificare questo tuo messaggio per includere il codice tra i tag "code".

Inizia a sistemare queste cose, poi posta il nuovo codice e proseguiamo anche col discorso variabili globali e altro..

Reply a nid69ita

nid69ita:
Se sono variabili globali, puoi fare come hai fatto

Si, sono tre variabili globali (p, d, w).
Quindi se ho capito bene costruisco la funzione con questa sintassi quindi void execCommand**()**
e non devo ritornarle inserendo dei return.

nid69ita:
Però ti ripeto che args lo devi convertire in numero prima di assegnarlo a quelle globali int
perchè:

  1. non puoi fare assegnazione tra vettore di char a numero, non converte da solo come farebbe un VB
  2. se p fosse un puntatore, assegni a p un puntatore a zona di memoria locale, che viene distrutta quando la funzione finisce

dei usare: p=atoi(args);

sisi capito. Modifica applicata.

nid69ita:
P.S. togli quel ,2 alla strcpy !!

Ok, avevo fatto confusione con strncpy.
poichè i comandi che invio da smartphone ad arduino terminano con \n, se uso strcpy senza pertanto specificare quan ti caratteri prendere in considerazione, io mi copio anche lo \n.
Dico bene? Quando uso atoi per estrarre il parametro decimale esso poi viene ignorato?

In altre parole:
1-col mio cellulare voglio settare la variab ile globale p = 23 quindi la mia app android spara il comando AP23\n
2-strcpy legge dalla seconda posizione ed estrae 23\n
3-atoi converte 23\n char in 23 int e lo assegno alla variabile p.

é corretto?

Reply a nid69ita

docdoc:
quella “if ( c == ‘\n’ || pBuf == MAXBUF)” ha il corpo senza alcun comando,

corretto, avevo aggiunto un corpo vuoto io per scriverci qualcosa… ma avevo capito male io la logica e ho ripristianto a come mi avevi mostrato tu.

docdoc:
inoltre esegui “execCommand()” ad ogni carattere ricevuto

corretto poichè ho corretto il punto sopra… ora dovrebbe filare e execCommand è eseguito solo quando quando viene letto il carattere \n del pacchetto dati.

docdoc:
(perché hai aggiunto il controllo “if ( c > 0 )”?).

quello c’era già nel programma da te postato… no? serve perchè, diceva nid69ita, Serial.read può assumere valore -1

docdoc:
Comunque sia, per rispetto del regolamento, dovresti modificare questo tuo messaggio per includere il codice tra i tag “code”.

fatto

docdoc:
posta il nuovo codice e proseguiamo anche col discorso variabili globali e altro…

Eccolo tutto il programma:

#include <SoftwareSerial.h>
#define MAXBUF 40
SoftwareSerial HM10(3, 4); // RX\TX .. BLE TX-> ATtiny85 PB0, BLE RX-> ATtiny85 PB1
char inputBuf[MAXBUF];
byte pBuf = 0;
int ledpin = 1; // define pin for led
char inData;
int p, d, w; // parametri per definire i tempi in secondi

void setup() {
  HM10.begin(9600); // start BEL device
  delay(500); // wait until BLE device starts
  HM10.println("AT+NAMEATtiny85_BLE"); // change device name
  delay(500); // wait for change
  HM10.println("AT+RESET"); // reset module to enact name change
  delay(1000); // wait for reset
  pinMode(3, INPUT);
  pinMode(4, OUTPUT);
  pinMode(ledpin, OUTPUT);
  analogWrite(ledpin, 100); // for further testing purposes

}

void loop() {
  inputCheck();
}

void inputCheck() {
  char c = 0;
  if ( HM10.available() ) 
    c = HM10.read();
    if ( c > 0 ) { 
      if ( c == '\n' || pBuf == MAXBUF) {
        // Fine comando
      if ( pBuf > 0 )
        execCommand();
        pBuf = 0;
      }
      else if ( c != '\r' && pBuf < MAXBUF - 1 ) {
        inputBuf[pBuf++] = c;
        inputBuf[pBuf] = 0;
      }
    }
  }

void execCommand() {
  // Qui leggo in "inputBuf" i caratteri ricevuti e faccio quello che serve...
  // Ad esempio prima verifico il prefisso
  if ( inputBuf[0] != '#' ) {
    // Pacchetto ignorato
    HM10.println("Pacchetto ignorato");
    return;
  }
  // Interpreto il comando ed estraggo il parametro
  char cmd = inputBuf[1];
  char args[MAXBUF - 1];
  strncpy(args, inputBuf + 2, 2); // copia 2 caratteri da inputBuf +2 alla stringa args (arguments)
  switch (cmd) {
    case 'P':
      p = atoi(args);
      break;
    case 'D':
      d = atoi(args);
      break;
    case 'W':
      w = atoi(args);
      break;
  }
}