Duvida sobre a Serial.available

Saudações pessoas! É a minha primeira publicação no fórum, me desculpe se estou cometendo algum erro ao produzir esse tópico.

Em uma breve busca pelo fórum não encontrei solução a minha dúvida, que é a seguinte: estava desenvolvendo um projeto com o registrador de deslocamento 74hc595n, quando me deparei com os operadores bit-a-bit e então resolvi dar uma pausa no projeto e entender melhor como os mesmos funcionam.

Daí me veio a ideia de criar um sketch que pudesse me auxiliar no entendimento. Nesse sketch, gostaria de receber um valor pela porta Serial e imprimir esse valor em decimal, binário e hexadecimal. Porém percebi que quando o valor é recebido pela Serial, em vez do número decimal, o arduino le o codigo ASCII desse valor, ou seja, se eu envio 1 pela Serial é imprimido na tela o valor 48 em vez do numero 1 . E se a porta le um número com 2 casas decimais por exemplo 15, é enviado 48 que representa o 1 e depois 53 que representa 5. Espero que não tenha ficado muito confuso e desde já agradeço a compreensão.


// Operações bit a bit

void setup() {

  Serial.begin(9600);

}

void loop() {


  if (Serial.available() > 0)
  {
    
    int x = int(Serial.read());

    int y = x >> 4; //desloca 4 posições para a direita em x

    Serial.print("Valor de x em decimal: ");
    Serial.println(x); 

    Serial.print("Valor de x em binário: ");
    Serial.println(x, BIN); // imprime o valor de x em binario

    Serial.print("Valor de x em hexadecimal: ");
    Serial.println(x, HEX); // imprime o valor de x em hexadecimal

    Serial.println();

    Serial.print("Valor de y deslocado 4 casas para a direita: ");
    Serial.println(y);

    Serial.print("Valor de y em binário: ");
    Serial.println(y, BIN); // imprime o valor de x em binario

    Serial.print("Valor de y em hexadecimal: ");
    Serial.println(y, HEX); // imprime o valor de x em hexadecimal

    Serial.println();


  }
}

Boa noite @moreiralexandre
É isto mesmo, você está correto.
O serial recebe no formato caracter.

RV mineirn

Olá,

A função Serial.read() obtém o primeiro byte do buffer de recepção da UART. Depois, ao ser usada novamente obtém os bytes seguintes (se existirem mais...). O byte é obtido tal como foi enviado. Como o terminal série envia caracteres ASCII, é isso que é visualizado.

Podes processar e validar a informação obtida byte a byte e formar o valor pretendido, ou então, neste caso, se é só para obter um valor inteiro podes usar a função Serial.parseInt().

Esta função processa os dados no buffer de recepção durante um determinado tempo. Por omissão 1 segundo. Para diminuíres este timeout podes usar a função Serial.setTimeout(). Coloco o teu código usando o Serial.parseInt() com um timeout de 50 ms.


// Operações bit a bit

void setup() {
  Serial.begin(9600);
  Serial.setTimeout(50); // 50 ms de timeout para a função Serial.parseInt().
}

void loop() {

  if (Serial.available() > 0) {

    //int x = int(Serial.read());
    long x = Serial.parseInt(SKIP_ALL, '\n');

    //int y = x >> 4; //desloca 4 posições para a direita em x
    long y = x >> 4; //desloca 4 posições para a direita em x

    Serial.println("----------------------------------");

    Serial.print("Valor de x em decimal: ");
    Serial.println(x); 

    Serial.print("Valor de x em binário: ");
    Serial.println(x, BIN); // imprime o valor de x em binario

    Serial.print("Valor de x em hexadecimal: ");
    Serial.println(x, HEX); // imprime o valor de x em hexadecimal

    Serial.println();

    Serial.print("Valor de y deslocado 4 casas para a direita: ");
    Serial.println(y);

    Serial.print("Valor de y em binário: ");
    Serial.println(y, BIN); // imprime o valor de x em binario

    Serial.print("Valor de y em hexadecimal: ");
    Serial.println(y, HEX); // imprime o valor de x em hexadecimal

    Serial.println();
  }
}

