Pages: [1]   Go Down
Author Topic: Avoid strange characters from serial buffer  (Read 1240 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 0
Posts: 106
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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!
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 106
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 106
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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   smiley-confuse  );
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:
limpezaSerial = Serial.available();
      for (int s=limpezaSerial; s>=0; s--) {
      Serial.read();
      }

Cheers!
« Last Edit: March 01, 2013, 02:42:02 pm by blastboot » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 216
Posts: 13676
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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:
void HardwareSerial::clearRX(void)
{
 _rx_buffer->tail = _rx_buffer->head;
}
This is about the best you can do.
Logged

Rob Tillaart

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

Offline Offline
Full Member
***
Karma: 0
Posts: 106
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Pages: [1]   Go Up
Jump to: