
Passo 1 de 8
Definir o comportamento antes do código
Planeje a sinalização como estados distintos antes de traduzi-la para o firmware.
Trilha de aprendizado · Nível 10 · Tutorial 3
Implementar uma sequência de sinalização acionada por botão usando estados e transições temporizadas, sem interromper o atendimento das entradas.
Definir o comportamento antes do código
Planeje a sinalização como estados distintos antes de traduzi-la para o firmware. 2 min
Separar estado, evento e marca de entrada
Diferencie a memória da máquina, o estado estável do botão, o evento momentâneo e a marca temporal que acompanharão a sinalização. 2 min
Traduzir a tabela para enum e switch
Transforme os estados da tabela em nomes de código e organize a seleção com enum, switch, case, break e default. 2 min
Executar a ação de entrada uma única vez
Centralize os efeitos de uma mudança de estado para que sejam executados apenas na entrada. 2 min
Avançar por tempo sem bloquear o loop
Use a marca de entrada de cada estado para avançar pelos pulsos e pela pausa sem bloquear o loop. 2 min
Definir a prioridade do cancelamento
Defina a prioridade do pressionamento aceito sobre o vencimento do intervalo para garantir uma única transição por atualização da máquina. 2 min
Integrar entrada, máquina e saída
Integre o evento de botão tratado por rebote à máquina de estados e execute a sequência no Uno R3 próprio. 2 min
Aplicar e verificar a sequência completa
Verifique a sinalização no Uno R3, teste cancelamentos e confirme por rastreamento a prioridade entre evento e prazo. 4 min

Passo 1 de 8
Planeje a sinalização como estados distintos antes de traduzi-la para o firmware.
Um pressionamento aceito do botão inicia uma sinalização no LED integrado: ele acende por 1000 ms, apaga por 500 ms e acende novamente por 1000 ms. Ao fim, volta a ficar apagado.
Durante essa sequência, um novo pressionamento aceito cancela a sinalização e leva a aplicação de volta ao repouso. Manter o botão pressionado não cria comandos adicionais; a soltura também não muda diretamente a sequência.

A sequência avança pelo tempo; um novo pressionamento durante uma etapa ativa a cancela.
A tabela é a especificação antes do código. Ela separa o que o LED mostra da situação em que a aplicação está.
| Estado atual | LED | Permanece até | Próximo estado |
|---|---|---|---|
| REPOUSO | Apagado | Pressionamento aceito | PRIMEIRO_PULSO |
| PRIMEIRO_PULSO | Aceso | 1000 ms ou pressionamento | PAUSA ou REPOUSO |
| PAUSA | Apagado | 500 ms ou pressionamento | SEGUNDO_PULSO ou REPOUSO |
| SEGUNDO_PULSO | Aceso | 1000 ms ou pressionamento | REPOUSO |
Observe que REPOUSO e PAUSA deixam o LED apagado, mas não são o mesmo estado.
Portanto, a saída sozinha não informa o comportamento seguinte. A aplicação precisa guardar em qual etapa está, mesmo quando duas etapas comandam a mesma saída.
Dica
Não use o nível mantido do botão como se fosse vários comandos. Um pressionamento aceito é um acontecimento único: depois de ser usado para iniciar ou cancelar, continuar segurando o botão não reinicia nem cancela novamente.
Associe cada estado à condição que determina seu avanço normal ou sua resposta ao pressionamento.
Toque em um item e depois no par correspondente.

Passo 2 de 8
Diferencie a memória da máquina, o estado estável do botão, o evento momentâneo e a marca temporal que acompanharão a sinalização.
A cada passagem por loop(), a máquina precisa saber em que etapa da sinalização está. Essa informação é o estado da aplicação e permanece armazenada entre passagens.
Por exemplo, depois que um pressionamento inicia a sequência, o estado pode continuar como PRIMEIRO_PULSO durante muitas passagens por loop(). Ele não deve voltar automaticamente a REPOUSO no início de cada passagem.
Isso é diferente de ler o botão: a leitura é renovada frequentemente; o estado da máquina registra a etapa que ainda está em execução.

O estado e a marca de entrada permanecem; o evento existe somente na passagem em que é detectado.
Para organizar a sequência, separe quatro informações que têm papéis diferentes:
REPOUSO ou PRIMEIRO_PULSO.millis() registrado quando a máquina entrou no estado atual.O estado estável do botão pode permanecer “pressionado” por bastante tempo. Já o evento de pressionamento deve ser breve: ele ocorre uma vez na transição estável de solto para pressionado.
Compare a duração e a função de cada informação.
| Informação | Duração típica | Para que serve |
|---|---|---|
| Estado da máquina | Várias passagens | Indicar a etapa atual |
| Evento de pressionamento | Uma passagem | Pedir uma ação uma vez |
| Marca de entrada | Enquanto o estado durar | Referenciar a entrada no estado |
| Estado estável do botão | Enquanto houver pressão | Representar o botão aceito |
Imagine que o botão já foi aceito pelo tratamento de rebote e permanece pressionado.
Na passagem em que foi aceito, eventoPressionou vale true e a máquina pode iniciar a sequência. Nas passagens seguintes, enquanto o botão continua pressionado, o estado estável ainda indica “pressionado”, mas eventoPressionou deve voltar a false.
Assim, o mesmo toque não vira vários comandos. A máquina permanece na etapa que iniciou até ocorrer uma transição prevista. A soltura, por si só, não muda a sequência desta aplicação.
O botão está estável como pressionado há várias passagens por loop(). O evento de pressionamento já iniciou a sequência na passagem anterior. Nesta passagem, o evento deve continuar verdadeiro para iniciar a sequência novamente.
A afirmação é verdadeira ou falsa?

Passo 3 de 8
Transforme os estados da tabela em nomes de código e organize a seleção com enum, switch, case, break e default.
A variável de estado guarda em que etapa a aplicação está entre uma passagem e outra de loop(). Em vez de números como 0, 1 e 2, use um enum: os nomes documentam o comportamento e reduzem trocas acidentais entre valores sem significado.
Os quatro nomes vêm diretamente da tabela já definida: REPOUSO, PRIMEIRO_PULSO, PAUSA e SEGUNDO_PULSO. A variável começa em REPOUSO e não deve ser declarada dentro de loop(), pois seria reinicializada a cada passagem.

Na ordem do ciclo: REPOUSO, PRIMEIRO_PULSO, PAUSA e SEGUNDO_PULSO. O desenho mostra que estados com LED apagado ainda podem ter papéis diferentes.
Use switch (estado) para traduzir cada linha da tabela em um case. Cada case contém somente as decisões válidas naquele estado.
A atribuição estado = PAUSA; altera a variável para as próximas passagens por loop(), mas não faz o switch voltar ao topo nesta mesma execução. Por isso, todo caso deve terminar em break: ele encerra a seleção atual e devolve o controle ao restante do programa.
Estrutura inicial da máquina. As condições temporizadas serão acrescentadas depois; aqui, observe como os nomes da tabela viram cases e como cada case é encerrado.
enum Estado {
REPOUSO,
PRIMEIRO_PULSO,
PAUSA,
SEGUNDO_PULSO
};
Estado estado = REPOUSO;
void atualizarMaquina(bool eventoPressionado) {
switch (estado) {
case REPOUSO:
if (eventoPressionado) {
estado = PRIMEIRO_PULSO;
}
break;
case PRIMEIRO_PULSO:
// A condição de tempo será incluída depois.
break;
case PAUSA:
// A condição de tempo será incluída depois.
break;
case SEGUNDO_PULSO:
// A condição de tempo será incluída depois.
break;
default:
estado = REPOUSO;
digitalWrite(LED_BUILTIN, LOW);
break;
}
}Dica
O default é o caminho definido quando estado não corresponde a nenhum case. Nesta aplicação, ele restabelece REPOUSO e comanda o LED apagado.
Isso define uma resposta coerente para um valor não reconhecido; não é uma promessa de proteger o firmware contra qualquer tipo de falha.
Complete a estrutura usando o nome do segundo estado, os encerramentos necessários e o caso para valor não reconhecido.
enum Estado {
REPOUSO,
,
PAUSA,
SEGUNDO_PULSO
};
switch (estado) {
case REPOUSO:
if (eventoPressionado) {
estado = PRIMEIRO_PULSO;
}
case PRIMEIRO_PULSO:
// Decisão temporal será incluída depois.
break;
estado = REPOUSO;
digitalWrite(LED_BUILTIN, LOW);
}
Passo 4 de 8
Centralize os efeitos de uma mudança de estado para que sejam executados apenas na entrada.
Uma passagem por loop() pode ocorrer muitas vezes enquanto a máquina continua no mesmo estado. Por isso, se o LED e a marca entradaEstado forem atualizados dentro do case a cada passagem, a ação de entrada será repetida sem que tenha havido transição.
Separe dois papéis:
Assim, a marca temporal permanece fixa durante a permanência. Nos próximos passos, ela servirá de referência para verificar os prazos sem bloquear o loop.

