Go Down

Topic: Avoid strange characters from serial buffer (Read 1 time) previous topic - next topic

blastboot

Hi everyone, need your very important help again... i have a ultrasonic sensor from Maxbotix(mb7060) which output delivers asynchronous serial with an RS232 format, except voltages are 0-Vcc. The output is an ASCII capital "R", followed by three ASCII character digits representing the range in centimeters up to a maximum of 765, followed by a carriage return (ASCII 13). The baud rate is 9600, 8 bits, no parity, with one stop bit.
Because of RS232 format with TTL level (5 volts its a '0' and 0 volts its a '1') i have to put an TTL inverter to invert this voltages to arduino to understand it when it receives the readings on RX pin.

Sometimes i get some strange characters reading (maybe because i was disable the sensor in the middle of reading sended by sensor) so i make some changes in my code, that follows:
Code: [Select]
#include <SPI.h>
#include <VirtualWire.h>
#define TEMPO_LIMITE 200  //Tempo de espera por dados na serie

//DECLARAÇÃO DAS VARIÁVEIS GLOBAIS
//ENABLE/DISABLE PARA O SENSOR
const int sensor = 7;

//LED'S
const int ledTransmissao = 4;
const int ledActivacao = 5;

//ENABLE/DISABLE DO TRANSMISSOR E PINO DE TRANSMISSÃO
const int pinoTransmissao = 8;
const int pinoActTransm = 3;

//VARIÁVEL QUE GUARDA A MENSAGEM A TRANSMITIR
char mensagem[5];

//VARIÁVEIS PARA DADOS LIDOS DO SENSOR
int dados;
char buffer[4];
boolean estado = false;
unsigned long inicioContagem;

void setup(){
 
//DEFINIÇÃO DOS PINOS DE ENTRADA E DE SAÍDA
 pinMode(sensor, OUTPUT);
 pinMode(ledTransmissao, OUTPUT);
 pinMode(ledActivacao, OUTPUT);
 digitalWrite(sensor, LOW);
 //digitalWrite(pinoActTransm, LOW);
 digitalWrite(ledTransmissao, LOW);
 digitalWrite(ledActivacao, LOW);
   
//CONFIGURAÇÃO DO VIRTUALWIRE -TRANSMISSÃO-
 vw_set_tx_pin(pinoTransmissao);
 vw_set_ptt_pin(pinoActTransm);
 vw_setup(2000);  //VELOCIDADE DE TRANSMISSÃO DE 2000 BITS POR SEGUNDO

//INICIAR A UART PARA DEBUG
 Serial.begin(9600);
 delay(1000);
}

void loop() {

//ENABLE DO SENSOR E LED DE ACTIVAÇÃO LIGADO

 digitalWrite(sensor, HIGH);
 digitalWrite(ledActivacao, HIGH);
 
//LEITURA DOS DADOS ENVIADOS PELO SENSOR
inicioContagem = millis();
 while ((Serial.available () < 5) && ((millis() - inicioContagem) < TEMPO_LIMITE))
 {
   //Espera que o buffer tenha pelo menos 5 bytes para ler e que não demore mais que 1 segundo
 }
 if (Serial.available() < 5) {
   Serial.println("Não foram recebidos 5 bytes de dados");
   Serial.flush();
   delay(5000);
 } else {
   char c = Serial.read();
   if (c == 'R') {
    Serial.readBytesUntil ('\r', &buffer[0], 4);
 
//DISABLE DO SENSOR E LED DE ACTIVAÇÃO DESLIGADO
 digitalWrite(sensor, LOW);
 digitalWrite(ledActivacao, LOW);
 Serial.flush();
 dados = atoi (buffer);  //CONVERSÃO DOS DADOS RECEBIDOS PARA VALORES INTEIROS
 
 //ENVIO PARA A SÉRIE DO VALOR, PARA DEPURAÇÃO
 Serial.print("BUFFER:");
 Serial.print(buffer);
 Serial.print("  ");
 Serial.print("DADOS:");
 Serial.println(dados);

 memset(&buffer, 0, sizeof(buffer)); //LIMPEZA DO BUFFER
 Serial.print("BUFFER:");
 Serial.println(buffer);
 
/*VERIFICAÇÃO SE OS DADOS RECEBIDOS DO SENSOR SÃO VÁLIDOS. O MÁXIMO
VALOR É 465 -ALTURA MÁXIMA DA ÁGUA- E O MÍNIMO É ZERO -TANQUE VAZIO-*/
 if(dados >= 1 && dados <= 465) {
   mensagem[0] = 'R';
   itoa (dados, &mensagem[1], 10);
   Serial.print("MENSAGEM A TRANSMITIR:");
   Serial.println(mensagem);
   
//LED DE TRANSMISSÃO ACTIVA LIGADO
   digitalWrite(ledTransmissao, HIGH);

//ENVIO DA MENSAGEM 2 VEZES PARA GARANTIR QUE É RECEBIDA  
   for (int i = 0; i<2; i++) {
   vw_send ((uint8_t*)mensagem, strlen(mensagem)); //ENVIO DA MENSAGEM
   vw_wait_tx(); //ESPERA QUE MENSAGEM SEJA TOTALMENTE ENVIADA
   delay(2000);
   }
   digitalWrite(ledTransmissao, LOW);
   memset(&mensagem, 0, sizeof(mensagem)); //LIMPA O BUFFER DA MENSAGEM ENVIADA
}
//LED DE TRANSMISSÃO ACTIVA DESLIGADO
   Serial.print("MENSAGEM:");
   Serial.println(mensagem);
   Serial.flush();
   delay(5000);
 }
  }
}

