2.1 Adaptações para projeto Arduino
Antes de começar a editar o código, temos que modificar a estrutura do projeto para adequar ao padrão do Arduino.
Essencialmente, necessitamos que o arquivo principal (main.c
) tenha o mesmo nome do diretório no qual está contido (alarme
) e deve ter a extensão .ino
.
Para tal, siga os seguintes passos:
- mova todos os arquivos da pasta
src
para a pasta raiz (alarme
); - renomeie o arquivo
main.c
paraalarme.ino
; e - altere as extensões de todos os arquivos
.c
para.cpp
.
Esta última etapa é necessária pois um sketch Arduino adota a linguagem C++, cuja extensão dos arquivos de código fonte é .cpp
.
Por fim, vamos remover os arquivos Makefile
, sensores.h
, sensores.c
, zonas.h
e zonas.c
, que não serão utilizados.
Não deixe de remover as diretivas #include "sensores.h"
e #include "zonas.h"
do arquivo alarme.ino
. Ao final, a estrutura do seu projeto deve ser:
📦alarme
┣ 📜.gitignore
┣ 📜alarme.ino
┣ 📜comunicacao.cpp
┣ 📜comunicacao.h
┣ 📜definicoes_sistema.h
┣ 📜ihm.cpp
┣ 📜ihm.h
┣ 📜README.md
┣ 📜senhas.cpp
┣ 📜senhas.h
┣ 📜sirene.cpp
┣ 📜sirene.h
┣ 📜state_machine.svg
┣ 📜timer.cpp
┗ 📜timer.h
2.2 Substituindo as chamadas de funções da biblioteca padrão de C
No Arduino, não temos as funcionalidades necessárias para realizar as funções printf
e scanf
, que escreve na tela e lê entradas do teclado, respectivamente. Vamos substituir estas funções pelas de comunicação serial do Arduino.
No caso do printf
, basta utilizar o método Serial.print
ou Serial.println
.
No entanto, estes não suportam especificadores de formato.
Uma solução é fazer múltiplas chamadas; sendo assim, o código
printf("Estado: %d Evento: %d Acao:%d\n", estado, codigoEvento, codigoAcao);
pode ser substituído por
Serial.print("Estado: ");
Serial.print(estado);
Serial.print(" Evento: ");
Serial.print(codigoEvento);
Serial.print(" Acao: ");
Serial.println(codigoAcao);
Também é necessário substituir os headers stdio.h
e stdlib.h
por (Arduino.h
).
Por exemplo, o arquivo comunicacao.cpp
deve ficar:
#include <Arduino.h>
#include "definicoes_sistema.h"
#include "comunicacao.h"
/************************
com_notificar
Envia mensagem para a Central
entradas
texto : texto para envio para Central
saidas
nenhuma
*************************/
void com_notificar(char* texto)
{
Serial.print("Comunicacao com a Central: ");
Serial.println(texto);
}
Por fim, é necessário inicializar a comunicação serial na função setup()
do alarme.ino
, como no exemplo do capítulo 1.
2.3 Adaptação dos componentes ihm e Timer
Os eventos serão gerados a partir do recebimento de mensagens via serial.
Assim, a função ihm_obterTeclas
do componente ihm pode ser modificado para
...
/************************
ihm_obterTecla
Obtem tecla do teclado
entradas
nenhuma
saidas
teclas lidas do teclado
*************************/
char* ihm_obterTeclas()
{
// Serial.print("obter teclas:");
int read_count = 0;
// check for input
if (Serial.available() > 0) {
// read the incoming bytes:
read_count = Serial.readBytesUntil('\n',buf, sizeof(buf)/sizeof(buf[0]) - 1);
}
buf[read_count] = '\0';
if(read_count > 0) {
Serial.println(buf);
}
return buf;
}
}
Vamos implementar o componente timer utilizando o relógio do próprio Arduino.
Assim, o arquivo timer.cpp
deve ser modificado para
#include <Arduino.h>
#include "definicoes_sistema.h"
#include "timer.h"
#define TEMPO 10
int tmr_situacao = false;
unsigned long horaInicio;
/*******************************
tmr_iniciar
Aciona ou desaciona o timer
entradas
controle: TRUE:liga FALSE:desliga
saidas
nenhuma
********************************/
void tmr_iniciar(int controle)
{
tmr_situacao = controle;
if (controle)
{
horaInicio = millis();
}
}
/*******************************
tmr_timeout
Retorna se o timer esta em timeout.
entradas
nenhuma
saidas
FALSE: nao houve estouro do temporizador
TRUE: houve estouro do temporizador
********************************/
int tmr_timeout()
{
if (tmr_situacao == false)
{
return false;
}
if(millis() - horaInicio > TEMPO*1000)
{
return true;
}
return false;
}
2.4 Reestruturação do código para setup e loop
Agora vamos trabalhar no arquivo principal, o alarme.ino
.
Analisando a função main
, podemos separá-la em inicialização e operação, que ocorre dentro de um loop while
infinito.
Inicialmente, vamos mover a inicialização das variáveis simples para o escopo global, ou seja, fora da função main
, escreva
...
/***********************************************************************
Estaticos
***********************************************************************/
int codigoEvento = NENHUM_EVENTO;
int eventoInterno = NENHUM_EVENTO;
int estado = ESPERA;
...
Assim, a nossa função setup
deve ficar:
void setup() {
Serial.begin(9600);
iniciaSistema();
Serial.println("Alarme iniciado");
} // setup
Depois, devemos mover o loop infinito para a função loop
:
void loop() {
if (eventoInterno == NENHUM_EVENTO) {
codigoEvento = obterEvento();
} else {
codigoEvento = eventoInterno;
}
if (codigoEvento != NENHUM_EVENTO)
{
codigoAcao = obterAcao(estado, codigoEvento);
estado = obterProximoEstado(estado, codigoEvento);
eventoInterno = executarAcao(codigoAcao);
Serial.print("Estado: ");
Serial.print(estado);
Serial.print(" Evento: ");
Serial.print(codigoEvento);
Serial.print(" Acao: ");
Serial.println(codigoAcao);
}
} // loop
Com isso, finalizamos a nossa aplicação de alarme. Para testar, compile e faça o upload para o Arduino; sua operação pode ser realizada totalmente pelo monitor serial do Arduino IDE.
No caso de dúvidas, o código final da aplicação pode ser consultado em
https://gitlab.uspdigital.usp.br/andre.kubagawa/alarme_arduino/-/tree/master/alarme_basico
2.5 Código final completo no Tinkercad
O Tinkercad possui a limitação de apenas um arquivo de código fonte. Isto significa que temos que juntar todos os arquivos do projeto do alarme.
No repositório foi incluído um script Python que faz a conversão automática dos projetos de alarme:
https://gitlab.uspdigital.usp.br/andre.kubagawa/alarme_arduino/-/blob/master/ino2Tinkercad.py
para usá-lo, é necessário executar o seguinte comando a partir da pasta do projeto:
python ..\ino2Tinkercad.py alarme.ino -o ../alarme_tinkercad.ino
Depois copie e cole o conteúdo de alarme_tinkercad.ino
para o seu circuito no Tinkercad.
O código final pode ser obtido em:
https://gitlab.uspdigital.usp.br/-/snippets/17
2.6 Adicionando um buzzer piezoelétrico
Para deixar nossa aplicação um pouco mais interessante, vamos adicionar um buzzer para simular a sirene do nosso alarme. Primeiro, crie o seguinte circuito:
Depois, declare uma nova função do componente sirene em sirene.h
:
...
/************************
sne_setup
Configura a sirene
entradas
pin: pino do buzzer
saidas
nenhuma
*************************/
extern void sne_setup(int pin);
..
e modifique as suas definições em sirene.cpp
:
#include <Arduino.h>
#include "definicoes_sistema.h"
#include "sirene.h"
#define TONE_FREQ 1000
#define BEEP_TIME 100
int sne_pin;
/************************
sne_setup
Configura a sirene
entradas
pin: pino do buzzer
saidas
nenhuma
*************************/
void sne_setup(int pin)
{
sne_pin = pin;
pinMode(sne_pin, OUTPUT);
}
/************************
sne_bip
Aciona momentaneamente a sirene
entradas
nenhuma
saidas
nenhuma
*************************/
void sne_bip()
{
tone(sne_pin, TONE_FREQ, BEEP_TIME);
}
/************************
sne_acionar
Aciona ou desaciona a sirene
entradas
controle: TRUE:ligar FALSE:desligar
saidas
nenhuma
*************************/
void sne_acionar(int controle)
{
if(controle)
tone(sne_pin, TONE_FREQ);
else
noTone(sne_pin);
}
Por fim, no arquivo .ino
principal, insira a chamada para a função sne_setup()
dentro de setup
:
void setup()
{
sne_setup();
Serial.begin(9600);
Serial.println("Maquina de estados iniciada");
}
Agora, ao acionar o alarme, o buzzer deve gerar um beep curto; e quando o alarme for disparado, o buzzer deve emitir um som contínuo.
Bibliografia para este capítulo
- Documentação da linguagem do Arduino: https://www.arduino.cc/reference/en/
- Código fonte original do alarme: https://gitlab.uspdigital.usp.br/andre.kubagawa/alarme
- Código fonte do alarme no Arduino: https://gitlab.uspdigital.usp.br/andre.kubagawa/alarme_arduino/-/tree/master/alarme_basico