A transição concentra a alteração do estado, da marca de entrada e da saída. As passagens seguintes apenas avaliam condições.
Crie uma função para ser a única porta de mudança de estado. Ela recebe o próximo estado e o instante já observado na passagem atual. Primeiro, valida o destino; depois atualiza, em conjunto, o estado, a marca temporal e o LED.
O comando do LED não fica misturado à decisão de qual transição escolherá o próximo estado. Quem decide chama transicionarPara(...); a função aplica os efeitos da entrada.
Use esta função após as declarações do enum, de estado e de entradaEstado.
void transicionarPara(Estado proximo, unsigned long agora) {
switch (proximo) {
case REPOUSO:
case PRIMEIRO_PULSO:
case PAUSA:
case SEGUNDO_PULSO:
break;
default:
proximo = REPOUSO;
break;
}
estado = proximo;
entradaEstado = agora;
if (estado == PRIMEIRO_PULSO || estado == SEGUNDO_PULSO) {
digitalWrite(LED_BUILTIN, HIGH);
} else {
digitalWrite(LED_BUILTIN, LOW);
}
}Exemplo
Em cada case, chame a função somente quando a decisão realmente mudar o estado. Por exemplo, uma condição que inicia a sequência poderá chamar:
transicionarPara(PRIMEIRO_PULSO, agora);
Já o default do switch principal pode recuperar uma situação não reconhecida pela mesma porta:
default: transicionarPara(REPOUSO, agora); break;
Isso define LED apagado, estado REPOUSO e uma nova marca de entrada coerente. Não é uma proteção contra toda falha possível; é apenas o comportamento definido para esse caso.
A inicialização não deve esperar uma transição que ainda não aconteceu. Em setup(), estabeleça explicitamente a condição inicial:
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
estado = REPOUSO;
entradaEstado = millis();
digitalWrite(LED_BUILTIN, LOW);
}Complete a função de transição. As lacunas devem garantir que a marca é registrada e que o LED recebe o nível correspondente ao estado ativo ou inativo.
Preencha as ações que pertencem à entrada no novo estado.
void transicionarPara(Estado proximo, unsigned long agora) {
estado = proximo;
= agora;
if (estado == PRIMEIRO_PULSO || estado == SEGUNDO_PULSO) {
digitalWrite(LED_BUILTIN, );
} else {
digitalWrite(LED_BUILTIN, );
}
}
Passo 5 de 8
Use a marca de entrada de cada estado para avançar pelos pulsos e pela pausa sem bloquear o loop.
Nos estados temporizados, a máquina faz uma consulta curta: verifica se o intervalo contado desde entradaEstado já venceu.
agora - entradaEstado >= intervaloSe a condição for falsa, não há transição nesta passagem. A função retorna, e o loop() pode continuar atendendo o botão e as demais tarefas. Não use delay() nem um laço de espera dentro de um case.
A marca entradaEstado foi registrada ao entrar no estado pela função transicionarPara(...), construída no step anterior.

