Arduino – Entendendo e usando o serialEvent()

Acredito que todo mundo que usou e programou um Arduino pelo menos para um teste simples já enviou/recebeu dados pela serial, certo? Algo muito simples e trivial de fazer até com exemplos prontos na própria IDE Arduino.

Um modelo basico deste tipo de aplicação seria este.

O código acima foi baseado no exemplo do próprio site do Arduino[link] com algumas pequenas modificações, mas a ideia é um if() ou um while() dentro do loop principal sempre verificando se tem algo no buffer de recepção da serial, porém, a aplicação ganhando forma e conteúdo, e agregando mais maquinas de estados.

Dependendo da quantidade ou o tempo para percorrer um loop inteiro, esta forma de atender a recepção da serial pode não ser eficiente e também não é aplicado a fins profissionais.

E é nessas horas que podemos usar serialEvent()[link], ele é chamado sempre antes de cada interação do loop caso algum byte tenha sido recebido pela serial, sua definição pode ser vista facilmente no arquivo hardware/arduino/cores/arduino/HardwareSerial.cpp

 

É importante observar que as declarações do serialEvent() não estão dentro do ISR(), ou seja, a função não é chamada na interrupção da recepção dos dados da serial, e sim apenas o buffer da serial é preenchido e logo abaixo o serialEventRun() possui a  chamada da função, caso existir byte(s) no buffer, e neste mesmo arquivo podemos ver que o buffer de recepção no caso do Arduino é 64 bytes, olhando para o define SERIAL_BUFFER_SIZE.

Certo, mas como o serialEvent() é chamado? Se ele é executado antes de cada interação do loop(). Para responder a esta pergunta vamos ver a estrutura do setup() e loop(), acessando o arquivo hardware/arduino/cores/arduino/main.cpp

 

A resposta para a nossa pergunta esta na linha 14 e 15, certo? Beleza, conseguimos ver como funciona nosso serialEvent() e ficamos tranquilo que ele não esta dentro do ISR(), :) certo? Porém, o que é aquele __attribute__((weak))[link] no “void serialEvent() __attribute__((weak)), __attribute__((  )) é usado quando queremos passar algum atributo especial em variáveis, funções ou tipos, para agregar melhor a verificação de erros do compilador ou na otimização.

Neste caso, o (weak) durante o processo de linker do objeto, faz-se um link com simbolo fraco para a função serialEvent(), dizendo que ela esta definida na biblioteca porém poderá ser sobrescrita no arquivo do usuário, no caso no projeto do Arduino, sem este (weak) com certeza receberíamos um erro de “undefined reference to serialEvent“, mais detalhes e outros atributos veja em GCC 4.9.2 – Declaring Attributes of Functions[link].

Sim é um assunto complexo e que merece atenção, irei escrever sobre __attribute__ e como analisar os objetos gerados para melhor compreensão destes símbolos.

Agora um exemplo com o serialEvent().

 

A aplicação acima foi baseada no exemplo do site do Arduino[link], vamos comunicar com nossa aplicação pelo Monitor Serial do Arduino e ver a saída.

 

Na saída acima, um loop ficara a cada 500ms dando echo com um :) e eu enviei algumas coisas como ARDUINO, OK e 2015.

Espero que tenham gostado desta dica, e de garimbar os arquivos da IDE do Arduino e como podemos percebemos, da para aprender muito com isso, conhecendo com as coisas são implementadas por trás da IDE.

Até a próxima!

 

Referências

http://arduino.cc/en/Serial/Read

http://arduino.cc/en/Tutorial/SerialEvent

https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/Function-Attributes.html#Function-Attributes

http://www.keil.com/support/man/docs/armccref/armccref_Cacdgifc.htm

Share Button

CC BY-NC-SA 4.0 Arduino – Entendendo e usando o serialEvent() by Cleiton Bueno is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

  • André De Pádua Reis

    Ela é sempre chamada quando tem um evento na serial certo ?!
    se sim por que usar o while ?
    ou ela funciona como uma trhead ?
    abraço

    • O While abaixo server para que enquanto estiver dados no buffer da serial ele irá processar e só sair quando terminar. Sim, o mais eficiente é inserir no buffer e depois em um maquina de estados tratar esse cara, sem “prender” o uso da CPU para isso.

  • Josemar

    Ótimo artigo Cleiton, com certeza vou usar nos meus projetos com Arduíno. Parabéns.

    • Legal que gostou do artigo Josemar, e que bom que irá ajuda-lo ;)
      Abraço.