Ho l'esigenza di leggere un sensore di distanza (MB7060 datasheet: http://www.maxbotix.com/documents/MB7060-MB7070_Datasheet.pdf) che ha come possibilità di uscita, fra l'altro, una RS232. (Dico subito che ho scartato l'uscita analogica perchè l'ambiente di installazione del sensore è altamente rumoroso e le oscillazioni sembravano un'altalena... )
Osservo anche che mi è noto che il protocollo RS232 standard utilizza tensioni fuori dal range di Arduino, ma il sensore, come riporta il datasheet emette un segnale 0-Vcc, quindi entro i 5V utilizzati per la sua alimentazione, senza friggermi i pin di Arduino.
Nella sezione dedicata all'uscita RS232 si dice che il sensore emette una R maiuscola e tre cifre in formato ASCII che lette una dietro l'altra mi danno la distanza in cm letta dallo stesso. Praticamente per una distanza di 35 cm dovrei avere R035, quindi un carattere di "a capo".
Ho scritto un breve listato che legge a caso 10 volte sulla seriale software (uso la libreria SerialSoftware perchè la seriale HW è occupata da un LCD).
ossia 10 caratteri, che nella codifica ASCII sono apparentemente a caso. Si ripete "0 43 0" (come se questa fosse la "R" ad inizio segnale") e poi ci sono 5 numeri che variano al variare della distanza di ostacoli dal sensore.
Sono certo che il problema sia una cattiva decodifica dei dati in arrivo dalla seriale, anche perchè se il sensore sta fermo quei numeri che vi ho scritto restano costanti. Quindi rappresentano, in codice, una lettura.
Ok, quindi non ci sono le limitazioni sui pin della SoftwareSerial ...
Sicuramente hai un problema con la lettura dei valori ...
... tu difatti aspetti che si disponibile qualche cosa sulla seriale, ma poi ... leggi a raffica 10 valori senza sapere se c'è qualche cosa di valido o no (... e quasi sicuramente NON c'è visto che Arduino è molto più veloce a fare quel ciclo che non il sensore a scrivere carattere a carattere sulla seriale) !!!
OGNI lettura deve essere preceduta da "if (mySerial.available() ) { ... }" altrimenti rischi che "mySerial.read()" ti ritorni valori non validi.
Introduci questa modifica e verifica cosa succede ...
Guglielmo
P.S. : ... e scusa ... quale sarebbe lo scopo della "mySerial.flush()" che fai alla fine ???
Per quel che ho capito dal datasheet, il sensore invia in continuo la lettura. Quindi dopo che ho preso i valori, vorrei svuotare il buffer, per leggere al prossimo ciclo valori "freschi". Questo ragionamento naturalmente ipotizza una velocità di invio del sensore alta, compatibile o maggiore di quella di Arduino.
Provo invece la strada suggerita da te limitando la lettura con una verifica della disponibilità dati e ti faccio sapere...
nfloppy:
Mi è venuto il dubbio che lo standard RS232 abbia una logica invertita rispetto a TTL. ...
Ah .. questo SI ... una a riposo è LOW (RS232), e, se leggi il datasheet, c'è anche scritto : "Low IDLE state for RS232", mentre la seriale TTL, a riposo è HIGH ... devi mettere un inverter ...
Nella dichiarazione della porta seriale virtuale via software, come terzo parametro specificando 'true' si imposta l'inversione della logica (per rendere TTL compatibile con RS232 !!!salvo tensioni naturalmente!!!).
Ho fatto al volo una prova e sembra leggere valori ASCII pari a 82 (l'attesa R maiuscola) e compresi nel range 48-57, ossia i digit. Quindi a occhio sembra funzionare. Ottimizzo il codice e lo posto appena possibile perchè resti a disposizione della comunità.
Posto il listato finale (una prova veloce, naturalmente da modificare per le esigenze di ciascuno e senz'altro ottimizzabile da programmatori più esperti.).
Funziona. E risolve il problema di un ambiente davvero rumoroso (vi garantisco che l'uscita analogica oscilla di 1.5 - 2.5 V in continuazione...). E' così stabile che probabilmente non servono ulteriori manovre di normalizzazione del dato, come ne ho trovate in rete (ad esempio campionando la lettura ad n intervalli e scartando valori troppo lontani dalla media...). Naturalmente però dipende dall'applicazione.
L'inversione della logica rende compatibile il TTL col protocollo RS-232 (a meno, lo sottolineo per chi dovesse leggere questa replica senza il resto della discussione, dei valori di tensione, che nel caso del sensore in uso sono 0-Vcc, mentre il protocollo RS-232 standard prevede range più estesi ed anche negativi, non compatibili direttamente con Arduino).
#include <SoftwareSerial.h>
SoftwareSerial mySerial(6, 7, true); // RX, TX, inv. logica
void setup() {
//inizializzazione LCD
Serial.begin(9600);
Serial.write(0x13);
Serial.write(4);
Serial.write(30);
Serial.write(200);
//impostazioni per Serial Software
mySerial.begin(9600);
pinMode(6, INPUT);
pinMode(7, OUTPUT);
}
void lcd_pos(byte x, byte y)
{
Serial.write(3);
Serial.write(x);
Serial.write(y);
}
void loop() {
long tempo = millis();
boolean valore = false;
byte dato = 0;
char c1;
char c2;
char c3;
do
{
if (mySerial.available() > 8) { //poichè il sensore invia 5 caratteri (R)(xxx)(13) in 9 byte ho la certezza di avere un dato completo
do
{
dato = mySerial.read();
} while (dato != 82);
c1 = mySerial.read();
c2 = mySerial.read();
c3 = mySerial.read();
valore = true;
}
} while (!valore || ((millis() - tempo) > 10000)); // dopo 10 secondi esce dal loop
lcd_pos(1,1);
Serial.print("Distanza: ");
Serial.print(c1);
Serial.print(c2);
Serial.print(c3);
Serial.print("cm ");
delay(1000);
mySerial.flush(); //svuota il buffer della serial software
valore = false;
Serial.write(12); //cancella l'LCD
}
Grazie a Guglielmo per la consueta assistenza!
Spero che la mia esperienza possa tornare utile a qualcuno.