A marca temporal pertence ao estado atual e só muda quando uma transição realmente acontece.
Durante a permanência em um estado, a referência temporal deve ficar intacta. Atualizá-la em toda passagem deslocaria continuamente o início da contagem: a diferença agora - entradaEstado continuaria pequena e o prazo poderia nunca vencer.
A marca é atualizada somente na inicialização ou ao chamar transicionarPara(...). Quando ocorre uma transição, o mesmo instante agora observado nesta passagem passa a ser o início do intervalo seguinte.
Trecho para incluir nos cases temporizados de atualizarMaquina(...). A função transicionarPara(...) e a variável entradaEstado já foram definidas anteriormente.
case PRIMEIRO_PULSO:
if ((unsigned long)(agora - entradaEstado) >= 1000UL) {
transicionarPara(PAUSA, agora);
}
break;
case PAUSA:
if ((unsigned long)(agora - entradaEstado) >= 500UL) {
transicionarPara(SEGUNDO_PULSO, agora);
}
break;
case SEGUNDO_PULSO:
if ((unsigned long)(agora - entradaEstado) >= 1000UL) {
transicionarPara(REPOUSO, agora);
}
break;Dica
O vencimento é percebido em uma passagem pelo loop() que observa a condição como verdadeira. Portanto, a mudança não é prometida exatamente no milissegundo do prazo. O importante é que a consulta seja breve e repetida com frequência, sem bloquear o atendimento das entradas.
Complete as condições temporais usando a duração do estado que está terminando. As lacunas representam os intervalos da tabela de comportamento.
Preencha os intervalos temporizados da sequência.
case PRIMEIRO_PULSO:
if ((unsigned long)(agora - entradaEstado) >= ) {
transicionarPara(PAUSA, agora);
}
break;
case PAUSA:
if ((unsigned long)(agora - entradaEstado) >= ) {
transicionarPara(SEGUNDO_PULSO, agora);
}
break;
case SEGUNDO_PULSO:
if ((unsigned long)(agora - entradaEstado) >= ) {
transicionarPara(REPOUSO, agora);
}
break;A máquina está em PRIMEIRO_PULSO, mas a condição de 1000 ms nunca se torna verdadeira. Qual alteração provavelmente causou esse problema?

Passo 6 de 8
Defina a prioridade do pressionamento aceito sobre o vencimento do intervalo para garantir uma única transição por atualização da máquina.
Nos estados ativos — PRIMEIRO_PULSO, PAUSA e SEGUNDO_PULSO — um novo pressionamento aceito cancela a sequência e leva a aplicação para REPOUSO. Essa é uma política escolhida para esta sinalização.
Em uma passagem por loop(), podem estar verdadeiros tanto o evento de pressionamento quanto a condição de tempo decorrido. A máquina não tenta decidir qual ocorreu fisicamente “primeiro”: ela usa os valores observados naquela passagem e aplica uma prioridade definida no código.
Dica
O cancelamento é testado antes do prazo em cada estado ativo. Assim, há no máximo uma transição por chamada da atualização da máquina.

Durante uma etapa ativa, o caminho de cancelamento tem prioridade sobre o avanço temporizado.
Considere a atualização em um estado ativo. A cadeia if/else if torna as alternativas mutuamente exclusivas: se o cancelamento ocorrer, o teste de prazo não decide outra transição nessa mesma chamada.
Trecho para um estado ativo, como PRIMEIRO_PULSO
case PRIMEIRO_PULSO:
if (pressionamentoAceito) {
transicionarPara(REPOUSO, agora);
} else if (agora - entradaNoEstado >= 1000UL) {
transicionarPara(PAUSA, agora);
}
break;Dica
Mesmo que transicionarPara() altere a variável de estado, o switch já selecionou este case para a chamada atual. O break encerra a seleção. Portanto, o evento que cancelou não reinicia a sequência imediatamente; será necessário soltar e fazer um novo pressionamento aceito em outra passagem.
Complete a condição que deve ser avaliada primeiro em um estado ativo. Ela representa o evento momentâneo já produzido pelo tratamento de botão.
Preencha a primeira condição da cadeia de decisão.
if () {
transicionarPara(REPOUSO, agora);
} else if (agora - entradaNoEstado >= intervalo) {
transicionarPara(proximoEstado, agora);
}A máquina está em PRIMEIRO_PULSO. Na passagem atual, pressionamentoAceito é verdadeiro e já se passaram 1000 ms desde a entrada nesse estado. Após atualizar a máquina, qual é o estado e a saída?

Passo 7 de 8
Integre o evento de botão tratado por rebote à máquina de estados e execute a sequência no Uno R3 próprio.
A integração mantém responsabilidades separadas: o loop() observa o tempo uma vez, o tratamento de rebote produz um evento momentâneo e a máquina decide se haverá transição. O LED é comandado apenas pela função transicionarPara(...), quando a máquina entra em um estado.
Assim, manter o botão pressionado não cria vários comandos, e não há delay() bloqueando novas leituras.

