Relógio digital no Arduino usando uma máquina de estado finito
Componentes e suprimentos
![]() |
| × | 1 | |||
| × | 1 |
Aplicativos e serviços online
| ||||
|
Sobre este projeto
Ei,
Vou mostrar a você como um relógio digital pode ser criado com YAKINDU Statechart Tools e executado em um Arduino, que usa um teclado de LCD blindado.
O modelo original do relógio digital foi tirado de David Harel. Ele publicou um artigo sobre a "ampla extensão do formalismo convencional das máquinas e diagramas de estado".
Neste artigo, ele usou o exemplo do relógio digital para sua pesquisa. Eu o usei como inspiração e reconstruí o relógio com YAKINDU Statechart Tools (uma ferramenta para criar modelos gráficos de máquinas de estado e gerar código C / C ++ com ele) e o trouxe de volta à vida em um Arduino.
Como funciona o relógio digital
Vamos começar definindo como o relógio digital deve funcionar. Você se lembra desses ... digamos ... relógios digitais "ultra legais" que todo mundo tinha nos anos 90? Um cronômetro integrado, alarmes diferentes e seu bipe irritante a cada hora inteira. Se não, dê uma olhada:relógio digital dos anos 90.
Basicamente, é um relógio configurável com diferentes modos. Principalmente, a hora atual será exibida, mas existem alguns outros recursos. Como entrada, você tem um liga / desliga , um modo e um conjunto botão. Além disso, você pode ligar e desligar a luz.
Com o modo botão você pode distinguir entre os modos e ativar / desativar os recursos do relógio:
- Exibir a hora (relógio)
- Exibir a data (data)
- Defina o alarme (Alarme 1, Alarme 2)
- Ativar / desativar campainha (Definir campainha)
- Use o cronômetro (cronômetro)
Nos menus, você pode usar o liga / desliga botão para configurar o modo. O conjunto botão permite definir a hora - por exemplo, para o relógio ou os alarmes. O cronômetro pode ser controlado - iniciado e interrompido - usando o botão luz acesa e luz apagada. Você também pode usar um contador de voltas integrado.
Além disso, há um carrilhão, que toca a cada minuto, e uma luz de fundo controlável integrada. Na primeira etapa, não os conectei ao Arduino.
A máquina de estado






Não quero entrar em muitos detalhes para a explicação deste exemplo. Não é porque é muito complexo, é apenas um pouco grande. Vou tentar explicar a ideia básica de como funciona. A execução deve ser autoexplicativa, basta dar uma olhada no modelo ou fazer o download e simular. Algumas partes da máquina de estado são resumidas em sub-regiões, como o tempo definido região. Com isso, a legibilidade da máquina de estado deve ser garantida.
O modelo é dividido em duas partes - uma gráfica e uma textual. Na parte textual serão definidos os eventos, variáveis, etc. Na parte gráfica - o diagrama de estado - a execução lógica do modelo é especificada. Para criar uma máquina de estado que atenda ao comportamento especificado, alguns eventos de entrada são necessários, os quais podem ser usados no modelo: onoff , definir , modo , leve e light_r. Na seção de definição, um evento interno é usado, o que aumenta o valor de tempo a cada 100 ms:
a cada 100 ms / tempo + =1
Com base nas etapas de 100 ms, o tempo atual será calculado em HH:MM:SS formato:
display.first =(tempo / 36000)% 24;
display.second =(tempo / 600)% 60;
display.third =(tempo / 10)% 60;
Os valores serão conectados ao display LCD usando a operação updateLCD toda vez que a máquina de estado for chamada:
display.updateLCD (display.first, display.second, display.third, display.text)
A execução básica da máquina de estados já está definida na seção Como funciona o Digital Watch . Dentro da ferramenta, usei alguns elementos de modelagem "especiais" como CompositeState , História , Subdiagramas , ExitNodes, etc. Uma descrição detalhada pode ser encontrada no Guia do Usuário.
Escudo do teclado LCD
O escudo do teclado LCD é muito bom para projetos simples, que requerem uma tela para visualização e alguns botões como entrada - uma típica e simples IHM (Interface Homem-Máquina). O escudo do teclado LCD contém cinco botões de usuário e outro para reinicialização. Os cinco botões juntos são conectados ao pino A0 do Arduino. Cada um deles está conectado a um divisor de tensão, que permite distinguir entre os botões.
Você pode usar analogRead (0) para encontrar os valores específicos, que podem variar de acordo com o fabricante. Este projeto simples exibe o valor atual no LCD:
#include
#include
LiquidCrystal lcd (8, 9, 4, 5, 6, 7);
void setup () {
lcd.begin (16, 2);
lcd.setCursor (0,0);
lcd.write ("Valor medido");
}
void loop () {
lcd.setCursor (0,1);
lcd.print ("");
lcd. setCursor (0,1);
lcd.print (analogRead (0));
atraso (200);
}
Estes são os meus resultados medidos:
- Nenhum:1023
- Selecione:640
- Esquerda:411
- Para baixo:257
- Até:100
- Certo:0