/*FIM DO PROGRAMA*/

I expected to get good data from serial, but sometimes it doesn't.
I'm asking if you could help me to do some changes to the code to prevent receiving strange characters.
Adding to this i realize that somethimes i get in serial monitor the same reads (like 8 or 9 times) even pointing sensor to another object at another distance... Got no clues at this time that what could be do this.
Thanks in advance!

blastboot

After reading Serial.flush() documentation i realize that it just not clear serial buffer anymore   :smiley-eek-blue:  So maybe this could be the problem because i always think that it is clearing serial buffer but it's not!
How can i clear the entire serial buffer now?

blastboot

#2
Mar 01, 2013, 08:39 pm Last Edit: Mar 01, 2013, 08:42 pm by blastboot Reason: 1
I've made it. After a lots of tests i could make the code get always good readings.
For people who may have this issue i let the new code here:
Code: [Select]
#include <SPI.h>
#include <VirtualWire.h>
#define TEMPO_LIMITE 200  //Tempo de espera por dados na serie

//DECLARAÇÃO DAS VARIÁVEIS GLOBAIS
//ENABLE/DISABLE PARA O SENSOR
const int sensor = 7;

//LED'S
const int ledTransmissao = 4;
const int ledActivacao = 5;

//ENABLE/DISABLE DO TRANSMISSOR E PINO DE TRANSMISSÃO
const int pinoTransmissao = 8;
const int pinoActTransm = 3;

//VARIÁVEL QUE GUARDA A MENSAGEM A TRANSMITIR
char mensagem[5];

//VARIÁVEIS PARA DADOS LIDOS DO SENSOR
int dados;
char buffer[4];
boolean estado = false;
unsigned long inicioContagem;
unsigned char limpezaSerial;

void setup(){
 
//DEFINIÇÃO DOS PINOS DE ENTRADA E DE SAÍDA
 pinMode(sensor, OUTPUT);
 pinMode(ledTransmissao, OUTPUT);
 pinMode(ledActivacao, OUTPUT);
 digitalWrite(sensor, LOW);
 //digitalWrite(pinoActTransm, LOW);
 digitalWrite(ledTransmissao, LOW);
 digitalWrite(ledActivacao, LOW);
   
//CONFIGURAÇÃO DO VIRTUALWIRE -TRANSMISSÃO-
 vw_set_tx_pin(pinoTransmissao);
 vw_set_ptt_pin(pinoActTransm);
 vw_setup(2000);  //VELOCIDADE DE TRANSMISSÃO DE 2000 BITS POR SEGUNDO

//INICIAR A UART PARA DEBUG
 Serial.begin(9600);
 delay(1000);
}