Com a placa desenergizada, conecte o botão entre D2 e GND. Use o LED integrado e alimente o Uno somente pelo USB.
Atenção
Desconecte o USB antes de alterar a montagem. Não conecte fonte externa a VIN nem ao pino de 5 V enquanto o cabo USB estiver alimentando a placa.
Parte 1 do sketch: declarações, protótipos e tratamento de rebote. Crie um único sketch na IDE e insira os blocos na ordem apresentada.
const byte PINO_BOTAO = 2;
const unsigned long DEBOUNCE_MS = 30;
const unsigned long PULSO_MS = 1000;
const unsigned long PAUSA_MS = 500;
enum Estado {
REPOUSO,
PRIMEIRO_PULSO,
PAUSA,
SEGUNDO_PULSO
};
Estado estado = REPOUSO;
unsigned long entradaEstado = 0;
bool leituraAnterior = HIGH;
bool estadoEstavel = HIGH;
unsigned long mudouEm = 0;
bool atualizarBotao(unsigned long agora);
void transicionarPara(Estado proximo, unsigned long agora);
void atualizarMaquina(bool eventoPressionado, unsigned long agora);
bool atualizarBotao(unsigned long agora) {
bool leitura = digitalRead(PINO_BOTAO);
if (leitura != leituraAnterior) {
leituraAnterior = leitura;
mudouEm = agora;
}
bool eventoPressionado = false;
if ((unsigned long)(agora - mudouEm) >= DEBOUNCE_MS &&
leitura != estadoEstavel) {
estadoEstavel = leitura;
if (estadoEstavel == LOW) {
eventoPressionado = true;
}
}
return eventoPressionado;
}atualizarBotao() retorna true somente na passagem em que um pressionamento estável é aceito. Nas demais passagens, inclusive enquanto o botão continua pressionado, retorna false.
As variáveis do botão e da máquina são persistentes: foram declaradas fora das funções e não são reinicializadas pelo loop().
Parte 2 do sketch: a função de transição aplica a ação de entrada; a máquina decide qual transição é válida. Nos estados ativos, o evento de pressionamento é testado antes do prazo.
void transicionarPara(Estado proximo, unsigned long agora) {
switch (proximo) {
case REPOUSO:
case PRIMEIRO_PULSO:
case PAUSA:
case SEGUNDO_PULSO:
break;
default:
proximo = REPOUSO;
break;
}
estado = proximo;
entradaEstado = agora;
if (estado == PRIMEIRO_PULSO || estado == SEGUNDO_PULSO) {
digitalWrite(LED_BUILTIN, HIGH);
} else {
digitalWrite(LED_BUILTIN, LOW);
}
}
void atualizarMaquina(bool eventoPressionado, unsigned long agora) {
switch (estado) {
case REPOUSO:
if (eventoPressionado) {
transicionarPara(PRIMEIRO_PULSO, agora);
}
break;
case PRIMEIRO_PULSO:
if (eventoPressionado) {
transicionarPara(REPOUSO, agora);
} else if ((unsigned long)(agora - entradaEstado) >= PULSO_MS) {
transicionarPara(PAUSA, agora);
}
break;
case PAUSA:
if (eventoPressionado) {
transicionarPara(REPOUSO, agora);
} else if ((unsigned long)(agora - entradaEstado) >= PAUSA_MS) {
transicionarPara(SEGUNDO_PULSO, agora);
}
break;Parte 3 do sketch: complete a função da máquina e acrescente setup() e loop(). Depois de inserir as três partes no mesmo sketch, grave-o no Uno R3.
case SEGUNDO_PULSO:
if (eventoPressionado) {
transicionarPara(REPOUSO, agora);
} else if ((unsigned long)(agora - entradaEstado) >= PULSO_MS) {
transicionarPara(REPOUSO, agora);
}
break;
default:
transicionarPara(REPOUSO, agora);
break;
}
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PINO_BOTAO, INPUT_PULLUP);
unsigned long agora = millis();
leituraAnterior = digitalRead(PINO_BOTAO);
estadoEstavel = leituraAnterior;
mudouEm = agora;
estado = REPOUSO;
entradaEstado = agora;
digitalWrite(LED_BUILTIN, LOW);
}
void loop() {
unsigned long agora = millis();
bool eventoPressionado = atualizarBotao(agora);
atualizarMaquina(eventoPressionado, agora);
}LED inicialmente apagado. Após um pressionamento aceito: LED aceso por cerca de 1 s, apagado por cerca de 0,5 s, aceso por cerca de 1 s e novamente apagado. Um novo pressionamento aceito durante a sequência cancela a execução e deixa o LED apagado.
A duração é aproximada: a transição ocorre na primeira passagem pelo loop que observar o prazo vencido.
Dica
O mesmo valor de agora é entregue ao botão e à máquina na mesma passagem pelo loop(). Em um estado ativo, a cadeia if / else if dá prioridade ao cancelamento: se eventoPressionado for verdadeiro, o prazo não provoca outra transição nessa passagem.
Ordene as operações de uma passagem pelo loop().
Complete o argumento que liga o evento do botão à atualização da máquina.
void loop() {
unsigned long agora = millis();
bool eventoPressionado = atualizarBotao(agora);
atualizarMaquina(, agora);
}
Passo 8 de 8
Verifique a sinalização no Uno R3, teste cancelamentos e confirme por rastreamento a prioridade entre evento e prazo.
Com o sketch do step anterior gravado no Uno R3, compare a especificação com o LED integrado. Use somente a alimentação USB nesta prática.
Faça cada linha da tabela como uma execução independente: antes de iniciar o próximo caso, espere o LED ficar apagado em REPOUSO. Um novo pressionamento válido só pode existir após soltar o botão e pressioná-lo novamente.
Ao observar, considere as durações aproximadas: o loop detecta os prazos em passagens sucessivas, portanto não é esperado medir transições fisicamente exatas no milissegundo.
Execute cada caso a partir de REPOUSO, com o LED apagado. Registre o que realmente ocorreu no seu equipamento.
| Caso | Como iniciar | Comportamento esperado | Resultado observado |
|---|---|---|---|
| Partida | Ligue ou reinicie a placa | LED apagado; máquina em REPOUSO | Anote |
| Botão mantido | Em REPOUSO, pressione e mantenha | Acende ~1 s, apaga ~0,5 s, acende ~1 s e apaga | Anote |
| Soltura | Em REPOUSO, pressione; solte durante um pulso ou a pausa | A soltura não causa transição; a sequência temporal continua | Anote |
| Novo ciclo | Após a sequência acabar, solte se necessário e pressione | Inicia PRIMEIRO_PULSO novamente | Anote |