Com esses limites, é possível ler os botões:
#define NENHUM 0
#define SELECCIONE 1
#define ESQUERDA 2
#define BAIXO 3
#define UP 4
#define DIREITO 5
static int readButton () {
int result =0;
result =analogRead (0);
if (result <50) {
return RIGHT;
}
if (resultado <150) {
retornar PARA CIMA;
}
if (resultado <300) {
retornar PARA BAIXO;
}
if (resultado <550) {
retornar ESQUERDA;
}
if (resultado <850) {
retornar SELECT;
}
retornar NENHUM;
}
Interface da máquina de estado
O código C ++ gerado da máquina de estado fornece interfaces, que devem ser implementadas para controlar a máquina de estado. O primeiro passo é conectar os eventos de entrada com as teclas do escudo do teclado. Já mostrei como ler os botões, mas para fazer a interface deles com a máquina de estado, é necessário eliminar os botões - caso contrário, os eventos seriam disparados várias vezes, o que resulta em um comportamento imprevisível. O conceito de depuração de software não é novo. Você pode dar uma olhada na documentação do Arduino.
Na minha implementação, detectei uma borda descendente (soltando o botão). Eu li o valor do botão, esperei 80 ms (obtive melhores resultados com 80 em vez de 50), salvei o resultado e li o novo valor. Se o oldResult não era NENHUM (não comprimido) e o novo resultado é NENHUM , Eu sei, que o botão foi pressionado antes e agora foi liberado. Então, eu aumento o evento de entrada correspondente da máquina de estado.
int oldState =NONE;
static void raiseEvents () {
int buttonPressed =readButton ();
delay (80);
oldState =buttonPressed;
if (oldState! =NONE &&readButton () ==NONE) {
switch (oldState) {
case SELECT:{
stateMachine-> getSCI_Button () -> raise_mode ();
break;
}
case LEFT:{
stateMachine-> getSCI_Button () -> raise_set ();
break;
}
case DOWN:{
stateMachine-> getSCI_Button () -> raise_light ();
break;
}
case UP:{
stateMachine-> getSCI_Button () -> raise_light_r ();
break;
}
case RIGHT:{
stateMachine-> getSCI_Button () -> raise_onoff ();
break;
}
padrão:{
break;
}
}
}
}
Conectando as coisas
O programa principal usa três partes:
- A máquina de estado
- Um cronômetro
- Um manipulador de exibição (típico lcd.print (...))
DigitalWatch * stateMachine =new DigitalWatch ();
CPPTimerInterface * timer_sct =new CPPTimerInterface ();
DisplayHandler * displayHandler =new DisplayHandler ();
A máquina de estado usa um manipulador de display e tem um cronômetro, que será atualizado para controlar os eventos cronometrados. Depois disso, a máquina de estado é inicializada e inserida.
void setup () {
stateMachine-> setSCI_Display_OCB (displayHandler);
stateMachine-> setTimer (timer_sct);
stateMachine-> init ();
stateMachine-> enter ();
}
O loop faz três coisas:
- Gerar eventos de entrada
- Calcule o tempo decorrido e atualize o cronômetro
- Ligue para a máquina de estado
long current_time =0;
long last_cycle_time =0;
void loop () {
raiseEvents ();
last_cycle_time =current_time;
current_time =millis ();
timer_sct-> updateActiveTimer (stateMachine,
current_time - last_cycle_time);
stateMachine-> runCycle ();
}
Obtenha o exemplo
É isso. Provavelmente, não mencionei todos os detalhes da implementação, mas você pode dar uma olhada no exemplo ou deixar um comentário.
Adicione o exemplo a um IDE em execução com:
Arquivo -> Novo -> Exemplo -> Exemplos de gráfico de estado YAKINDU -> Próximo -> Arduino - Relógio digital (C ++)
>> Você pode baixar o IDE aqui <<
Você pode começar com um teste de 30 dias. Depois disso, você deve obter uma licença, que é gratuita para uso não comercial !
Processo de manufatura
- Máquinas de estado finito
- Faça Monitor Ambilight usando Arduino
- Dados digitais Arduino
- Máquina de LEVITAÇÃO ULTRASÔNICA Usando ARDUINO
- Faça você mesmo voltímetro usando Arduino e Smartphone
- Monitor de freqüência cardíaca usando IoT
- WebServerBlink usando Arduino Uno WiFi
- Arduino Tamagotchi Clone - Animal de estimação digital
- Arduino Apple Watch
- Jogo Dino automatizado usando arduino