void loop() {

//ENABLE DO SENSOR E LED DE ACTIVAÇÃO LIGADO

 digitalWrite(sensor, HIGH);
 digitalWrite(ledActivacao, HIGH);
 
//LEITURA DOS DADOS ENVIADOS PELO SENSOR
inicioContagem = millis();
 while ((Serial.available () < 5) && ((millis() - inicioContagem) < TEMPO_LIMITE))
 {
   //Espera que o buffer tenha pelo menos 5 bytes para ler e que não demore mais que 1 segundo
 }
 if (Serial.available() < 5) {
   Serial.println("Nao foram recebidos 5 bytes de dados");
   delay(5000);
 } else {
   digitalWrite(sensor, LOW);
   digitalWrite(ledActivacao, LOW);
   char c = Serial.read();
   if (c == 'R') {
    Serial.readBytesUntil ('\r', &buffer[0], 4);
   
 dados = atoi (buffer);  //CONVERSÃO DOS DADOS RECEBIDOS PARA VALORES INTEIROS
 
 //ENVIO PARA A SÉRIE DO VALOR, PARA DEPURAÇÃO
 Serial.print("BUFFER:");
 Serial.print(buffer);
 Serial.print("  ");
 Serial.print("DADOS:");
 Serial.println(dados);
 memset(&buffer, 0, sizeof(buffer)); //LIMPEZA DO BUFFER
 Serial.print("BUFFER:");
 Serial.println(buffer);
 
/*VERIFICAÇÃO SE OS DADOS RECEBIDOS DO SENSOR SÃO VÁLIDOS. O MÁXIMO
VALOR É 465 -ALTURA MÁXIMA DA ÁGUA- E O MÍNIMO É ZERO -TANQUE VAZIO-*/
 if(dados >= 1 && dados <= 465) {
   mensagem[0] = 'R';
   itoa (dados, &mensagem[1], 10);
   Serial.print("MENSAGEM A TRANSMITIR:");
   Serial.println(mensagem);
   
//LED DE TRANSMISSÃO ACTIVA LIGADO
   digitalWrite(ledTransmissao, HIGH);

//ENVIO DA MENSAGEM 2 VEZES PARA GARANTIR QUE É RECEBIDA  
   for (int i = 0; i<2; i++) {
   vw_send ((uint8_t*)mensagem, strlen(mensagem)); //ENVIO DA MENSAGEM
   vw_wait_tx(); //ESPERA QUE MENSAGEM SEJA TOTALMENTE ENVIADA
   delay(2000);
   }
   digitalWrite(ledTransmissao, LOW);
   memset(&mensagem, 0, sizeof(mensagem)); //LIMPA O BUFFER DA MENSAGEM ENVIADA
}
//LED DE TRANSMISSÃO ACTIVA DESLIGADO
   Serial.print("MENSAGEM:");
   Serial.println(mensagem);
   delay(5000);
 }
  }
     limpezaSerial = Serial.available();
     for (int s=limpezaSerial; s>=0; s--) {
     Serial.read();
     }
}

/*End of Program*/


I had two wrong things. The first was the char array "Buffer" that only had 3 bytes and it needed 4 bytes (i have ever this problem of calculating the number of vectors needed   :~  );
The second was the Serial.readBytesUntil function that was only reading 3 bytes and needed to read 4.
The last was the Serial.flush that i thought that was clearing the serial buffer, but it was changed since version 1.0 of IDE, so i cleared it this way:
Code: [Select]
limpezaSerial = Serial.available();
     for (int s=limpezaSerial; s>=0; s--) {
     Serial.read();
     }


Cheers!

robtillaart

Your clearing routine has a flaw if additional character come in after you read Available() and you are in the for loop.

The best way to clear the buffer from code is the following loop as it continues to check the buffersize, if additional bytes come in these are also read.
Code: [Select]
while (Serial.available()>0) Serial.Read();

Even better is to add a simple clearRX() function to the (Hardware) Serial library. It resets the internal pointer.

Code: [Select]
void HardwareSerial::clearRX(void)
{
_rx_buffer->tail = _rx_buffer->head;
}

This is about the best you can do.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

blastboot

Thanks it's always good to know another and better options. In my case and because i'm expecting only receive data from sensor and since there is at least 5 bytes in serial buffer, the sensor is disabled i will not receive no other data after that, but sure that the options you gave are more efficient and prevents this possible issue that for loop have if data is received after var gets the number of bytes of serial buffer at that time.

Go Up