Estruturas de controle — Arduino e IoT — semana 3 do 1o trimestre
Semana 3 de 13· 1o trimestre · 01/02 a 30/04
Estruturas de controle
if, switch e laco. O aluno já sabe a lógica; muda a sintaxe.
Aula 1 — if, else e o operador ternario
Objetivos
- Escrever uma condição com
if,else ifeelsee dizer qual caminho o programa tomou. - Trocar um
ifde duas linhas pelo operador ternário e explicar o que se perde nessa troca. - Montar condição composta com
&&e||sem confundir os dois operadores lógicos. - Usar uma guarda de tempo para o programa reagir a uma entrada sem refazer a classificação a cada volta do laço.
Material
- 1 ESP32 DevKit V1 por aluno, com o cabo USB
- 1 protoboard de 830 pontos e 1 jogo de jumpers por aluno
- 2 a 5 LEDs de 3,3 V e 2 a 5 resistores de 330 Ω por aluno
- 1 módulo de alimentação MB102 por dupla
- Folha com quatro faixas de 0 a 100 impressa, uma por dupla
Conceitos
As três partes da condição
if (tensao > 3.0) { Serial.println("alta"); }
A condição precisa ser um valor booleano, ou seja, verdadeiro ou falso. tensao > 3.0 é uma pergunta que devolve true ou false; tensao sozinho, sem comparação, não serve.
As chaves delimitam o bloco. Elas não são enfeite: o C++ usa as chaves para saber onde o comando termina, e sem elas ele assume que o comando é só a próxima frase. É a diferença mais visível entre o C++ e o JavaScript na hora de escrever.
Encadeamento e a ordem dos testes
if (valor < 30) { ... } else if (valor < 70) { ... } else { ... }
Os testes são lidos de cima para baixo, e o primeiro que for verdadeiro ganha; os outros nem são olhados. Por isso valor < 30 vem antes de valor < 70: invertido, todo número abaixo de 70 cairia na faixa baixa.
O else do final não tem condição: é o "nenhum dos anteriores deu certo". E ele é opcional — omitir o else apenas faz o programa não fazer nada nesse caminho.
O operador ternário
faixa = (valor < 70) ? "baixa" : "alta";
É um if de duas saídas escrito em uma linha: condição, interrogação, resultado se verdadeiro, dois-pontos, resultado se falso.
O que se perde é o nome do caminho. Com if e else, o bloco tem nome e o programa lê como uma frase. Com o ternário, o valor final importa e o motivo fica escondido. Regra do curso: ternário para escolher um valor, if para fazer uma coisa.
Condição composta e o curto-circuito
&& é "e", || é "ou". Ambos aceitam várias condições:
if (tensao > 1.0 && tensao < 3.0) { ... } // dentro da faixa if (digitalRead(PINO) == LOW || contador > 10) { ... }
O detalhe que só aparece na prática: quando o lado esquerdo já decide o resultado, o lado direito não é avaliado. Isso se chama curto-circuito e é o que salva expressões como indice > 0 && TABELA[indice - 1] != -1, onde o lado direito seria uma leitura fora do vetor.
A guarda que evita refazer tudo
No loop do sketch, o if está dentro de if (Serial.available() > 0). Sem essa guarda, a classificação rodaria milhares de vezes por segundo com o número velho, e o serial viraria uma parede de texto repetido. A guarda pergunta "chegou algo novo?" antes de agir.
Atividade
Montagem:
- Resistor de 330 Ω entre o
GPIO2e um lado do LED. - O outro lado do LED na trilha
+da protoboard. - Jumper macho-fêmea levando o
GPIO2ao resistor.
O lado longo do LED é o anodo e vai para o positivo.
- Grave a resolução, abra o monitor serial a 115200 baud e confirme que aparece o convite para digitar um número.
- Digite
10, depois50, depois90, e anote as três faixas devolvidas na ordem em que apareceram. - Digite
0e depois-5. Diga qual dos dois caminhos do código Cada um tomou e por que a ordem dos testes importa. - Escreva a mesma classificação usando só o operador ternário, em no máximo três linhas, e grave. Compare as duas versões no caderno: qual delas dá para ler em voz alta?
- Escreva uma condição que acenda o LED só quando o número for maior que 50 ou igual a 10, e diga qual dos dois operadores lógicos você usou.
- Acrescente uma quarta faixa ao código, entre 70 e 90, com o nome que você escolher, sem alterar as três que já funcionam. Confirme que os números das outras faixas continuam caindo na faixa certa.
Nota: 10 pontos. Critério de fim: o serial responde corretamente aos cinco números testados e a quarta faixa foi acrescentada sem quebrar as outras.
Resolucao
// Aula 1 do dia 3: if, else e o operador ternário. // // O aluno já sabe a lógica de condição; o que muda é a sintaxe e a //indentação. Este sketch lê um número que o professor digita no monitor // serial e classifica, para que a turma veja o caminho tomado no Serial. #include <Arduino.h> const int PINO_LED = 2; const int LIMITE_BAIXO = 30; const int LIMITE_ALTO = 70; int voltas = 0; void setup() { pinMode(PINO_LED, OUTPUT); Serial.begin(115200); Serial.println(); Serial.println("=== dia 3, aula 1: if, else e ternário ==="); Serial.println(); Serial.println("Digite um número de 0 a 100 e aperte Enter."); Serial.println("O programa diz em que faixa ele caiu."); } void loop() { // Só age quando chegou byte novo no monitor. Sem esta guarda, o programa // entraria no if a cada volta e classificaria o número velho mil vezes. if (Serial.available() > 0) { int valor = Serial.parseInt(); if (valor <= 0) { Serial.println("Digite um número maior que zero."); } else if (valor < LIMITE_BAIXO) { Serial.print(valor); Serial.println(" -> faixa baixa"); digitalWrite(PINO_LED, LOW); } else if (valor < LIMITE_ALTO) { Serial.print(valor); Serial.println(" -> faixa media"); digitalWrite(PINO_LED, HIGH); } else { Serial.print(valor); Serial.println(" -> faixa alta"); digitalWrite(PINO_LED, HIGH); } voltas++; Serial.print(" classifications: "); Serial.println(voltas); Serial.println("Digite outro numero."); Serial.println(); } // while sem condição de parada seria o laço infinito. Aqui ele só espera: // passa pelo loop milhares de vezes por segundo, e não faz nada até o // professor digitar alguma coisa. Isso é normal e não trava a placa. }
Por que assim e não de outro jeito. O programa espera o número digitado no monitor serial em vez de um analogRead. Nesta aula a condição é o assunto, não o sensor: um valor que muda sozinho deixaria a turma classificando números que não escolheu, e a discussão do caminho tomado seria curta demais.
A ordem dos testes é valor <= 0, depois < LIMITE_BAIXO, depois < LIMITE_ALTO. O 0 vem primeiro de propósito: se viesse depois, 0 < 30 seria verdadeiro e o zero cairia na faixa baixa, e o aluno não veria o caminho de erro.
O else final e o de erro estão separados de propósito. O caminho apertado/solt do dia 5 vai nascer daqui: a estrutura de decidir o que fazer com cada estado já está pronta, e no dia 5 só troca o número por digitalRead.
O loop termina sem delay e sem qualquer espera. Ele passa por ali dezenas de milhares de vezes por segundo sem fazer nada, e isso não é defeito: é o que permite responder ao que o professor digitar no mesmo instante.
Criterios de correcao
| Critério | Pontos |
|---|---|
| Sketch gravado e as cinco faixas devolvidas corretamente no serial | 3 pontos |
pinMode declarado no setup antes de qualquer digitalWrite | 2 pontos |
| Versão só com ternário, gravada, e comparação escrita no caderno | 3 pontos |
| Item 5 com o operador lógico nomeado | 2 pontos |
Erros comuns
| Erro | Como aparece | Correcao | ||||
|---|---|---|---|---|---|---|
Usar = dentro da condição | if (valor = 0) e o programa entra sempre | "Um igual so ordena. Para perguntar são dois: ==." | ||||
Esquecer as chaves no primeiro if | Só a linha seguinte entra no if, o resto roda sempre | "O C++ assume que o comando e so a proxima frase. Se a ideia era varias, abra e feche chave." | ||||
| Testar a faixa larga antes da estreita | valor < 70 antes de valor < 30 e tudo cai na faixa baixa | "Os testes vao do mais especifico para o mais geral. O primeiro que der certo ganha." | ||||
Confundir && com ` | ` | Condição que aceita faixa que devia recusar | "Leia em voz alta. 'E' e &&, com dois sinais. 'Ou' e ` | `, com duas barras." | ||
Escrever else com condição | else (valor < 70) não compila | "else não tem condição: ele e o 'nenhum dos anteriores deu certo'." | ||||
Não fechar a chave do else | Erro de compilacao apontando varias linhas depois | "A chave que abriu o if fecha no fim do else, e não antes dele." | ||||
Colocar a ação fora do if | LED aceso o tempo todo, sem depender do número | "A ação que depende da condição fica dentro das chaves. Fora delas, ela roda sempre." |
Desafio extra
Troque a faixa media por uma condição composta que dependa de dois parâmetros ao mesmo tempo: o número digitado e o estado de um botão. Faça o programa só aceitar números na faixa media quando o botão estiver apertado, e escrever "recusado" quando o número estiver na faixa e o botão estiver solto. Explique no caderno qual das duas condições você pôs primeiro, e o que aconteceria se invertesse.
>A resolucao, compilada
// Aula 1 do dia 3: if, else e o operador ternário. // // O aluno já sabe a lógica de condição; o que muda é a sintaxe e a //indentação. Este sketch lê um número que o professor digita no monitor // serial e classifica, para que a turma veja o caminho tomado no Serial. #include <Arduino.h> const int PINO_LED = 2; const int LIMITE_BAIXO = 30; const int LIMITE_ALTO = 70; int voltas = 0; void setup() { pinMode(PINO_LED, OUTPUT); Serial.begin(115200); Serial.println(); Serial.println("=== dia 3, aula 1: if, else e ternário ==="); Serial.println(); Serial.println("Digite um número de 0 a 100 e aperte Enter."); Serial.println("O programa diz em que faixa ele caiu."); } void loop() { // Só age quando chegou byte novo no monitor. Sem esta guarda, o programa // entraria no if a cada volta e classificaria o número velho mil vezes. if (Serial.available() > 0) { int valor = Serial.parseInt(); if (valor <= 0) { Serial.println("Digite um número maior que zero."); } else if (valor < LIMITE_BAIXO) { Serial.print(valor); Serial.println(" -> faixa baixa"); digitalWrite(PINO_LED, LOW); } else if (valor < LIMITE_ALTO) { Serial.print(valor); Serial.println(" -> faixa media"); digitalWrite(PINO_LED, HIGH); } else { Serial.print(valor); Serial.println(" -> faixa alta"); digitalWrite(PINO_LED, HIGH); } voltas++; Serial.print(" classifications: "); Serial.println(voltas); Serial.println("Digite outro numero."); Serial.println(); } // while sem condição de parada seria o laço infinito. Aqui ele só espera: // passa pelo loop milhares de vezes por segundo, e não faz nada até o // professor digitar alguma coisa. Isso é normal e não trava a placa. }
Sem saída de compilação gravada. Rode python3 validar.py -t 1 dia03 aula1.
Aula 2 — for, while, do-while e o laco que não acaba
Objetivos
- Escolher entre
for,whileedo-whilesabendo dizer quantas vezes o laço roda. - Escrever o laço com variável de controle no cabeçalho, em vez de deixar o incremento solto no corpo.
- Usar
breakecontinuepara sair cedo ou pular uma iteração sem enshrinar o laço inteiro. - Substituir
delaydentro de laço por comparação commillis, rodando duas tarefas ao mesmo tempo.
Material
- 1 ESP32 DevKit V1 por aluno, com o cabo USB
- 1 protoboard de 830 pontos e 1 jogo de jumpers por aluno
- 2 a 5 LEDs de 3,3 V e 2 a 5 resistores de 330 Ω por aluno
- 1 módulo de alimentação MB102 por dupla
- Folha com os três tipos de laço lado a lado, uma por dupla
Conceitos
Os três laços, e quando usar cada um
| Laço | Testa | Use quando |
|---|---|---|
for | antes de cada volta | você sabe quantas vezes repete |
while | antes de cada volta | você repete até uma condição virar falsa |
do-while | depois da volta | o corpo tem de rodar pelo menos uma vez |
O do-while é o único que garante uma execução. Ele é o natural para ler um sensor pelo menos uma vez antes de decidir se continua, e por isso o dia 8, no DHT11, ele reaparece.
A variável de controle vive no cabeçalho
for (int i = 1; i <= 5; i++) { Serial.println(i); }
Três partes: int i = 1 é a inicialização, i <= 5 é a condição, e i++ é o incremento. O i só existe dentro do laço: depois da chave final ele não existe mais, e usá-lo fora é erro de compilação.
Escrever o incremento solto no meio do corpo funciona, mas espalha a condição por duas partes do código. Quando o laço chegar a 40 linhas, ninguém acha onde ele termina. O cabeçalho é o contrato do laço com quem lê.
break e continue
break sai do laço na hora. continue pula para o fim da volta atual e recomeça o teste. A diferença aparece com clareza no laço de 1 a 20 pulando os múltiplos de 3: continue ainda roda os outros números, break para tudo.
O break tem um uso escondido e importante: sair cedo de uma busca dentro de uma lista. Achou o valor? break, e o laço para de procurar.
O laço que não acaba, e o que ele custa
while (true) { Serial.println("."); }
Esse laço não acaba nunca, e o programa para de responder a tudo. Não trava a placa: a placa continua ligada, o monitor continua passando linhas. O que para é o resto do programa.
Este é o dia em que delay deixa de ser aceitável. Um delay de 1 segundo dentro do laço não é laço infinito, mas produz o mesmo efeito prático: durante aquele segundo, o processador não olha botão nenhum, não lê sensor nenhum, não responde a nada. No dia 5, com o botão, isso vira "o botão só funciona uma vez por segundo".
A saída é comparar o tempo com millis:
if (agora - instanteAnterior >= INTERVALO) { instanteAnterior = agora; // faz o serviço e sai }
A tarefa não espera: ela olha a hora, faz o serviço e sai na hora. O laço continua girando e as outras tarefas continuam sendo vistas.
E atenção ao detalhe do unsigned: millis devolve unsigned long, e é por isso que o padrão é agora - instanteAnterior >= INTERVALO. Se o processador reiniciar o relógio no meio, a subtração em unsigned continua dando a diferença certa. Comparar os dois instantes direto, com >=, quebraria nessa hora.
Atividade
Montagem:
- Resistor de 330 Ω entre o
GPIO2e um lado do LED. - O outro lado do LED na trilha
+da protoboard. - Jumper macho-fêmea levando o
GPIO2ao resistor.
O lado longo do LED é o anodo e vai para o positivo.
- Grave a resolução e confirme que o LED pisca rápido e que a coluna do contador lento sobe uma vez por segundo.
- Conte por dez segundos quantas linhas da coluna lenta aparecem. Compare com a conta de
voltasLentasno serial e diga por que o número não é exatamente 10. - Escreva um laço
forde 1 a 20 que imprima no serial apenas os números que não são múltiplos de 3, usandocontinue. - Repita o item 3 usando
whileno lugar dofor, com a variável de controle declarada antes do laço. Diga qual das duas versões tem a variável de controle visível depois do laço. - Descomente a versão errada que está no fim do arquivo de código, grave e meça quanto tempo o serial leva para mostrar dez linhas. Depois compare com o tempo da versão com
millis. - Troque
INTERVALO_LENTOde 1000 para 300 e diga o que acontece com oSerialque hoje é lento: fica igual ao rápido ou ainda é mais lento?
Nota: 10 pontos. Critério de fim: as duas tarefas rodam ao mesmo tempo no sketch final e o serial mostra as duas colunas.
Resolucao
// Aula 2 do dia 3: for, while, do-while e o laço que não acaba. // // Esta é a aula em que `delay` dentro de laço deixa de ser aceitável. O // sketch roda duas tarefas ao mesmo tempo — um contador rápido e uma contagem // lenta — usando `millis`, que é a aula que vale do dia inteiro. // // A versão ERRADA está comentada no fim do arquivo, para o professor colar no // projetor e deixar a turma ver a diferença. #include <Arduino.h> const int PINO_LED = 2; const int INTERVALO_RAPIDO = 100; // tarefa rápida, em milissegundos const int INTERVALO_LENTO = 1000; // tarefa lenta, em milissegundos // Instante da última execução de cada tarefa. `unsigned long` é o tipo que o // `millis` devolve; declarar com `int` estoura depois de cerca de 24 dias de // programa rodando sem parar. unsigned long instanteRapido = 0; unsigned long instanteLento = 0; int voltasRapidas = 0; int voltasLentas = 0; void setup() { pinMode(PINO_LED, OUTPUT); Serial.begin(115200); Serial.println(); Serial.println("=== dia 3, aula 2: dois laços ao mesmo tempo ==="); Serial.println(); Serial.println("Dois tarefas sem delay no meio: o LED pisca e o contador"); Serial.println("continua contando enquanto isso."); Serial.println(); Serial.println("tarefas | lenta | rapida"); } // Esta função roda a cada 100 ms e sai na hora. Ela nunca espera ninguém. void tarefaRapida() { voltasRapidas++; digitalWrite(PINO_LED, voltasRapidas % 2 == 0 ? HIGH : LOW); } // Esta roda a cada 1 s. As duas convivem porque nenhuma delas segura o // processador: cada uma só olha a hora e sai. void tarefaLenta() { voltasLentas++; Serial.print(voltasLentas); Serial.print(" | "); Serial.println(voltasRapidas); } void loop() { unsigned long agora = millis(); // Subtrair e comparar é mais seguro que comparar os instantes direto: // quando o processador reinicia o millis volta a zero, e a subtração // continua dando a diferença certa. if (agora - instanteRapido >= INTERVALO_RAPIDO) { instanteRapido = agora; tarefaRapida(); } if (agora - instanteLento >= INTERVALO_LENTO) { instanteLento = agora; tarefaLenta(); } // Loop vazio de propósito. Passa por aqui dezenas de milhares de vezes por // segundo sem fazer nada, e é exatamente isso que permite o processador // responder às duas tarefas. Um loop ocupado aqui travaria as duas. // ------------------------------------------------------------------ // VERSÃO ERRADA — o que o aluno escreve na primeira tentativa: // // void loop() { // digitalWrite(PINO_LED, HIGH); // delay(100); // digitalWrite(PINO_LED, LOW); // delay(900); // Serial.println("tarefa lenta"); // só sai depois de 1 s parado // } // // Compila. Não dá erro. Só que o Serial só imprime uma vez por segundo, e // qualquer botão apertado nesse intervalo só é lido no fim do segundo. // ------------------------------------------------------------------ }
Por que assim e não de outro jeito. O sketch roda duas tarefas que não se atrapalham, e isso é o ponto inteiro da aula. A rápida pisca o LED a cada 100 ms; a lenta imprime no serial a cada segundo. Com delay, as duas seriam a mesma coisa.
A comparação é agora - instante >= INTERVALO e não agora >= instante + INTERVALO. As duas formas funcionam, mas a primeira sobrevive ao reinício do relógio, porque a subtração de dois unsigned long dá o tempo decorrido mesmo quando o contador passou do zero.
O instantX é atualizado depois de decidir, não antes. Atualizar antes faria a tarefa disparar a cada volta do laço, e o nome da variável deixaria de dizer a que momento ela se refere.
A versão errada está no fim do arquivo, comentada, e não é decorativa: ela é o que o aluno escreve na primeira tentativa, e o professor precisa dela na tela para medir o mesmo tempo nos dois códigos. Se ele só acredita em frase, o botão do dia 5 vai parecer quebrado.
O loop é um loop vazio. Ele passa por ali dezenas de milhares de vezes por segundo sem fazer nada, e é exatamente isso que deixa as duas tarefas rodarem livremente. Um laço ocupado aqui travaria as duas.
Criterios de correcao
| Critério | Pontos |
|---|---|
| Duas tarefas rodando juntas, com as duas colunas no serial | 3 pontos |
pinMode declarado no setup antes de qualquer digitalWrite | 2 pontos |
millis com unsigned long e comparação por subtração | 3 pontos |
Itens 3 e 4 escritos e a diferença entre for e while respondida | 2 pontos |
Erros comuns
| Erro | Como aparece | Correcao |
|---|---|---|
while (true) com delay dentro | Programa que responde uma vez por segundo | "Esse e o laco que não acaba. Troque o delay por comparacao com millis." |
Declarar int agora = millis(); | Contador que falha depois de alguns dias rodando | "O millis devolve unsigned long. Guardar em int estoura a conta." |
Comparar agora >= instante + 1000 | Quebra quando o processador reinicia o relogio | "Prefira agora - instante >= 1000. A subtracao continua valendo quando o relogio da a volta." |
Escrever if (i = 3) no for | Laco que roda com i sempre valendo 3 | "Para testar, dois iguais. Um igual so substitui a variável." |
Colocar o i++ no fim do corpo e não no cabecalho | Laco de 40 linhas onde ninguem acha o fim | "O incremento vai no cabecalho, junto com o teste. E ele que diz onde o laco termina." |
Confundir while e do-while | Aluno espera o corpo rodar antes de testar | "O do-while testa depois. Por isso o corpo dele roda pelo menos uma vez, mesmo com a condição já falsa." |
Usar break no lugar de continue ao pular número | O laco para no primeiro múltiplo de 3 | "break sai do laco inteiro. Para pular so um, e continue." |
| Comentar a versão errada no código do aluno | "Se eu descomentar isso, da loop infinito" | "Descomente de verdade e meça. O serial vai mostrar a diferença de tempo na sua frente." |
Desafio extra
Acrescente uma terceira tarefa que rode a cada 500 ms e faça o LED piscar duas vezes seguidas, e escreva no caderno quantas voltas da tarefa rápida acontecem dentro de uma volta da tarefa lenta. Em seguida, inverta as três velocidades e verifique se a contagem continua batendo — se não bater, descubra por que e escreva a resposta em duas linhas.
>A resolucao, compilada
// Aula 2 do dia 3: for, while, do-while e o laço que não acaba. // // Esta é a aula em que `delay` dentro de laço deixa de ser aceitável. O // sketch roda duas tarefas ao mesmo tempo — um contador rápido e uma contagem // lenta — usando `millis`, que é a aula que vale do dia inteiro. // // A versão ERRADA está comentada no fim do arquivo, para o professor colar no // projetor e deixar a turma ver a diferença. #include <Arduino.h> const int PINO_LED = 2; const int INTERVALO_RAPIDO = 100; // tarefa rápida, em milissegundos const int INTERVALO_LENTO = 1000; // tarefa lenta, em milissegundos // Instante da última execução de cada tarefa. `unsigned long` é o tipo que o // `millis` devolve; declarar com `int` estoura depois de cerca de 24 dias de // programa rodando sem parar. unsigned long instanteRapido = 0; unsigned long instanteLento = 0; int voltasRapidas = 0; int voltasLentas = 0; void setup() { pinMode(PINO_LED, OUTPUT); Serial.begin(115200); Serial.println(); Serial.println("=== dia 3, aula 2: dois laços ao mesmo tempo ==="); Serial.println(); Serial.println("Dois tarefas sem delay no meio: o LED pisca e o contador"); Serial.println("continua contando enquanto isso."); Serial.println(); Serial.println("tarefas | lenta | rapida"); } // Esta função roda a cada 100 ms e sai na hora. Ela nunca espera ninguém. void tarefaRapida() { voltasRapidas++; digitalWrite(PINO_LED, voltasRapidas % 2 == 0 ? HIGH : LOW); } // Esta roda a cada 1 s. As duas convivem porque nenhuma delas segura o // processador: cada uma só olha a hora e sai. void tarefaLenta() { voltasLentas++; Serial.print(voltasLentas); Serial.print(" | "); Serial.println(voltasRapidas); } void loop() { unsigned long agora = millis(); // Subtrair e comparar é mais seguro que comparar os instantes direto: // quando o processador reinicia o millis volta a zero, e a subtração // continua dando a diferença certa. if (agora - instanteRapido >= INTERVALO_RAPIDO) { instanteRapido = agora; tarefaRapida(); } if (agora - instanteLento >= INTERVALO_LENTO) { instanteLento = agora; tarefaLenta(); } // Loop vazio de propósito. Passa por aqui dezenas de milhares de vezes por // segundo sem fazer nada, e é exatamente isso que permite o processador // responder às duas tarefas. Um loop ocupado aqui travaria as duas. // ------------------------------------------------------------------ // VERSÃO ERRADA — o que o aluno escreve na primeira tentativa: // // void loop() { // digitalWrite(PINO_LED, HIGH); // delay(100); // digitalWrite(PINO_LED, LOW); // delay(900); // Serial.println("tarefa lenta"); // só sai depois de 1 s parado // } // // Compila. Não dá erro. Só que o Serial só imprime uma vez por segundo, e // qualquer botão apertado nesse intervalo só é lido no fim do segundo. // ------------------------------------------------------------------ }
Sem saída de compilação gravada. Rode python3 validar.py -t 1 dia03 aula2.
