...
Grazie.
Da remoto intendi via seriale ? leggo rx, tx. O intendi via seriale del bluetooth ? Hc12=modulino radio 433 Mhz ?
docsavage:
Naturalmente ogni critica, commento e/o suggerimento è gradita
Prossimo sviluppo?
Si potrebbe implementare un indirizzo broadcast, ad esempio '.'
In 'ricevi' verrà settato anche un flag 'broad' in modo che 'esegui' possa scegliere cosa fare.
Un messaggio broadcast può essere utile per informare tutti gli ascoltatori di uno stato globale senza contattarli singolarmente, o ancora un ascoltatore può rispondere in modo broadcast per aggiornare tutti gli altri con un'informazione comune (ad esempio l'orario).
Mancherebbe ancora un controllo errori, che potrebbe essere una coppia di caratteri hex rappresentanti un qualsiasi CRC8 o checksum a 8 bit, ma in questo caso specifico mi domando se sia davvero necessario.
In una trasmissione di byte "normale" ci sono meno vincoli rispetto ad una trasmissione "testuale", ogni byte può valere da 0 a 255 e comparire in qualsiasi punto, mentre mi chiedo se il fatto di obbligare i valori entro limiti ristretti (solo alcuni caratteri del set ASCII), e successivamente controllare anche la congruenza di quanto ricevuto "ricomponendo" i caratteri (ad esempio nel caso di valori numerici), non svolgano già un'adeguata funzione di error detect.
Alla fine è tornato comodo anche a me, ho aggiunto anche la possibilità di ricevere un CRC8 in formato HEX (due caratteri aggiuntivi dopo il *)
Le variabili di lavoro:
#define MODULE_ADDR '0' // indirizzo/nome del modulo
#define MAX_LEN_BUF 16 // lunghezza massima payload
#define CRC_ON false // controllo CRC disattivo
byte rxBufi; // indice buffer, alla fine=numero byte ricevuti
byte rxBuf[MAX_LEN_BUF]; // buffer di ricezione
boolean onBroad = false; // true se ricevuto indirizzo broadcast '&'
Le funzioni di supporto:
//------------------------------------------------------------------------------
// SNAP CRC8 - initial val 0 - reflect data in - reflect crc out - polynom 31h
//------------------------------------------------------------------------------
void crcUpdate(byte &crc, byte n)
{
crc ^= n;
for(byte i=8; i; i--)
{
byte lsb = crc & 1;
crc >>= 1;
if(lsb) crc ^= 0x8C; // reflected polynom
}
}
boolean isAsciiHex(byte n)
{
return (n >= '0' && n <= '9') ? true : (n >= 'A' && n <= 'F') ? true : false;
}
//------------------------------------------------------------------------------
byte hexToInt(byte n)
{
byte m = n - '0';
return (m > 9) ? m - 7 : m;
}
La ricezione:
//------------------------------------------------------------------------------
// FORMATO CON CRC: #<addr><msg>*<crc> ESEMPIO: #0L01*0F
// FORMATO SENZA CRC: #<addr><msg>* ESEMPIO: #0L01*
// # -> start char
// <addr> -> 1 char (& = broadcast)
// <payload> -> 0..MAX_LEN_BUF char
// * -> end msg char
// <crc> -> 2 char hex SNAP CRC8 facoltativi
//------------------------------------------------------------------------------
boolean ricevuto()
{
static byte stat = 0;
static byte crc;
static byte crcH;
while(Serial.available())
{
byte rx = Serial.read();
if(rx == '#') { rxBufi = onBroad = crc = 0; stat = 1; } // start
else if(rx < ' ') stat = 0; // esclude 0..31 128..255
else
switch (stat)
{
case 1: // ricezione indirizzo modulo
if(CRC_ON) crcUpdate(crc, rx);
if(rx == MODULE_ADDR) stat = 2;
else if(rx == '&') { onBroad = true; stat = 2; }
else stat = 0;
break;
case 2: // ricezione dati
if(rx == '*') // fine dati
{
if(CRC_ON) stat = 3;
else { stat = 0; return true; }
}
else if(rxBufi == MAX_LEN_BUF) stat = 0; // over buffer
else // salva byte
{
if(CRC_ON) crcUpdate(crc, rx);
rxBuf[rxBufi++] = rx;
}
break;
case 3: // ricezione carattere alto crc8
if(isAsciiHex(rx)) { crcH = hexToInt(rx); stat = 4; }
else stat = 0;
break;
case 4: // ricezione carattere basso crc8
stat = 0;
if (isAsciiHex(rx) && crc == (crcH << 4) + hexToInt(rx))
return true;
}//switch
}//while
return false;
}
Quando la funzione ritorna true, rxBufi contiene il numero di caratteri ricevuti e onBroad vale true se l'indirizzo era '&'.
I caratteri ricevuti nel buffer non comprendono: start, indirizzo, fine, eventuale crc.
L'eventuale crc si calcola sui soli caratteri racchiusi tra # e * (quindi indirizzo e dati)
La funzione cerca, tra tutti i caratteri presenti in quel momento nel buffer di ricezione seriale, una sequenza valida, scartando tutto il resto e ritornando true appena ne trova una. Qualche carattere può restare nel buffer seriale e verrà analizzato/scartato alla successiva chiamata, qualsiasi sequenza errata viene ignorata senza alcun avviso.
La risposta alla domanda se limitare la comunicazione all' ASCII la rendeva intrinsecamente più adatta/sicura a rilevare/evitare gli errori è: NO
Se c'è la possibilità di linea errorata serve proprio un CRC.
Un normale checksum o uno xor ad esempio non rilevano differenze tra 0L01 e 01L0.
Fondamentalmente un current loop parallelo.
Master:
Slave:

I valori o la configurazione possono sembrare strani, ma sono ottenuti con misure all'oscilloscopio e mezzo chilometro di linea tra master e slave (caricando la linea in modo da simulare 30 slave connessi contemporaneamente).
Velocità 9600 bps.
Mi interessava il totale isolamento dei nodi.
La tensione ausiliaria 13V non è critica (da 10 a 16 mi pare funzionasse sempre).
