Captura de serial hex e conversão para decimal

Tenho um sensor que após enviar enviar 3 bytes pela porta serial (B0, 31,E1) ele me responde com 8 bytes : Sendo os 2 primeiros (B0 e A2) fixos e identificadores. O terceiro byte é o que vai definir o tipo de unidade. (pode ser 00, 01, 02, e 03) . Normalmente será 02 significando unidade em quilogramas). Em seguida é que vem o complicado. São 4 bytes significando o valor como um inteiro de 32 bits . O ultimo byte é o checksum que é a soma de todos os bytes anteriores.
O que não sei é como capturar esses 8 bytes , e ler o valores e fazer essa conversão para decimal ... Agradeceria se alguém puder me dar uma luz.

Olá,

Por curiosidade, que tipo de sensor é?

Então, a primeira coisa a fazer é verificar no ciclo principal se existem dados disponíveis no buffer de recepção do porto série e fazer uma função para processar esses dados.

Por exemplo:

  // Verifica se existem dados disponiveis.
  if ( Serial.available() ) {
    dados_recebe();
  }

Agora basta fazer a função dados_recebe() utilizando a função Serial.readBytes(). O timeout para a recepção de dados pode ser alterado, por exemplo no setup(), através de Serial.setTimeout(). Por omissão o timeout é de 1000 milisegundos.

Depois da recepção dos dados podes validar a mensagem verificando se tem 8 bytes e o respectivo checksum.

Exemplo onde antes de obter o inteiro de 32 bits é feita a verificação do tamanho da mensagem e validado o checksum:


// Definicao dos indices (idx) da mensagem recebida (8 bytes).
// (apenas para facilitar...)
#define IDX_ID_1    0
#define IDX_ID_0    1
#define IDX_TYPE    2
#define IDX_INT32_3 3
#define IDX_INT32_2 4
#define IDX_INT32_1 5
#define IDX_INT32_0 6
#define IDX_CHKSUM  7

// Definicao do tamanho do buffer auxiliar de recepcao.
#define SIZE_BUFFER 50

// Buffer auxiliar para processar os dados recebidos.
unsigned char rx_buffer[SIZE_BUFFER];

void dados_recebe() {
  long resultado;
  int rx_len;
  unsigned char chksum=0;

  // Obtem os dados para o buffer:
  rx_len = Serial.readBytes(rx_buffer, SIZE_BUFFER);

  // Mostra os dados obtidos.
  Serial.print("Dados recebidos: ");
  for(int i = 0; i < rx_len; i++) {
    if ( (rx_len == 8) && (i < IDX_CHKSUM) ) {
      // Soma cada byte para uma variavel de um byte.
      // A soma irá exceder o byte... o excesso será descartado...
      chksum += rx_buffer[i];
    }
    // Mostra os dados da mensagem em hexadecimal.
    Serial.print(" 0x");
    Serial.print(rx_buffer[i], HEX);
  }

  // Verificacao do checksum.
  // Ignorar a mensagem se esta tiver mais de 8 bytes...
  if (rx_len == 8) {
    Serial.print(" Checksum: ");
    Serial.print(chksum, HEX);
    // Se o checksum coincide:
    if (chksum == rx_buffer[IDX_CHKSUM]) {
      Serial.print(" OK!");
      // Obtem o numero a partir dos 4 bytes,
      // assumindo que o primeiro e' o mair peso
      // e o ultimo o de menor peso.
      // Aqui o valor é construído usando a soma dos bytes
      // de maior peso deslocados para a esquerda.
      // O ultimo nao precisa, sera apenas adicionado.
      // Caso o inteiro seja enviado pela ordem inversa
      // entao basta fazer o mesmo mas comecar pelo IDX_INT32_0
      // em vez do IDX_INT32_3.
      resultado = ((long)rx_buffer[IDX_INT32_3] << 24) +\
               ((long)rx_buffer[IDX_INT32_2] << 16) +\
               ((long)rx_buffer[IDX_INT32_1] << 8) +\
               rx_buffer[IDX_INT32_0];
      Serial.print(" Valor inteiro obtido: ");
      Serial.print(resultado);
      if (rx_buffer[IDX_TYPE] == 2) {
        Serial.print(" kg.");
      } // else if ... testar os outros casos...
    } else {
      Serial.print(" ERRO!");
    }
  }

  Serial.println(" ");
}

1 Like

Obrigado peja ajuda amigo. Vou testar o código. O sensor é o HX-750 para células de carga. Veja no seguinte link: HX-750

O código está capturando os dados porém imprime na mesma linha duas respostas consecutivas e não detecta o checksum para passar para a etapa seguinte. O inicio correto de cada mensagem são os 2 bytes : 0xB0 0xA2.

Dados recebidos: 0xB0 0xA2 0x2 0x0 0x3 0xC8 0xED 0xC 0xB0 0xA2 0x2 0x0 0x3 0xCA 0xB9 0xDA
Dados recebidos: 0xB0 0xA2 0x2 0x0 0x3 0x8C 0xC3 0xA6 0xB0 0xA2 0x2 0x0 0x3 0xBB
0x75 0x87

Coloquei a variavel resultado como unsigned long . Tirei qualquer delay do loop e agora obtenho o seguinte:

Dados recebidos: 0xB0 0xA2 0x2 0x0 0xB0 0xA2 0x2 0x0 0xB0 0xA2 0x2 0x0 0x3 0xA3 0x36 0x30
Dados recebidos: 0xB0 0xA2 0x2 0x0 0x3 0xA6 0xCE 0xCB Checksum: CB OK! Valor inteiro obtido: 239310 kg.
Dados recebidos: 0xB0 0xA2 0x2 0x0 0xB0 0xA2 0x2 0x0 0xB0 0xA2 0x2 0x0 0x3 0x98 0x70 0x5F
Dados recebidos: 0xB0 0xA2 0x2 0x0 0x3 0xBD 0x41 0x55 Checksum: 55 OK! Valor inteiro obtido: 245057 kg.

Como se vê a medição ocorre ocasionalmente e parece coerente mas só estou obtendo leituras em cerca de 1Hz.... não há nenhum delay especificado no código. Já verifiquei que o sensor suporta uma taxa de atualização bem maior.

Consegui uma melhora :
diminui o #define SIZE_BUFFER 50 para 8 e parece que acelerou muito a saida. Colocando o delay (100) está funcionando perfeitamente:
Também dividi o resultado por 100000:
Serial.print(resultado/100000);

Dados recebidos: 0xB0 0xA2 0x2 0x0 0x5 0x5F 0xB7 0x6F Checksum: 6F OK! Valor inteiro obtido: 3 kg.
Dados recebidos: 0xB0 0xA2 0x2 0x0 0x5 0x5F 0xB7 0x6F Checksum: 6F OK! Valor inteiro obtido: 3 kg.
Dados recebidos: 0xB0 0xA2 0x2 0x0 0x5 0x3C 0xB2 0x47 Checksum: 47 OK! Valor inteiro obtido: 3 kg.
Dados recebidos: 0xB0 0xA2 0x2 0x0 0x5 0x44 0xC7 0x64 Checksum: 64 OK! Valor inteiro obtido: 3 kg.

Então agora parece bem correto.

1 Like

A função de leitura de bytes só termina quando o buffer auxiliar de recepção ficar cheio ou quando acontecer o timeout (que por omissão é 1 segundo).

O timeout pode ser alterado através a função Serial.setTimeout().

Exemplo de acerto do timeout (no setup()) para 50 ms:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.setTimeout(50);
}

Neste caso reduzindo o buffer para 8 bytes resolve a situação :slight_smile: . Geralmente nestas situações uso um buffer maior que o tamanho da mensagem porque por vezes pode surgir algum(s) byte(s) a mais no inicio ou no fim da mensagem (que após análise da mensagem poderiam ser descartados/ignorados). Com o um buffer auxiliar de recepção maior que a mensagem, o acerto do timeout resolve a situação :wink: .

1 Like

Excelente . Obrigado tinyelectr ! O seu código me ajudou muito !!!

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.