Como percorrer dados obtidos da serial?

Olá pessoal, tudo bom?

Preciso ler dados da serial e compara-los com um padrão (protocolo).
Não tenho muita experiência, então não sei se é melhor criar uma string de entrada e depois fazer a comparação ou fazer uma rotina para tratar cada byte recebido sem montar uma string.

Para começar fiz o seguinte código tentando jogar os bytes lidos da serial numa string:

const int N = 10;
char inMsg[N];

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if(Serial.available() > 0)
  {
    int i = 0;
    while((Serial.available() > 0) && (i < N))
    {
      inMsg[i] = Serial.read();
      ++i;
    }
    
    // teste: imprime array para verificar o conteudo
    imprimeMsg();
  }
}

void imprimeMsg()
{
  int i = 0;
  //for(i = 0; i < (sizeof(inMsg) / sizeof(char)); i++)
  for(i = 0; i < N; i++)
    {
      Serial.print("inMsg[");
      Serial.print(i);
      Serial.print("] = ");
      Serial.println(inMsg[i]);
    }
}

O problema é que no teste, enviando a string '0123456789', tem ocorrido o seguinte:

inMsg[0] = 0
inMsg[1] = \0x00
inMsg[2] = \0x00
inMsg[3] = \0x00
inMsg[4] = \0x00
inMsg[5] = \0x00
inMsg[6] = \0x00
inMsg[7] = \0x00
inMsg[8] = \0x00
inMsg[9] = \0x00
inMsg[0] = 1
inMsg[1] = 2
inMsg[2] = 3
inMsg[3] = 4
inMsg[4] = 5
inMsg[5] = 6
inMsg[6] = 7
inMsg[7] = 8
inMsg[8] = 9
inMsg[9] =

Ou seja, ao invés de montar uma string com todos os bytes está sendo criada uma nova string após o primeiro byte lido da serial.

Obs: ainda falta fazer a rotina do protocolo, mas primeiro preciso garantir que estou obtendo os bytes corretamente.

Alguem tem ideia de como fazer?

Espero que possam ajudar.
Abs.

Experimenta isto:

const int N = 10;
char inMsg[N+1];

void setup()
{
  Serial.begin(9600);
  inMsg[N] = 0;
}

void loop()
{
  if(Serial.available() >= 10)
  {
    int i = 0;
    while(( i < 10))
    {
      inMsg[i++] = Serial.read();
      
    }
    
    // teste: imprime array para verificar o conteudo
    imprimeMsg();
  }
}

void imprimeMsg(){
    Serial.println(inMsg);
    
}

A tua funcão imprime mensagem está errada... certamente que se correres isto várias vezes vais obter resultados diferentes...

O problema ocorre quando fazes isto:

i < (sizeof(inMsg) / sizeof(char))

sizeof(inMsg) é igual a 10... sizeof(char) é sempre igual a 1...

Quando recebes algo na porta série, o if passa a ser válido... mas se só recebeste um valor, para que vais tentar imprimir os valores todos?

Ola bubulindo,

Obrigado por responder.
Seu código deu certo. Mas a função imprimeMsg() deve percorrer o array de caracteres (string) para verificar se cada índice possui conteúdo válido.
Por exemplo, se eu mandar 123 pela serial, inMsg deve ficar assim:
inMsg[0] = 1
inMsg[1] = 2
inMsg[2] = 3
inMsg[3] =
inMsg[4] =
...

Desta forma eu poderei comparar se corresponde com o protocolo que irei utilizar.

Abs.

Da maneira que está, funciona se mudares a imprimeMsg para o que estava. O que tens de ter em atenção é não imprimires o que ainda não recebeste

Entendi.
Obrigado pela ajuda :wink:

abs

Aproveitando o tópico, gostaria de tirar mais uma duvida:

  • Como percorrer um array de caracteres sem saber o seu tamanho?

Tentei desta forma:

for(i = 0; i < (sizeof(inMsg) / sizeof(char)); i++)

Porem desta forma não funciona, iterando apenas duas vezes.

Verifiquei que o Arduino trata um 'char array' diferentemente do C.

Em C:
sizeof(char) = 1 byte
char str[10]; sizeof(str) = 10 bytes

Arduino:
sizeof(char) = 1 byte
char str[10]; sizeof(str) = 2 bytes

Como assim?

Experimenta isto

char str_1[] = "hello";
char str_2[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
char str_3[10];

void setup() {

char str_1_local[] = "hello";
char str_2_local[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
char str_3_local[10];

Serial.println("These are the external arrays:");
Serial.print("str_1");
Serial.println(sizeof(str_1));
Serial.print("str_2");
Serial.println(sizeof(str_2));
Serial.print("str_3");
Serial.println(sizeof(str_3));

Serial.println("These are the local arrays:");
Serial.print("str_1");
Serial.println(sizeof(str_1_local));
Serial.print("str_2");
Serial.println(sizeof(str_2_local));
Serial.print("str_3");
Serial.println(sizeof(str_3_local));

}

void loop() {}

Eu suspeito que tem a ver com o facto de todo o código do Arduino correr dentro duma funcão (setup ou loop) e não directamente na main. Nada como experimentar esse código em cima e ver as diferencas. Outra coisa que convém teres em atencão tem a ver com o facto que o compilador para AVR pode ou não obedecer às convencões do C para computadores e não sabes exactamente as opcões de optimizacão que activaram no compilador. Tudo isso são possibilidades para explicar isto.

Isto é uma maneira de passar esse problema. Também podes usar um string terminator e percorrer a string até o encontrar. Normalmente usa-se '\0'.

#define ARRAY_SIZE   10
char array[ARRAY_SIZE];
unsigned char chars_in_array = 0;


array[chars_in_array++] = Serial.read();


for (i = 0; i< chars_in_array; i++) {
  Serial.println(array[i]);
}

Algo assim...

Edit:

No site tinha isto:

Note that sizeof returns the total number of bytes. So for larger variable types such as ints, the for loop would look something like this. Note also that a properly formatted string ends with the NULL symbol, which has ASCII value 0.

Logo parece-me que o sizeof vai procurar por um \0 para retornar um valor.

O exemplo que postei... retornou isto:

These are the external arrays:
str_1 = 6
str_2 = 6
str_3 = 10
These are the local arrays:
str_1 = 6
str_2 = 6
str_3 = 10

Queres meter o código que usaste?

Olá bubulindo,

Testei o seu código e obtive o mesmo resultado. Que está correto.

Só não entendi o porque eu estava obtendo um tamanho errado do array de caracteres.
Mas pelo menos está funcionando :wink:

Obrigado pela ajuda!

Provavelmente porque passaste o array para dentro de uma função? Nesse caso, o array é convertido para apontador.

Tens o código completo que usaste para testar? Agora estou curioso.