Um evento inicia a sequência. Manter pressionado ou soltar depois não cria uma transição por si só.
Teste o cancelamento em três execuções separadas. Em cada uma: comece em REPOUSO, pressione para iniciar, solte o botão, e faça um novo pressionamento durante o estado indicado.
PRIMEIRO_PULSO, o LED está aceso no primeiro pulso.PAUSA, o LED está apagado entre os pulsos.SEGUNDO_PULSO, o LED está aceso no segundo pulso.Nos três casos, o novo evento deve cancelar para REPOUSO, deixando o LED apagado. Depois do cancelamento, solte e pressione novamente: esse novo evento deve iniciar outro PRIMEIRO_PULSO. A pausa continua sendo um estado ativo, mesmo tendo a mesma saída apagada de REPOUSO.
Registre quatro blocos de evidência:
PRIMEIRO_PULSO, PAUSA e SEGUNDO_PULSO.Descreva somente o que observou; este campo serve como seu registro de teste.
Escreva pelo menos 160 caracteres (0/160).
A coincidência entre evento e prazo não precisa ser reproduzida manualmente. Rastreie uma passagem de atualizarMaquina(...) usando os mesmos nomes do sketch:
estado é PRIMEIRO_PULSO;eventoPressionado é true;(unsigned long)(agora - entradaEstado) >= PULSO_MS também é verdadeiro.A política da aplicação dá prioridade ao cancelamento. A cadeia mutuamente exclusiva deve produzir uma única chamada de transicionarPara(...): o LED termina apagado, pois o destino é REPOUSO.
Complete a decisão reconhecível do sketch integrado, preservando a prioridade do cancelamento.
case PRIMEIRO_PULSO:
(eventoPressionado) {
transicionarPara(, agora);
} else if ((unsigned long)(agora - entradaEstado) >= PULSO_MS) {
transicionarPara(PAUSA, agora);
}
break;Resumo
entradaEstado só muda na inicialização ou em uma transição, permitindo que os intervalos vençam.eventoPressionado tem prioridade sobre o prazo e a cadeia if/else if produz uma única transição.Parabéns! Você concluiu: Máquinas de estados no firmware
Milhares de cursos online em vídeo, ebooks e áudiobooks.
Para testar seus conhecimentos no decorrer dos cursos online
Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail
Baixe nosso aplicativo pelo QR Code ou pelos links abaixo:.
+ de 10 milhões
de alunos
Certificado grátis e
válido em todo o Brasil
60 mil exercícios
gratuitos
4,8/5 classificação
nas lojas de apps
Cursos gratuitos em
vídeo, ebooks e audiobooks