@ruilviana @tinyelectr muito obrigado pelas respostas!

Perfeito @tinyelectr , o seu código faz exatamente o que eu gostaria. Pesquisei a respeito das funções utilizadas e ficou claro, só não entendi os parâmetros da função

Vi no exemplo da documentação que também é usado:

Serial.parseInt(char skipChar)

esse parâmetro ignora pontos, virgulas e caracteres especiais em geral?

Sim, a função Serial.parseInt() usada sem qualquer parâmetro ignora tudo excepto os dígitos e o sinal de menos '-'. Ou seja, por omissão no primeiro parâmetro usa o SKIP_ALL.

Eu aí nesse exemplo coloquei explicitamente o SKIP_ALL porque queria introduzir o segundo parâmetro. O segundo parâmetro serve para indicar que pretendemos ignorar um caracter específico. Neste caso, serve para ignorar o NewLine '\n', caso contrário no loop seguinte irá encontrar o NewLine no buffer e processa-o apresentando zero (pois não há outros dígitos).

Outra forma de evitar o NewLine seria configurar o terminal com "No Line Ending" em vez de "New Line".

Show! Eu não uso o nova linha e nem o retorno de carro, mas me surgiu uma duvida.. como ficaria se eu precisasse ignorar dois ou mais caracteres?

A função Serial.parseInt() por omissão já ignora tudo excepto dígitos e o sinal '-'. A função termina sempre que encontra um caracter que não faça parte dos dígitos. Neste caso, como a função está num loop infinito, se colocares vários dígitos misturados com quaisquer outros caracteres a função vai processar separadamente cada conjunto de dígitos no buffer de recepção.

Por exemplo, se testares o programa com a string "aa a123,321.555-444bb b" podes observar no terminal o processamento de 5 números diferentes nessa string: 123, 321, 555, -444 e o zero (o último é o zero, porque a seguir ao -444 existem caracteres, mas nenhum deles é um dígito).

O segundo parâmetro opcional do Serial.parseInt(), o "ignore", é especialmente adequado para processar números com separador de milhares (geralmente um ponto OU uma vírgula, mas não ambos), ou outro caracter entre os dígitos. Aqui neste caso eu usei-o com o '\n' porque normalmente o NewLine é enviado pelo terminal e eu não queria que a função processasse o NewLine como sendo um segundo conjunto de caracteres sem dígitos, resultando no zero.

Caso os teus conjuntos de dígitos contenham no seu interior mais do que um caracter que deva ser ignorado o melhor será desenvolver uma função específica utilizando o Serial.read() para processar/validar caracter a caracter.

Por exemplo, imaginemos que a string "198,765.432_1" tem de resultar no número 1987654321, nesse caso seria necessário ignorar mais do que um caracter no interior dos dígitos: a vírgula ',', o ponto '.' e o underscore '_'. Se a string tiver sempre esse formato uma opção será chamar o Serial.parseInt() quatro vezes e multiplicar e adicionar os valores parciais (out1x10000000+out2x10000+out3x10+out4, no exemplo: 198x10000000+765x10000+432x10+1), outra opção será usar o Serial.read() para processar/validar caracter a caracter.

Nada como testar a função com múltiplas strings de teste para ver no que resulta :wink: .

Eu uso bastante o monitor serial pra testar os meus códigos, tentei incluir mais de um carácter no segundo parâmetro e não deu certo, então imaginei que uma possível solução seria chamar a Serial.parseInt()mais de uma vez, agora ficou bem claro! :sweat_smile:

Mais uma vez muito obrigado, de agora em diante vou estar mais presente na comunidade!

Avante! :facepunch: