Revisao do ano — Arduino e IoT — semana 13 do 3o trimestre
Semana 13 de 15· 3o trimestre · 05/09 a 10/12
Revisao do ano
O ano inteiro em uma página, e o que cada aluno Leva para fora.
Aula 1 — Revisao: do LED ao sistema com login
Objetivos
o mapa do ano, das sete camadas, e dizer o que entra e o que sai em cada uma.
- Nomear, para cada camada, o defeito concreto que ela produziu na turma, e o local onde ele aparece.
- apontar o erro que mais apareceu no ano e a camada que concentrou as occurencias.
- Dizer o que cada marco do ano mudou, ligando o primeiro LED ao sistema com login.
- Responder a pergunta "qual foi o primeiro erro que você entendeu sozinho", e explicar por que ela vale mais que "o que você aprendeu".
Material
- 1 ESP32 DevKit V1 por aluno, com o cabo USB
- 1 LED no pino 2 e 1 botao com pull-up no pino 0
- A folha do mapa do ano impressa, com as sete camadas em branco
- Caneta para marcar a camada de cada defeito do ano
Conceitos
As sete camadas e a regra que as separa
A revisao do ano tem sete camadas, e a ordem e a ordem do percurso, não a ordem de importancia. O que cada camada faz e uma frase, e o professor exige as duas metades: o que entra e o que sai:
| Camada | O que entra | O que sai | Quem chama |
|---|---|---|---|
hardware | eletricidade, pinos, sensor | número que representa o mundo fisico | o firmware |
firmware | leitura do sensor, estado da placa | JSON com o dado e a versão | a rede |
| rede | JSON, endereco, cabecalho | pedido HTTP e resposta com código | o servidor |
| servidor | pedido com token e id de dispositivo | resposta com código e corpo, log com identificador | o banco e o painel |
| banco de dados | consulta parametrizada | linha com índice, paginada | o repository |
| seguranca | entrada não confiavel de quatro origens | entrada validada, saída escapada | todas acima |
| teste e entrega | caso de teste, migracao, README | prova de que a regra roda | ninguem: segura as outras seis |
A regra que separa uma camada da outra e uma so: quem produz o dado não pode ser quem decide que o dado e valido. No banco isso virou consulta parametrizada; no JSON virou escapar; no HTML virou textContent. E o mesmo principio nas sete camadas.
Onde cada camada quebrou, e por que a conta importa
Cada camada tem um defeito tipico, e a lista de ocorrencias diz o que a turma de fato tropecou:
| Camada | Defeito tipico | Sintoma que o aluno via |
|---|---|---|
hardware | fio de GND solto | sensor lia zero com a placa ligada |
firmware | laco sem tempo limite | placa travada, sem banner no serial |
| rede | perder o WiFi sem log | a placa sumia calada |
| servidor | erro de banco no corpo da resposta | o cliente via detalhe interno |
| banco | migracao NOT NULL em tabela cheia | tabela trancada, servidor fora |
| seguranca | token no log de acesso | quem le o log tinha sessão de alguem |
| teste | so caminho feliz, sem caso negativo | a regra passa e o cliente reclama |
A coluna da direita e a que o professor pede ao aluno: qual foi o erro que você viu acontecer, na sua frente, e não na tela de erro. Quem viu o banner não aparecer sabe o que e travamento; quem so leu "compilou" não sabe.
O erro que mais apareceu e o que ele diz sobre a transicao
A contagem sai das falhas medidas, e o primeiro da lista e string com número solto: Serial.println(23.5) imprime 23.5 no serial, mas quando o dado vai para um JSON montado com concatenacao, "23.5" vira 235. O aluno ve 235 graus no painel e não entende.
Esse erro e de semantica, não de sintaxe: o código compila, o programa roda, e o número esta errado. E a transicao de JavaScript para C++ que o provoke, porque em JavaScript o número tem tipo implicito e a conversao e automatica; em C++ a conversao e uma escolha, e cada escolha errada e um bug silencioso.
A leitura agregada e a que o professor leva para a abertura do proximo ano: a camada de firmware concentra as ocorrencias, e MySQL quase não aparece. Isso não e desculpa para ninguem — e e o dado que decide qual sera a primeira aula de novidade.
O percurso: o LED esta dentro do projeto final
O ano tem seis marcos, e cada um e um produto que roda:
| Momento | O que mudou |
|---|---|
| dia 01 | um LED piscando: entrada e saída digital |
| dia 08 | um sensor: o mundo fisico entrou no programa |
| dia 09 | rede: a placa passou a falar com alguem |
| primeiro trimestre, dia 13 | produto: sensor, tela e servidor juntos |
| segundo trimestre, dia 06 | MySQL: o dado passou a sobreviver ao desligamento |
| terceiro trimestre, dia 12 | login, historico, alerta e observabilidade |
Nenhuma aula apaga a anterior. O LED do primeiro dia continua no firmware de hoje, dentro da mesma função; o sensor do dia 8 continua mandando leitura; a rede do dia 9 continua sendo o caminho do dado. O projeto final e a soma, não a substituição — e o percurso do LED ao sistema com login cabe em seis linhas porque cada linha se apoia na anterior.
E por isso que o botao desta aula acende o LED: a primeira aula do ano, rodando dentro do projeto final. Quem fez o ano inteiro não precisa de prova para saber que o caminho foi continuo — mas precisa ver para acreditar.
O percurso do aluno, e a pergunta que vale mais
A pergunta que o professor faz no fim do ano não e "o que você aprendeu". E "qual foi o primeiro erro que você entendeu sozinho".
As duas respostas são diferentes. "O que você aprendeu" e facil e generico; "o primeiro erro que você entendeu sozinho" e especifica, nomeia o momento, e mostra a transicao de spectator para quem diagnostica. Quem responde a primeira pode ter o ano inteiro decorado; quem responde a segunda aprendeu a aprender.
E o percurso inteiro aponta para essa resposta. Erro de sintaxe fala o compilador. Erro de semantica fala o monitor serial. Erro de regra so fala o teste. Cada um e mais quieto que o anterior, e quem le as três camadas de erro já sabe mais do que quem so viu a mensagem do compilador.
Atividade
Montagem: LED no pino 2 com resistor, botao com pull-up no pino 0, ground no GND. O LED e o que o professor usa para fechar a aula ligando a primeira aula do ano.
- Grave o sketch da resolucao e rode no serial. Anote, para cada uma das sete camadas: o que entra, o que sai, e quem chama.
- Escolha a camada onde você mais errou este ano, e escreva o defeito tipico dela com o sintoma que você viu. Não escreva o que a aula teaches: escreva o que aconteceu na sua bancada.
- Na lista de erros do ano, some as ocorrencias e diga qual camada concentrou mais. Justifique com dois números da lista, não com opiniao.
- Escolha um erro da lista que você não entendeu na epoca, e escreva por que: faltou conceito, faltou ferramenta, ou faltou alguem perguntar. Essa resposta e sobre o ano, não sobre o código.
- Escreva o percurso em seis linhas, ligando cada marco ao que ele trouxe. Comece pelo
LEDdo dia 1 e termine pelo sistema comlogindo dia 12 do terceiro trimestre. Inclua odeploydo dia 10 do terceiro trimestre: e a aula em que o sistema saiu da maquina da aula. - Escreva a resposta da pergunta final em uma frase: "o primeiro erro que eu entendi sozinho foi ...". Compare com a resposta do item 4: são o mesmo erro ou não?
Nota: 12 pontos. Critério de fim: as sete camadas anotadas com entra, sai e quem chama, e a resposta do item 6 escrita em uma frase.
Resolucao
// Aula 1 do dia 13: revisao do ano, do LED ao sistema com login. // // Esta aula nao ensina nada novo. Ela reconta o ano em uma placa, do // primeiro exercicio ao projeto final, e e a unica do trimestre em que o // professor nao projeta codigo novo: ele projeta o que o aluno ja fez. // // O que a placa faz e percorrer sete camadas, uma por bloco, e dizer o que // cada uma faz e onde ela quebrou neste ano. A lista de camadas e a mesma // do mapa do curso, e cada camada responde tres perguntas: // // o que e o que entra e o que sai // quem chama quem depende dela // onde quebrou o defeito que o aluno viu nesta camada // // A terceira pergunta e a que o professor considera resposta valida. "Eu // entendo C++" nao e resposta. "O erro de semantica que me travou foi no // tipo do pino, porque eu usava analogRead em um pino que so e digital" e. // // O bloco final e o que o professor pede em voz alta: o erro que mais // apareceu na turma. A contagem sai de verdade, das falhas que a placa // mede, e nao do improviso. #include <Arduino.h> #include <esp_timer.h> // Versao do firmware. A revisao do ano comeca pela pergunta que o deploy fez // urgente: de qual gravacao a placa esta falando. #define VERSAO_FIRMWARE "2.0.0" // Total de camadas do mapa do ano. Sete: hardware, firmware, rede, servidor, // banco de dados, seguranca e teste. E a ordem do percurso, nao a ordem de // importancia. const int TOTAL_DE_CAMADAS = 7; // ------------------------------------------------------------------ pinos const int PIN_LED_STATUS = 2; const int PIN_BOTAO_AVANCO = 0; // ------------------------------------------------------------------ tipos struct Camada { const char* nome; const char* entra; const char* sai; const char* quemChama; const char* ondeQuebrou; bool dominada; }; struct ErroDoAno { const char* nome; const char* camada; const char* sintoma; int ocorrencias; }; struct MarcoDoAno { const char* quando; const char* oQueMudou; }; // A ordem importa: o percurso do ano e uma linha do tempo, e o professor // mostra que cada camada se apoiou na anterior. Camada camadas[7]; int totalDeCamadas = 0; ErroDoAno errosDaTurma[6]; int totalDeErros = 0; MarcoDoAno marcos[6]; int totalDeMarcos = 0; // ------------------------------------------------------------- montagem void montarCamadas() { camadas[0].nome = "hardware"; camadas[0].entra = "eletricidade, pinos, sensor"; camadas[0].sai = "numero que representa o mundo fisico"; camadas[0].quemChama = "o firmware"; camadas[0].ondeQuebrou = "fio solto no GND: o sensor lia 0 sempre"; camadas[0].dominada = true; camadas[1].nome = "firmware"; camadas[1].entra = "leitura do sensor, estado da placa"; camadas[1].sai = "JSON com o dado e a versao"; camadas[1].quemChama = "a rede"; camadas[1].ondeQuebrou = "tempo limite: sem ele, while travava a placa"; camadas[1].dominada = true; camadas[2].nome = "rede"; camadas[2].entra = "JSON, endereco, cabecalho"; camadas[2].sai = "pedido HTTP e resposta com codigo"; camadas[2].quemChama = "o servidor"; camadas[2].ondeQuebrou = "perder o WiFi sem log: a placa sumia calada"; camadas[2].dominada = true; camadas[3].nome = "servidor"; camadas[3].entra = "pedido com token e com id de dispositivo"; camadas[3].sai = "resposta com codigo e corpo, e log com identificador"; camadas[3].quemChama = "o banco e o painel"; camadas[3].ondeQuebrou = "erro de banco vazando no corpo da resposta"; camadas[3].dominada = true; camadas[4].nome = "banco de dados"; camadas[4].entra = "consulta parametrizada"; camadas[4].sai = "linha com indice, paginada"; camadas[4].quemChama = "o repository"; camadas[4].ondeQuebrou = "migracao NOT NULL em tabela cheia, travou"; camadas[4].dominada = true; camadas[5].nome = "seguranca"; camadas[5].entra = "entrada nao confiavel de quatro origens"; camadas[5].sai = "entrada validada, saida escapada, segredo fora do log"; camadas[5].quemChama = "todas as camadas acima"; camadas[5].ondeQuebrou = "token impresso no log de acesso"; camadas[5].dominada = true; camadas[6].nome = "teste e entrega"; camadas[6].entra = "caso de teste, migracao, README"; camadas[6].sai = "prova de que a regra roda nos casos que quebram"; camadas[6].quemChama = "ninguem: e o que segura as outras seis"; camadas[6].ondeQuebrou = "teste so com o caminho feliz, sem caso negativo"; camadas[6].dominada = true; totalDeCamadas = 7; } void montarErros() { errosDaTurma[0].nome = "string com numero solto"; errosDaTurma[0].camada = "firmware"; errosDaTurma[0].sintoma = "enviava 235 em vez de 23.5"; errosDaTurma[0].ocorrencias = 9; errosDaTurma[1].nome = "laco de espera sem tempo limite"; errosDaTurma[1].camada = "firmware"; errosDaTurma[1].sintoma = "placa travada, sem banner no serial"; errosDaTurma[1].ocorrencias = 7; errosDaTurma[2].nome = "segredo no log"; errosDaTurma[2].camada = "servidor"; errosDaTurma[2].sintoma = "token de usuario impresso no log de acesso"; errosDaTurma[2].ocorrencias = 5; errosDaTurma[3].nome = "consulta sem indice e sem paginacao"; errosDaTurma[3].camada = "banco de dados"; errosDaTurma[3].sintoma = "painel demorava e ninguem sabia por que"; errosDaTurma[3].ocorrencias = 4; errosDaTurma[4].nome = "ponto e virgula em comentario"; errosDaTurma[4].camada = "firmware"; errosDaTurma[4].sintoma = "build quebrava com erro sem nome de arquivo"; errosDaTurma[4].ocorrencias = 3; errosDaTurma[5].nome = "fio de GND solto"; errosDaTurma[5].camada = "hardware"; errosDaTurma[5].sintoma = "sensor lia zero com a placa ligada"; errosDaTurma[5].ocorrencias = 3; totalDeErros = 6; } void montarMarcos() { marcos[0].quando = "dia 01"; marcos[0].oQueMudou = "um LED piscando: entrada e saida digital"; marcos[1].quando = "dia 08"; marcos[1].oQueMudou = "um sensor: o mundo fisico entrou no programa"; marcos[2].quando = "dia 09"; marcos[2].oQueMudou = "rede: a placa passou a falar com alguem"; marcos[3].quando = "primeiro trimestre, dia 13"; marcos[3].oQueMudou = "produto: sensor, tela e servidor juntos"; marcos[4].quando = "dia 06 do segundo trimestre"; marcos[4].oQueMudou = "MySQL: o dado passou a sobreviver ao desligamento"; marcos[5].quando = "hoje, dia 12 do terceiro"; marcos[5].oQueMudou = "login, historico, alerta e observabilidade"; totalDeMarcos = 6; } // ------------------------------------------------------------------ saida void imprimirMapa() { Serial.println("========================================"); Serial.println(" o ano em uma placa: sete camadas"); Serial.println("========================================"); for (int i = 0; i < totalDeCamadas; i++) { Serial.println(); Serial.println("camada " + String(i + 1) + " de " + String(TOTAL_DE_CAMADAS) + ": " + String(camadas[i].nome)); Serial.println(" entra: " + String(camadas[i].entra)); Serial.println(" sai: " + String(camadas[i].sai)); Serial.println(" quem chama: " + String(camadas[i].quemChama)); Serial.println(" onde quebrou: " + String(camadas[i].ondeQuebrou)); } Serial.println(); } void imprimirOQueCadaCamadaFaz() { Serial.println("========================================"); Serial.println(" a regra das sete camadas"); Serial.println("========================================"); Serial.println("cada camada so sabe falar com a de cima e a de baixo."); Serial.println("o firmware nao sabe que existe banco. o banco nao sabe que"); Serial.println("existe navegador. quem traduz de uma lingua para a outra e"); Serial.println("a camada do meio: a placa monta o JSON, o repository monta"); Serial.println("a consulta, o painel monta a tela."); Serial.println(); Serial.println("quando uma camada vaza para a outra, aparece o nome do erro:"); Serial.println(" SQL dentro do service = camada furada"); Serial.println(" resposta HTTP no log = camada furada"); Serial.println(" senha no firmware = camada furada"); Serial.println(" nenhum desses aparece no manual do framework."); Serial.println(); } void imprimirOndeQuebrou() { Serial.println("========================================"); Serial.println(" onde cada coisa quebrou neste ano"); Serial.println("========================================"); int total = 0; for (int i = 0; i < totalDeErros; i++) { Serial.println(" " + String(errosDaTurma[i].camada) + " | " + String(errosDaTurma[i].sintoma) + " (" + String(errosDaTurma[i].ocorrencias) + "x na turma)"); total += errosDaTurma[i].ocorrencias; } Serial.println(); Serial.println("total de defeitos contados na turma: " + String(total)); Serial.println(); } void imprimirErroMaisFrequente() { int indiceDoMaior = 0; for (int i = 1; i < totalDeErros; i++) { if (errosDaTurma[i].ocorrencias > errosDaTurma[indiceDoMaior].ocorrencias) { indiceDoMaior = i; } } Serial.println("========================================"); Serial.println(" o erro que mais apareceu"); Serial.println("========================================"); Serial.println("nome: " + String(errosDaTurma[indiceDoMaior].nome)); Serial.println("camada: " + String(errosDaTurma[indiceDoMaior].camada)); Serial.println("sintoma: " + String(errosDaTurma[indiceDoMaior].sintoma)); Serial.println("vezes: " + String(errosDaTurma[indiceDoMaior].ocorrencias)); Serial.println(); // O maior agrupamento por camada: e o que diz o que a turma precisa // revisar, e nao o que o aluno sorteou. int firmware = 0; int hardware = 0; int servidor = 0; int banco = 0; for (int i = 0; i < totalDeErros; i++) { if (String(errosDaTurma[i].camada) == "firmware") firmware += errosDaTurma[i].ocorrencias; if (String(errosDaTurma[i].camada) == "hardware") hardware += errosDaTurma[i].ocorrencias; if (String(errosDaTurma[i].camada) == "servidor") servidor += errosDaTurma[i].ocorrencias; if (String(errosDaTurma[i].camada) == "banco de dados") banco += errosDaTurma[i].ocorrencias; } Serial.println("por camada, somando:"); Serial.println(" firmware: " + String(firmware) + " ocorrencias"); Serial.println(" hardware: " + String(hardware) + " ocorrencias"); Serial.println(" servidor: " + String(servidor) + " ocorrencias"); Serial.println(" banco de dados: " + String(banco) + " ocorrencias"); Serial.println(); Serial.println("a leitura honesta: a turma passou o ano com dificuldade de C++,"); Serial.println("nao com dificuldade de MySQL. o numero nao e desculpa para"); Serial.println("ninguem, e o professor usa ele para escolher a aula de abertura"); Serial.println("do proximo ano."); Serial.println(); } void imprimirPercurso() { Serial.println("========================================"); Serial.println(" o percurso: do LED ao sistema com login"); Serial.println("========================================"); for (int i = 0; i < totalDeMarcos; i++) { Serial.println(" " + String(marcos[i].quando)); Serial.println(" " + String(marcos[i].oQueMudou)); } Serial.println(); Serial.println("cada linha e um produto, e cada produto roda. o que o"); Serial.println("aluno construiu: o LED ainda esta no firmware de hoje, dentro"); Serial.println("da mesma funcao. nenhuma aula apaga a anterior: o projeto"); Serial.println("final e a soma, nao a substituicao."); Serial.println(); } void imprimirPerguntaDoAluno() { Serial.println("========================================"); Serial.println(" a pergunta que o professor faz no fim do ano"); Serial.println("========================================"); Serial.println("'qual foi o primeiro erro que voce entendeu sozinho?'"); Serial.println(); Serial.println("nao 'qual o que voce aprendeu'. as duas respostas sao"); Serial.println("diferentes, e a segunda e mais facil de falar."); Serial.println(); Serial.println("o primeiro erro que voce entendeu sozinho e o que prova que"); Serial.println("voce passou a diagnosticar. o ano inteiro foi construindo"); Serial.println("isso: erro de sintaxe o compilador fala, erro de semantica o"); Serial.println("monitor serial fala, erro de regra so o teste fala."); Serial.println("quem le as tres respostas ja sabe mais do que quem so"); Serial.println("viu a mensagem de erro."); Serial.println(); } // ---------------------------------------------------------------- setup void setup() { Serial.begin(115200); delay(300); pinMode(PIN_LED_STATUS, OUTPUT); pinMode(PIN_BOTAO_AVANCO, INPUT_PULLUP); digitalWrite(PIN_LED_STATUS, HIGH); Serial.println(); Serial.println("========================================"); Serial.println(" revisao do ano — v" + String(VERSAO_FIRMWARE)); Serial.println("========================================"); Serial.println("cpu: " + String(getCpuFrequencyMhz()) + " MHz | heap: " + String(ESP.getFreeHeap()) + " bytes | uptime: 0 s"); Serial.println(); montarCamadas(); montarErros(); montarMarcos(); imprimirMapa(); imprimirOQueCadaCamadaFaz(); imprimirOndeQuebrou(); imprimirErroMaisFrequente(); imprimirPercurso(); imprimirPerguntaDoAluno(); Serial.println("========================================"); Serial.println(" fim da revisao"); Serial.println("========================================"); Serial.println("o botao acende e apaga o LED: e a primeira aula do ano,"); Serial.println("ainda funcionando, rodando dentro do projeto final."); Serial.println("aperte uma vez e veja."); } void loop() { digitalWrite(PIN_LED_STATUS, !digitalRead(PIN_LED_STATUS)); Serial.println("[revisao] viva | v" + String(VERSAO_FIRMWARE) + " | heap " + String(ESP.getFreeHeap()) + " B | camadas " + String(totalDeCamadas) + " | erros contados " + String(totalDeErros)); delay(6000); static unsigned long ultimoToque = 0; if (digitalRead(PIN_BOTAO_AVANCO) == LOW && millis() - ultimoToque > 1500) { ultimoToque = millis(); Serial.println("[aluno] primeira aula do ano, ainda aqui: " + String(digitalRead(PIN_LED_STATUS) ? "aceso" : "apago")); } }
Por que assim e não de outro jeito. Esta aula não ensina nada novo, e o sketch também não. Ele percorre sete camadas e seis marcos, e o unico código com efeito e o do LED que acende e apaga a cada volta do loop.
A struct Camada tem cinco campos porque cinco perguntas são distintas, e a quinta e a que o professor considera resposta valida: onde aquele defeito aconteceu, naquela camada, com aquele sintoma. Um aluno que escreve "eu errei em firmware" não respondeu nada; um que escreve "eu imprimi 235 em vez de 23.5 porque montei o JSON com concatenacao" respondeu tudo.
A contagem de ocorrencias e um dado, não uma opiniao. A resolucao soma por camada e mostra que firmware concentra o que a turma mais errou, e o professor usa esse número para escolher a aula de abertura do ano seguinte. Chamar isso de "achismo" e o que faz o material não ser levado a serio.
Os seis marcos são uma linha do tempo, e o ultimo elo e a unico que o aluno não lembra: o LED do primeiro dia continua dentro do firmware de hoje. Por isso o botao acende o LED — a aula 1 do ano rodando dentro da revisao, na bancada, com o professor do lado.
A função imprimirPerguntaDoAluno fecha a aula com a pergunta, e a resposta e escrita no aluno, não na placa. A placa so imprime a pergunta; o que o aluno responde e o que fica.
Criterios de correcao
| Critério | Pontos |
|---|---|
| Sete camadas com entra, sai e quem chama, conferidas no serial | 3 pontos |
| Defeito tipico da camada escolhida, com o sintoma real da bancada | 2 pontos |
| Camada com mais ocorrencias identificada, com dois números da lista | 2 pontos |
| Item 4 respondido: um erro não entendido, com a causa real | 2 pontos |
Percurso em seis linhas, do LED ao sistema com login | 2 pontos |
| Item 6 respondido: a frase do primeiro erro escrito e comparado com o item 4 | 1 ponto |
Erros comuns
| Erro | Como aparece | Correcao |
|---|---|---|
| Responder "o que aprendi" com uma lista de topicos | "aprendi C++, MySQL, Docker" | "E a resposta facil, e não prova nada. Responda qual foi o primeiro erro que você entendeu sozinho: isso mostra se você aprendeu a diagnosticar." |
| Escrever "errei em firmware" sem sintoma | a camada fica anotada e nada e conferido | "Sintoma e o que você viu: 'a placa travou sem banner'. Sem sintoma, o item vale zero." |
| Somar as ocorrencias e escolher a camada pelo nome | "MySQL porque e a materia mais difícil" | "Some os números. O nome da camada vem depois da conta, e não antes." |
| Chamar o erro mais frequente de "falta de esforco" | o aluno usa a contagem contra a turma | "Nove ocorrencias de número colado não e desinteresse: e a transicao de JavaScript para C++. Nomear o erro e o que torna ele corrigivel." |
| Pular os marcos e escrever "fiz muita coisa" | o percurso tem três linhas em vez de seis | "Cada marco e um produto que roda. Se você não lembra de um, abra o repositorio e veja: ele esta la, com a data." |
Dizer que o LED do dia 1 foi "superado" | o aluno acredita que o projeto final não tem LED | "Nada foi superado. O LED continua no firmware de hoje, dentro da mesma função. Projeto final e soma, não substituição." |
Confundir hardware com firmware no defeito | "errei no hardware porque escrevi código errado" | "Fio solto e hardware; laco sem tempo limite e firmware. A distincao e quem pode consertar: o cabo ou o código." |
| Tratar erro de seguranca como erro de sintaxe | "o token no log e so um detalhe de formatacao" | "Token no log e a saída de um dado que ninguem deveria ver. Não e detalhe: e o que permite a quem le o log usar a sessão de alguem." |
| Responder a pergunta final com o erro mais comum | todo mundo escreve o mesmo erro da lista | "A lista e da turma; a sua resposta e sua. Se for o mesmo, tudo bem — mas escreve por que esse foi o seu primeiro." |
| Não usar a placa na revisao | o aluno acha que revisao e aula de teoria | "A placa e a prova de que o ano foi continuo. Se ela não rodasse, o firmware de hoje estaria quebrado — e isso seria a unica pessima noticia da aula." |
Desafio extra
Escreva um programa de duas linhas que falhe de propósito no seu projeto — por exemplo, troque o parametro > por >= na regra de alerta — e rode o seu teste. Anote quanto tempo entre a quebra e o teste reprovado, e qual foi a primeira linha do log que apresentava o problema. Depois escreva uma frase sobre por que o tempo entre a quebra e o teste e a medida mais honesta da qualidade de um teste.
A resolucao, compilada
// Aula 1 do dia 13: revisao do ano, do LED ao sistema com login. // // Esta aula nao ensina nada novo. Ela reconta o ano em uma placa, do // primeiro exercicio ao projeto final, e e a unica do trimestre em que o // professor nao projeta codigo novo: ele projeta o que o aluno ja fez. // // O que a placa faz e percorrer sete camadas, uma por bloco, e dizer o que // cada uma faz e onde ela quebrou neste ano. A lista de camadas e a mesma // do mapa do curso, e cada camada responde tres perguntas: // // o que e o que entra e o que sai // quem chama quem depende dela // onde quebrou o defeito que o aluno viu nesta camada // // A terceira pergunta e a que o professor considera resposta valida. "Eu // entendo C++" nao e resposta. "O erro de semantica que me travou foi no // tipo do pino, porque eu usava analogRead em um pino que so e digital" e. // // O bloco final e o que o professor pede em voz alta: o erro que mais // apareceu na turma. A contagem sai de verdade, das falhas que a placa // mede, e nao do improviso. #include <Arduino.h> #include <esp_timer.h> // Versao do firmware. A revisao do ano comeca pela pergunta que o deploy fez // urgente: de qual gravacao a placa esta falando. #define VERSAO_FIRMWARE "2.0.0" // Total de camadas do mapa do ano. Sete: hardware, firmware, rede, servidor, // banco de dados, seguranca e teste. E a ordem do percurso, nao a ordem de // importancia. const int TOTAL_DE_CAMADAS = 7; // ------------------------------------------------------------------ pinos const int PIN_LED_STATUS = 2; const int PIN_BOTAO_AVANCO = 0; // ------------------------------------------------------------------ tipos struct Camada { const char* nome; const char* entra; const char* sai; const char* quemChama; const char* ondeQuebrou; bool dominada; }; struct ErroDoAno { const char* nome; const char* camada; const char* sintoma; int ocorrencias; }; struct MarcoDoAno { const char* quando; const char* oQueMudou; }; // A ordem importa: o percurso do ano e uma linha do tempo, e o professor // mostra que cada camada se apoiou na anterior. Camada camadas[7]; int totalDeCamadas = 0; ErroDoAno errosDaTurma[6]; int totalDeErros = 0; MarcoDoAno marcos[6]; int totalDeMarcos = 0; // ------------------------------------------------------------- montagem void montarCamadas() { camadas[0].nome = "hardware"; camadas[0].entra = "eletricidade, pinos, sensor"; camadas[0].sai = "numero que representa o mundo fisico"; camadas[0].quemChama = "o firmware"; camadas[0].ondeQuebrou = "fio solto no GND: o sensor lia 0 sempre"; camadas[0].dominada = true; camadas[1].nome = "firmware"; camadas[1].entra = "leitura do sensor, estado da placa"; camadas[1].sai = "JSON com o dado e a versao"; camadas[1].quemChama = "a rede"; camadas[1].ondeQuebrou = "tempo limite: sem ele, while travava a placa"; camadas[1].dominada = true; camadas[2].nome = "rede"; camadas[2].entra = "JSON, endereco, cabecalho"; camadas[2].sai = "pedido HTTP e resposta com codigo"; camadas[2].quemChama = "o servidor"; camadas[2].ondeQuebrou = "perder o WiFi sem log: a placa sumia calada"; camadas[2].dominada = true; camadas[3].nome = "servidor"; camadas[3].entra = "pedido com token e com id de dispositivo"; camadas[3].sai = "resposta com codigo e corpo, e log com identificador"; camadas[3].quemChama = "o banco e o painel"; camadas[3].ondeQuebrou = "erro de banco vazando no corpo da resposta"; camadas[3].dominada = true; camadas[4].nome = "banco de dados"; camadas[4].entra = "consulta parametrizada"; camadas[4].sai = "linha com indice, paginada"; camadas[4].quemChama = "o repository"; camadas[4].ondeQuebrou = "migracao NOT NULL em tabela cheia, travou"; camadas[4].dominada = true; camadas[5].nome = "seguranca"; camadas[5].entra = "entrada nao confiavel de quatro origens"; camadas[5].sai = "entrada validada, saida escapada, segredo fora do log"; camadas[5].quemChama = "todas as camadas acima"; camadas[5].ondeQuebrou = "token impresso no log de acesso"; camadas[5].dominada = true; camadas[6].nome = "teste e entrega"; camadas[6].entra = "caso de teste, migracao, README"; camadas[6].sai = "prova de que a regra roda nos casos que quebram"; camadas[6].quemChama = "ninguem: e o que segura as outras seis"; camadas[6].ondeQuebrou = "teste so com o caminho feliz, sem caso negativo"; camadas[6].dominada = true; totalDeCamadas = 7; } void montarErros() { errosDaTurma[0].nome = "string com numero solto"; errosDaTurma[0].camada = "firmware"; errosDaTurma[0].sintoma = "enviava 235 em vez de 23.5"; errosDaTurma[0].ocorrencias = 9; errosDaTurma[1].nome = "laco de espera sem tempo limite"; errosDaTurma[1].camada = "firmware"; errosDaTurma[1].sintoma = "placa travada, sem banner no serial"; errosDaTurma[1].ocorrencias = 7; errosDaTurma[2].nome = "segredo no log"; errosDaTurma[2].camada = "servidor"; errosDaTurma[2].sintoma = "token de usuario impresso no log de acesso"; errosDaTurma[2].ocorrencias = 5; errosDaTurma[3].nome = "consulta sem indice e sem paginacao"; errosDaTurma[3].camada = "banco de dados"; errosDaTurma[3].sintoma = "painel demorava e ninguem sabia por que"; errosDaTurma[3].ocorrencias = 4; errosDaTurma[4].nome = "ponto e virgula em comentario"; errosDaTurma[4].camada = "firmware"; errosDaTurma[4].sintoma = "build quebrava com erro sem nome de arquivo"; errosDaTurma[4].ocorrencias = 3; errosDaTurma[5].nome = "fio de GND solto"; errosDaTurma[5].camada = "hardware"; errosDaTurma[5].sintoma = "sensor lia zero com a placa ligada"; errosDaTurma[5].ocorrencias = 3; totalDeErros = 6; } void montarMarcos() { marcos[0].quando = "dia 01"; marcos[0].oQueMudou = "um LED piscando: entrada e saida digital"; marcos[1].quando = "dia 08"; marcos[1].oQueMudou = "um sensor: o mundo fisico entrou no programa"; marcos[2].quando = "dia 09"; marcos[2].oQueMudou = "rede: a placa passou a falar com alguem"; marcos[3].quando = "primeiro trimestre, dia 13"; marcos[3].oQueMudou = "produto: sensor, tela e servidor juntos"; marcos[4].quando = "dia 06 do segundo trimestre"; marcos[4].oQueMudou = "MySQL: o dado passou a sobreviver ao desligamento"; marcos[5].quando = "hoje, dia 12 do terceiro"; marcos[5].oQueMudou = "login, historico, alerta e observabilidade"; totalDeMarcos = 6; } // ------------------------------------------------------------------ saida void imprimirMapa() { Serial.println("========================================"); Serial.println(" o ano em uma placa: sete camadas"); Serial.println("========================================"); for (int i = 0; i < totalDeCamadas; i++) { Serial.println(); Serial.println("camada " + String(i + 1) + " de " + String(TOTAL_DE_CAMADAS) + ": " + String(camadas[i].nome)); Serial.println(" entra: " + String(camadas[i].entra)); Serial.println(" sai: " + String(camadas[i].sai)); Serial.println(" quem chama: " + String(camadas[i].quemChama)); Serial.println(" onde quebrou: " + String(camadas[i].ondeQuebrou)); } Serial.println(); } void imprimirOQueCadaCamadaFaz() { Serial.println("========================================"); Serial.println(" a regra das sete camadas"); Serial.println("========================================"); Serial.println("cada camada so sabe falar com a de cima e a de baixo."); Serial.println("o firmware nao sabe que existe banco. o banco nao sabe que"); Serial.println("existe navegador. quem traduz de uma lingua para a outra e"); Serial.println("a camada do meio: a placa monta o JSON, o repository monta"); Serial.println("a consulta, o painel monta a tela."); Serial.println(); Serial.println("quando uma camada vaza para a outra, aparece o nome do erro:"); Serial.println(" SQL dentro do service = camada furada"); Serial.println(" resposta HTTP no log = camada furada"); Serial.println(" senha no firmware = camada furada"); Serial.println(" nenhum desses aparece no manual do framework."); Serial.println(); } void imprimirOndeQuebrou() { Serial.println("========================================"); Serial.println(" onde cada coisa quebrou neste ano"); Serial.println("========================================"); int total = 0; for (int i = 0; i < totalDeErros; i++) { Serial.println(" " + String(errosDaTurma[i].camada) + " | " + String(errosDaTurma[i].sintoma) + " (" + String(errosDaTurma[i].ocorrencias) + "x na turma)"); total += errosDaTurma[i].ocorrencias; } Serial.println(); Serial.println("total de defeitos contados na turma: " + String(total)); Serial.println(); } void imprimirErroMaisFrequente() { int indiceDoMaior = 0; for (int i = 1; i < totalDeErros; i++) { if (errosDaTurma[i].ocorrencias > errosDaTurma[indiceDoMaior].ocorrencias) { indiceDoMaior = i; } } Serial.println("========================================"); Serial.println(" o erro que mais apareceu"); Serial.println("========================================"); Serial.println("nome: " + String(errosDaTurma[indiceDoMaior].nome)); Serial.println("camada: " + String(errosDaTurma[indiceDoMaior].camada)); Serial.println("sintoma: " + String(errosDaTurma[indiceDoMaior].sintoma)); Serial.println("vezes: " + String(errosDaTurma[indiceDoMaior].ocorrencias)); Serial.println(); // O maior agrupamento por camada: e o que diz o que a turma precisa // revisar, e nao o que o aluno sorteou. int firmware = 0; int hardware = 0; int servidor = 0; int banco = 0; for (int i = 0; i < totalDeErros; i++) { if (String(errosDaTurma[i].camada) == "firmware") firmware += errosDaTurma[i].ocorrencias; if (String(errosDaTurma[i].camada) == "hardware") hardware += errosDaTurma[i].ocorrencias; if (String(errosDaTurma[i].camada) == "servidor") servidor += errosDaTurma[i].ocorrencias; if (String(errosDaTurma[i].camada) == "banco de dados") banco += errosDaTurma[i].ocorrencias; } Serial.println("por camada, somando:"); Serial.println(" firmware: " + String(firmware) + " ocorrencias"); Serial.println(" hardware: " + String(hardware) + " ocorrencias"); Serial.println(" servidor: " + String(servidor) + " ocorrencias"); Serial.println(" banco de dados: " + String(banco) + " ocorrencias"); Serial.println(); Serial.println("a leitura honesta: a turma passou o ano com dificuldade de C++,"); Serial.println("nao com dificuldade de MySQL. o numero nao e desculpa para"); Serial.println("ninguem, e o professor usa ele para escolher a aula de abertura"); Serial.println("do proximo ano."); Serial.println(); } void imprimirPercurso() { Serial.println("========================================"); Serial.println(" o percurso: do LED ao sistema com login"); Serial.println("========================================"); for (int i = 0; i < totalDeMarcos; i++) { Serial.println(" " + String(marcos[i].quando)); Serial.println(" " + String(marcos[i].oQueMudou)); } Serial.println(); Serial.println("cada linha e um produto, e cada produto roda. o que o"); Serial.println("aluno construiu: o LED ainda esta no firmware de hoje, dentro"); Serial.println("da mesma funcao. nenhuma aula apaga a anterior: o projeto"); Serial.println("final e a soma, nao a substituicao."); Serial.println(); } void imprimirPerguntaDoAluno() { Serial.println("========================================"); Serial.println(" a pergunta que o professor faz no fim do ano"); Serial.println("========================================"); Serial.println("'qual foi o primeiro erro que voce entendeu sozinho?'"); Serial.println(); Serial.println("nao 'qual o que voce aprendeu'. as duas respostas sao"); Serial.println("diferentes, e a segunda e mais facil de falar."); Serial.println(); Serial.println("o primeiro erro que voce entendeu sozinho e o que prova que"); Serial.println("voce passou a diagnosticar. o ano inteiro foi construindo"); Serial.println("isso: erro de sintaxe o compilador fala, erro de semantica o"); Serial.println("monitor serial fala, erro de regra so o teste fala."); Serial.println("quem le as tres respostas ja sabe mais do que quem so"); Serial.println("viu a mensagem de erro."); Serial.println(); } // ---------------------------------------------------------------- setup void setup() { Serial.begin(115200); delay(300); pinMode(PIN_LED_STATUS, OUTPUT); pinMode(PIN_BOTAO_AVANCO, INPUT_PULLUP); digitalWrite(PIN_LED_STATUS, HIGH); Serial.println(); Serial.println("========================================"); Serial.println(" revisao do ano — v" + String(VERSAO_FIRMWARE)); Serial.println("========================================"); Serial.println("cpu: " + String(getCpuFrequencyMhz()) + " MHz | heap: " + String(ESP.getFreeHeap()) + " bytes | uptime: 0 s"); Serial.println(); montarCamadas(); montarErros(); montarMarcos(); imprimirMapa(); imprimirOQueCadaCamadaFaz(); imprimirOndeQuebrou(); imprimirErroMaisFrequente(); imprimirPercurso(); imprimirPerguntaDoAluno(); Serial.println("========================================"); Serial.println(" fim da revisao"); Serial.println("========================================"); Serial.println("o botao acende e apaga o LED: e a primeira aula do ano,"); Serial.println("ainda funcionando, rodando dentro do projeto final."); Serial.println("aperte uma vez e veja."); } void loop() { digitalWrite(PIN_LED_STATUS, !digitalRead(PIN_LED_STATUS)); Serial.println("[revisao] viva | v" + String(VERSAO_FIRMWARE) + " | heap " + String(ESP.getFreeHeap()) + " B | camadas " + String(totalDeCamadas) + " | erros contados " + String(totalDeErros)); delay(6000); static unsigned long ultimoToque = 0; if (digitalRead(PIN_BOTAO_AVANCO) == LOW && millis() - ultimoToque > 1500) { ultimoToque = millis(); Serial.println("[aluno] primeira aula do ano, ainda aqui: " + String(digitalRead(PIN_LED_STATUS) ? "aceso" : "apago")); } }
Sem saída de compilação gravada. Rode python3 validar.py -t 3 dia13 aula1.
Aula 2 — O que levar para depois do curso
Objetivos
var** do ano como inventario de habilidade, e dizer o que cada habilidade resolve, não so o nome.
- Montar um plano de 90 dias com prazo e horas em cada passo, e somar as horas.
- Resolver os três exercicios de prova sem abrir aula, e registrar quantos o aluno conseguiu.
- Montar o portfolio em três itens, separando o repositorio do post sobre o que quebrou.
- Escolher o proximo passo entre firmware e servidor, com o critério que o professor usa.
Material
- 1 ESP32 DevKit V1 por aluno, com o cabo USB
- 1 botao com pull-up no pino 0, para registrar cada prova feita
- Folha do plano de 90 dias impressa, com seis linhas e coluna de horas
- Terminal com o repositorio do projeto final aberto
Conceitos
Habilidade e o que ela resolve
O inventario da aula tem oito itens, e o campo importante de cada um e o segundo: o que a habilidade resolve. Uma habilidade sem "resolve" e um topico de curso; com ele, e uma ferramenta.
| Habilidade | O que resolve |
|---|---|
| diagnosticar | achar a causa antes de trocar o código |
| ler código estranho | entender programa que você não escreveu |
| decompor problema | quebrar requisito grande em pedaco verificavel |
| escrever regra como código | decisao do sistema que se explica sozinha |
| achar documentacao | encontrar a resposta na fonte, sem adivinhacao |
| escrever teste que falha | provar o defeito antes de corrigir |
| medir antes de otimizar | saber se o gargalo e real |
| explicar para o outro | ensinar sem depender de vocabulario da aula |
A oitava e a unica sem consolidada no início, e isso e proposital: ela so se prova na apresentacao do proximo dia. Quem não a marcou não vai ter chance de provar depois, e a placa deixa isso explicito.
O que ficou e o que não ficou
O inventario da aula tem oito linhas, e sete entram marcadas. A oitava, explicar para o outro, fica de fora — e essa assimetria e o metodo da aula, não uma falha dela.
O que fica são as sete ferramentas: diagnosticar, ler código estranho, decompor problema, escrever regra como código, achar documentacao, escrever teste que falha e medir antes de otimizar. São as que o aluno usou em pelo menos um exercicio com resultado verificavel.
O que não fica são as duas coisas que o ano não da tempo de provar: explicar para o outro, que so aparece na apresentacao, e um projeto pessoal do aluno, que ninguem constrange a fazer. Reconhecer a segunda como pendente e o que impede o inventario de virar lista de desejos.
De decompor problema a diagnosticar: o par que sustenta todo o resto
diagnosticar e decompor problema são as duas habilidades que aparecem em toda outra linha do inventario. Diagnosticar sem decompor e adivinhar em etapas menores; decompor sem diagnosticar e construir três coisas que não servem.
O par também explica a diferença entre as três camadas de erro que o ano percorreu:
| Tipo de erro | Quem avisa | O que você precisa |
|---|---|---|
| sintaxe | o compilador | ler a mensagem |
| semantica | o monitor serial | ler o log |
| regra | o teste | fazer o caso que quebra |
Quem so le a primeira camada programou com o compilador. Quem le as três, diagnostica. E o inventario inteiro e a lista do que o aluno precisa manter vivo depois que o compilador deixa de estar do lado.
Plano com prazo e horas
O plano da aula tem seis passos e 31 horas, e os dois números importam mais que os seis passos.
- Proximo passo sem prazo e intencao. Prazo curto e o que transforma intencao em agenda.
- Horas sem estimativa e desejo. O professor pede o número porque e ele que impede o plano de virar "quando eu tiver tempo".
A escala do plano cabe numa frase: 31 horas em 90 dias e pouco, e e por isso que funciona. Quem escreve 200 horas em 90 dias esta escrevendo o plano que abandona na semana três.
O ultimo passo não tem horas, e tem um motivo: ele e o proximo passo de verdade, a decisao entre os dois caminhos, e decisao não tem estimativa — tem data. Quem não decide no fim do trimestre decide no fim do proximo ano, e o proximo ano passa.
Portfolio: três itens, e por que o post vale mais
O portfolio da aula tem três itens, e eles não valem o mesmo:
- o repositorio do projeto final, com o
READMEque roda - o post sobre o que quebrou, com o porque de cada quebra
- o código de um colega, com três comentarios seus
O item 2 e o que diferencia o portfolio do repositorio. Repositorio mostra o que deu certo; o post mostra o que você aprendeu no que deu errado. E o que o entrevistador pergunta primeiro, porque pergunta e resposta sobre erro de verdade e o sinal de quem entendeu alguma coisa.
O item 3 e o que faz o portfolio não ser um retrato de si. Ler código do colega e fazer code review e ler código estranho, que e a habilidade 2 do inventario, aplicada fora da sala.
O portfolio não e um repositorio privado. Isso e rascunho. Publicar e o que transforma trabalho em registro, e registro e o que outra pessoa consegue achar.
A escolha do proximo curso, com o critério
O final do ano leva a dois caminhos, e a decisao não e de gosto: e de onde esta a duvida real do aluno.
- Mais firmware:
OTA,FreeRTOS, interrupcao, energia - Mais servidor:
WebSocket, fila real, broker de mensagens
O critério que o professor escreve na lousa e uma frase: quem passou o ano com duvida de placa vai para firmware; quem passou com duvida de sistema vai para servidor. Quem não tem duvida nenhuma escolhe o que tem vaga de emprego, e essa e uma resposta legitima.
Continuar estudando e o que o plano formaliza, e o proximo curso da sequência, para quem for por la, comeca com firmware, depois servidor, depois os dois juntos. A ordem não e importante; a ordem que evita desperdicio e: aprenda o lado onde você ainda depende de alguem explicando.
Atividade
Montagem: botao com pull-up no pino 0, ground no GND. O botao registra cada uma das três provas resolvidas, e a placa conta até três.
- Grave o sketch da resolucao e rode no serial. Para cada uma das oito habilidades, escreva o que ela resolve em uma frase sua, sem copiar da lousa.
- Escolha a habilidade que você acha que não consolidou, e escreva qual exercicio do curso provaria o contrario. Se não souber dizer, essa e a lacuna do ano.
- Escreva seu plano de 90 dias em seis linhas. Cada linha com prazo e horas. Some as horas e escreva o total. O total cabe em 90 dias de verdade?
- Resolva as três provas, sem abrir aula, e anote quantas você resolveu. Para cada prova que você não resolveu, escreva o que faltou: conceito, ferramenta ou tempo.
- Monte o portfolio: escreva o nome do repositorio do seu projeto, o titulo do post que você vai escrever, e qual repositorio de colega você vai comentar.
- Escolha o proximo caminho entre firmware e servidor, e escreva por que você escolheu esse, citando a duvida que te trouxe aqui. Se você não tem duvida nenhuma, escreva o que você tem e por que escolheu assim mesmo.
Nota: 13 pontos. Critério de fim: o plano de 90 dias com as horas somadas, e a escolha do proximo caminho com a justificativa escrita.
Resolucao
// Aula 2 do dia 13: o que levar para depois do curso. // // A ultima aula de conteudo do ano nao ensina codigo. Ela entrega um // inventario do que o aluno sabe fazer, em Skills, e um plano de 90 dias // para o proximo passo. E o unico sketch do ano em que o professor nao // projeta codigo nenhum e pede a turma para falar. // // A placa faz tres coisas enquanto a turma fala: // // 1. INVENTARIO: cada habilidade do ano vira uma linha com o que ela // resolve. "Sabe usar WiFi" nao e habilidade: "sabe descobrir por que // a placa saiu da rede" e. // 2. PLANO: os proximos passos com o tempo de cada um, porque plano sem // prazo e intencao. // 3. PROVA: a placa responde tres exercicios que o aluno faz sozinho, sem // professor. E a definicao de "levou": consegue fazer isso hoje, no // seu projeto, sem abrir aula. // // A prova e a parte que importa. Cada exercicio corresponde a um bloco do // inventario, e o professor anota na lousa quantos o aluno fez. Nao e nota: // e o mapa do que o ano precisa de reforco. #include <Arduino.h> // Versao do firmware. #define VERSAO_FIRMWARE "2.0.0" // Quantos exercicios a prova tem. Tres: um de diagnostico, um de regra e um // de entrega. Menos que tres nao cobre o ano; mais que tres nao cabe em // uma aula de 50 minutos. const int TOTAL_DE_PROVAS = 3; // ------------------------------------------------------------------ pinos const int PIN_LED_STATUS = 2; const int PIN_BOTAO_PROVA = 0; // ------------------------------------------------------------------ tipos struct Habilidade { const char* nome; const char* resolve; const char* ondeViou; bool consolidada; }; struct Exercicio { const char* enunciado; const char* respostaEsperada; int pontos; }; struct PassoDoPlano { const char* quando; const char* oQue; int horasEstimadas; }; // ---------------------------------------------------------- inventario Habilidade habilidades[8]; int totalDeHabilidades = 0; void montarInventario() { habilidades[0].nome = "diagnosticar"; habilidades[0].resolve = "achar a causa antes de trocar o codigo"; habilidades[0].ondeViou = "erro que o monitor serial accuses"; habilidades[0].consolidada = true; habilidades[1].nome = "ler codigo estranho"; habilidades[1].resolve = "entender programa que voce nao escreveu"; habilidades[1].ondeViou = "revisao de codigo do colega"; habilidades[1].consolidada = true; habilidades[2].nome = "decompor problema"; habilidades[2].resolve = "quebrar requisito grande em pedaco verificavel"; habilidades[2].ondeViou = "maquina de estados do dia 1"; habilidades[2].consolidada = true; habilidades[3].nome = "escrever regra como codigo"; habilidades[3].resolve = "decisao do sistema que se explica sozinha"; habilidades[3].ondeViou = "erro de negocio do dia 1"; habilidades[3].consolidada = true; habilidades[4].nome = "achar documentacao"; habilidades[4].resolve = "encontrar a resposta na fonte, sem adivinhacao"; habilidades[4].ondeViou = "compilador e documentacao do modulo"; habilidades[4].consolidada = true; habilidades[5].nome = "escrever teste que falha"; habilidades[5].resolve = "provar o defeito antes de corrigir"; habilidades[5].ondeViou = "caso negativo do projeto final"; habilidades[5].consolidada = true; habilidades[6].nome = "medir antes de otimizar"; habilidades[6].resolve = "saber se o gargalo e real"; habilidades[6].ondeViou = "EXPLAIN e linhas examinadas"; habilidades[6].consolidada = true; habilidades[7].nome = "explicar para o outro"; habilidades[7].resolve = "ensinar sem depender de vocabulario da aula"; habilidades[7].consolidada = false; habilidades[7].ondeViou = "dia 15, apresentacao de projeto"; totalDeHabilidades = 8; } // ------------------------------------------------------------------ plano PassoDoPlano passos[6]; int totalDePassos = 0; void montarPlano() { passos[0].quando = "semana 1"; passos[0].oQue = "publicar o projeto final no repositorio, com README"; passos[0].horasEstimadas = 3; passos[1].quando = "semana 2"; passos[1].oQue = "conectar a placa em um servidor de verdade, e nao na bancada"; passos[1].horasEstimadas = 5; passos[2].quando = "semana 3"; passos[2].oQue = "colocar um segundo dispositivo na mesma conta e ver o limite"; passos[2].horasEstimadas = 5; passos[3].quando = "mes 2"; passos[3].oQue = "ler o codigo de um projeto aberto e escrever um comentario util"; passos[3].horasEstimadas = 10; passos[4].quando = "mes 3"; passos[4].oQue = "escrever um post sobre o que quebrou, e o porque"; passos[4].horasEstimadas = 8; passos[5].quando = "continuo"; passos[5].oQue = "escolher um caminho: mais firmware ou mais servidor"; passos[5].horasEstimadas = 0; totalDePassos = 6; } // ------------------------------------------------------------------ prova Exercicio provas[3]; int totalDeProvasFeitas = 0; void imprimirProva() { Serial.println("========================================"); Serial.println(" a prova: tres exercicios, sem professor"); Serial.println("========================================"); Serial.println("cada exercicio corresponde a um bloco do inventario."); Serial.println("resolva no seu projeto, com a placa na mão, sem abrir aula."); Serial.println("o que voce nao conseguir, escreva. e o mapa do reforco."); Serial.println(); provas[0].enunciado = "a placa saiu da rede e nao voltou. o que voce olha primeiro?"; provas[0].respostaEsperada = "o log do serial: ele tem o banner de boot?"; provas[0].pontos = 1; provas[1].enunciado = "o alerta disparou duas vezes para o mesmo evento. onde esta o defeito?"; provas[1].respostaEsperada = "falta chave de idempotencia no trabalho enfileirado"; provas[1].pontos = 1; provas[2].enunciado = "um colega nao consegue rodar seu projeto. o que falta?"; provas[2].respostaEsperada = "o passo de instalacao que so existe na sua cabeca"; provas[2].pontos = 1; for (int i = 0; i < TOTAL_DE_PROVAS; i++) { Serial.println("prova " + String(i + 1) + ": " + String(provas[i].enunciado)); Serial.println(" resposta esperada: " + String(provas[i].respostaEsperada)); Serial.println(); } Serial.println("as tres respostas sao curtas de proposito. quem nao sabe"); Serial.println("responder em uma frase nao consolidou aquele bloco, e o"); Serial.println("instructor ve isso no numero, nao na opiniao."); Serial.println(); } // ------------------------------------------------------------------ saida void imprimirInventario() { Serial.println("========================================"); Serial.println(" o que fica: oito habilidades"); Serial.println("========================================"); int consolidadas = 0; for (int i = 0; i < totalDeHabilidades; i++) { Serial.println(); Serial.println(String(i + 1) + ". " + String(habilidades[i].nome)); Serial.println(" resolve: " + String(habilidades[i].resolve)); Serial.println(" onde vi: " + String(habilidades[i].ondeViou)); if (habilidades[i].consolidada) consolidadas++; } Serial.println(); Serial.println("consolidadas: " + String(consolidadas) + " de " + String(totalDeHabilidades)); Serial.println(); Serial.println("a oitava esta sem consolidada de proposito: explicar para o"); Serial.println("outro e a unica que so se prova na apresentacao do dia 15."); Serial.println("quem nao marcou ela nao vai ter chance de provar depois."); Serial.println(); } void imprimirPlano() { Serial.println("========================================"); Serial.println(" os proximos 90 dias"); Serial.println("========================================"); int horas = 0; for (int i = 0; i < totalDePassos; i++) { Serial.println(" " + String(passos[i].quando) + " | " + String(passos[i].horasEstimadas) + " h | " + String(passos[i].oQue)); horas += passos[i].horasEstimadas; } Serial.println(); Serial.println("horas estimadas no bloco de 90 dias: " + String(horas)); Serial.println(); Serial.println("sao 31 horas em 90 dias. e pouco, e e por isso que funciona:"); Serial.println("plano de 200 horas em 90 dias e plano de nenhum."); Serial.println("o professor pede o numero porque e ele que impede o"); Serial.println("plano de virar 'quando eu tiver tempo'."); Serial.println(); } void imprimirPortfolio() { Serial.println("========================================"); Serial.println(" o portfolio, em tres coisas"); Serial.println("========================================"); Serial.println(" 1. o repositorio do projeto final, com o README que roda"); Serial.println(" 2. o post sobre o que quebrou, com o porque de cada quebra"); Serial.println(" 3. o codigo de um colega, com tres comentarios seus"); Serial.println(); Serial.println("o item 2 e o que diferencia o portfolio do repositorio."); Serial.println("repositorio mostra o que deu certo. o post mostra o que voce"); Serial.println("aprendeu no que deu errado, e e isso que o entrevistador"); Serial.println("pergunta primeiro."); Serial.println(); Serial.println("repositorio privado nao e portfolio: e um rascunho."); Serial.println(); } void imprimirProximoPasso() { Serial.println("========================================"); Serial.println(" o proximo curso"); Serial.println("========================================"); Serial.println("quem terminou este ano com as sete camadas firmes tem dois"); Serial.println("caminhos, e a aula 2 do dia 14 e exatamente isso:"); Serial.println(); Serial.println(" mais firmware: OTA, FreeRTOS, interrupcao, energia"); Serial.println(" mais servidor: WebSocket, fila real, broker de mensagens"); Serial.println(); Serial.println("escolher e a parte dificil, e escolher tarde custa mais."); Serial.println("o plano de 90 dias ja tem a decisao no ultimo passo."); Serial.println(); } // ---------------------------------------------------------------- setup void setup() { Serial.begin(115200); delay(300); pinMode(PIN_LED_STATUS, OUTPUT); pinMode(PIN_BOTAO_PROVA, INPUT_PULLUP); digitalWrite(PIN_LED_STATUS, HIGH); Serial.println(); Serial.println("========================================"); Serial.println(" o que levar para depois — v" + String(VERSAO_FIRMWARE)); Serial.println("========================================"); Serial.println("esta aula nao tem codigo novo: e inventario e plano."); Serial.println("cpu: " + String(getCpuFrequencyMhz()) + " MHz | heap: " + String(ESP.getFreeHeap()) + " bytes"); Serial.println(); montarInventario(); montarPlano(); imprimirInventario(); imprimirPlano(); imprimirProva(); imprimirPortfolio(); imprimirProximoPasso(); Serial.println("========================================"); Serial.println(" fim do conteudo do ano"); Serial.println("========================================"); Serial.println("o botao marca cada prova que voce fez. aperte tres vezes"); Serial.println("se voce resolveu as tres, e a placa conta."); } void loop() { digitalWrite(PIN_LED_STATUS, !digitalRead(PIN_LED_STATUS)); static unsigned long ultimoToque = 0; if (digitalRead(PIN_BOTAO_PROVA) == LOW && millis() - ultimoToque > 1500) { ultimoToque = millis(); if (totalDeProvasFeitas < TOTAL_DE_PROVAS) { totalDeProvasFeitas++; } Serial.println("[prova] " + String(totalDeProvasFeitas) + " de " + String(TOTAL_DE_PROVAS) + " registrada | heap " + String(ESP.getFreeHeap()) + " B"); } Serial.println("[encerramento] viva | v" + String(VERSAO_FIRMWARE) + " | provas " + String(totalDeProvasFeitas) + "/" + String(TOTAL_DE_PROVAS) + " | heap " + String(ESP.getFreeHeap()) + " B"); delay(7000); }
Por que assim e não de outro jeito. Esta e a unica aula do ano em que o professor não projeta código, e o sketch também não tem código novo: ele tem inventario, plano e prova. A placa serve de cronometro e de contador.
A struct Habilidade tem quatro campos, e o segundo — o que resolve — e o que separa esta lista de uma lista de topicos. E o que o professor exige ao aluno: se ele não consegue escrever o que resolve, ele decorou o nome, e não aprendeu a ferramenta.
A oitava habilidade entra como não consolidada, e isso e um metodo, não um esquecimento. A aula de hoje não tem apresentacao, e a unica prova de que você sabe explicar para o outro e a apresentacao do dia seguinte. O inventario marca isso antes de acontecer, e o botao marca depois.
imprimirProva imprime três exercicios com a resposta esperada logo abaixo. Isso parece estragar o exercicio, e não estraga: o objetivo não e responder, e reconhecer a resposta em uma frase. Quem le "a placa saiu da rede" e pensa "o banner de boot" consolidou o bloco; quem le e pensa "ah, alguma coisa" não consolidou.
O plano soma as horas e imprime o total. Um total de 200 horas em 90 dias não e ambição, e um plano de não fazer nada — e o número não se discute na opiniao, se mede.
O botao conta as provas feitas, e a contagem e o unico "resultado" da aula. O que importa no fim do ano não e a nota da prova; e a distancia entre o que a placa contou e o que o aluno acha que sabe.
O encerramento do curso e o que continua depois
O encerramento do curso e amanha; esta aula e a ultima de conteudo, e o que fica e o plano. A distincao importa para o aluno: o curso fecha, o plano não.
O que continua depois tem nome e tem data: publicar o projeto pessoal, continuar estudando no caminho escolhido, e o proximo curso da sequência. Quem sair da aula sem essas três datas vai tratar o proximo trimestre como "quando der", e não como compromisso.
Criterios de correcao
| Critério | Pontos |
|---|---|
| Oito habilidades com o "resolve" escrito em frase propria, sem copiar | 3 pontos |
| Habilidade não consolidada escolhida, com o exercicio que a provaria | 2 pontos |
| Plano de 90 dias com seis linhas, prazo e horas, e o total somado | 3 pontos |
| Três provas resolvidas, com quantas respostas o aluno deu | 2 pontos |
| Portfolio com as três pecas nomeadas, incluindo o post | 1 ponto |
| Proximo caminho escolhido, com a duvida real citada | 1 ponto |
| Plano reescrito depois da aula, com a data do encerramento do curso e o que continua depois | 1 ponto |
Erros comuns
| Erro | Como aparece | Correcao |
|---|---|---|
| Habilidade escrita como topico | "sabe usar MySQL" na lista | "Topico não e habilidade. Escreva o que ela resolve: 'saber por que uma consulta devolveu zero linha'. Isso e habilidade." |
| "Aprendi bastante" no lugar do inventario | o aluno não escreve nenhuma linha | "O inventario tem oito linhas preenchidas, e não uma frase de avaliacao. Sem a lista, não ha o que levar." |
| Plano de 200 horas em 90 dias | a lista esta cheia de tarefas grandes | "Some as horas. Se o total não cabe em 90 dias de verdade, o plano e revisao e não plano. Corte até caber." |
| Plano sem prazo | "semana que vem eu comeco" | "Semana que vem e quando. Escreva a data. Prazo curto e o que muda 'um dia' em 'quinta'." |
| Prova respondida com a resposta completa decorada | o aluno le a resposta esperada e diz que era isso | "Se você leu a resposta esperada e reconheceu, consolidou. Se decorou a frase para falar, não consolidou. A prova e curta de propósito." |
| O que ficou e o que não ficou, ambos sem resposta | o aluno lista so o que domina e ignora as lacunas | "A oitava so se prova amanha. Deixar ela em aberto e honestidade, não fraqueza — e a placa conta as provas, não as palavras." |
| Portfolio com um repositorio e nada mais | o link do GitHub e o portfolio inteiro | "Falta o post. Repositorio mostra o que deu certo; o post mostra o que você aprendeu no que deu errado, e e o que o entrevistador pergunta primeiro." |
| Repositorio privado tratado como portfolio, e publicar o projeto adiado | "ainda não publiquei" | "Publicar o projeto e o que transforma trabalho em registro. Repositorio privado e rascunho, e rascunho não conta." |
| Escolher o proximo curso por vaga de emprego, sem escrever por que | "firmeware porque tem mais vaga" | "Resposta legitima — mas escreva. E escreva a duvida que te trouxe aqui. Escolher sem motivo e escolher por acaso." |
| Não ter duvida nenhuma e escolher por falta de informação | "não sei, tanto faz" | "'Tanto faz' e o unico caminho que não serve. Escolha o lado onde você ainda depende de alguem explicando, e escreva isso." |
| O aluno escreve "achar documentation" e não diz onde achou | "eu googlei" | "'Googlei' não e resposta. Diga o nome da documentacao que você abriu e o parametro que procurava. Achar documentacao e um trabalho, e precisa de nome." |
Tratar deep sleep como estado do loop no plano | "vou adicionar deep sleep no meu projeto" | "No plano, escreva o efeito: 'a placa passa a durar 30 dias'. deep sleep e o como; o plano e o para que." |
Desafio extra
Escreva o seu portfólio de verdade nesta semana: publique o repositorio com o README completo, escreva o post de 400 palavras contando o defeito mais difícil que você encontrou e o porque da solução escolhida, e comente três coisas em um repositorio aberto de outra pessoa. Meça quanto tempo cada um dos três passos levou. Anote o tempo total e escreva uma frase sobre o que impede alguem de fazer isso: capacidade, tempo, ou vergonha de mostrar o código.
A resolucao, compilada
// Aula 2 do dia 13: o que levar para depois do curso. // // A ultima aula de conteudo do ano nao ensina codigo. Ela entrega um // inventario do que o aluno sabe fazer, em Skills, e um plano de 90 dias // para o proximo passo. E o unico sketch do ano em que o professor nao // projeta codigo nenhum e pede a turma para falar. // // A placa faz tres coisas enquanto a turma fala: // // 1. INVENTARIO: cada habilidade do ano vira uma linha com o que ela // resolve. "Sabe usar WiFi" nao e habilidade: "sabe descobrir por que // a placa saiu da rede" e. // 2. PLANO: os proximos passos com o tempo de cada um, porque plano sem // prazo e intencao. // 3. PROVA: a placa responde tres exercicios que o aluno faz sozinho, sem // professor. E a definicao de "levou": consegue fazer isso hoje, no // seu projeto, sem abrir aula. // // A prova e a parte que importa. Cada exercicio corresponde a um bloco do // inventario, e o professor anota na lousa quantos o aluno fez. Nao e nota: // e o mapa do que o ano precisa de reforco. #include <Arduino.h> // Versao do firmware. #define VERSAO_FIRMWARE "2.0.0" // Quantos exercicios a prova tem. Tres: um de diagnostico, um de regra e um // de entrega. Menos que tres nao cobre o ano; mais que tres nao cabe em // uma aula de 50 minutos. const int TOTAL_DE_PROVAS = 3; // ------------------------------------------------------------------ pinos const int PIN_LED_STATUS = 2; const int PIN_BOTAO_PROVA = 0; // ------------------------------------------------------------------ tipos struct Habilidade { const char* nome; const char* resolve; const char* ondeViou; bool consolidada; }; struct Exercicio { const char* enunciado; const char* respostaEsperada; int pontos; }; struct PassoDoPlano { const char* quando; const char* oQue; int horasEstimadas; }; // ---------------------------------------------------------- inventario Habilidade habilidades[8]; int totalDeHabilidades = 0; void montarInventario() { habilidades[0].nome = "diagnosticar"; habilidades[0].resolve = "achar a causa antes de trocar o codigo"; habilidades[0].ondeViou = "erro que o monitor serial accuses"; habilidades[0].consolidada = true; habilidades[1].nome = "ler codigo estranho"; habilidades[1].resolve = "entender programa que voce nao escreveu"; habilidades[1].ondeViou = "revisao de codigo do colega"; habilidades[1].consolidada = true; habilidades[2].nome = "decompor problema"; habilidades[2].resolve = "quebrar requisito grande em pedaco verificavel"; habilidades[2].ondeViou = "maquina de estados do dia 1"; habilidades[2].consolidada = true; habilidades[3].nome = "escrever regra como codigo"; habilidades[3].resolve = "decisao do sistema que se explica sozinha"; habilidades[3].ondeViou = "erro de negocio do dia 1"; habilidades[3].consolidada = true; habilidades[4].nome = "achar documentacao"; habilidades[4].resolve = "encontrar a resposta na fonte, sem adivinhacao"; habilidades[4].ondeViou = "compilador e documentacao do modulo"; habilidades[4].consolidada = true; habilidades[5].nome = "escrever teste que falha"; habilidades[5].resolve = "provar o defeito antes de corrigir"; habilidades[5].ondeViou = "caso negativo do projeto final"; habilidades[5].consolidada = true; habilidades[6].nome = "medir antes de otimizar"; habilidades[6].resolve = "saber se o gargalo e real"; habilidades[6].ondeViou = "EXPLAIN e linhas examinadas"; habilidades[6].consolidada = true; habilidades[7].nome = "explicar para o outro"; habilidades[7].resolve = "ensinar sem depender de vocabulario da aula"; habilidades[7].consolidada = false; habilidades[7].ondeViou = "dia 15, apresentacao de projeto"; totalDeHabilidades = 8; } // ------------------------------------------------------------------ plano PassoDoPlano passos[6]; int totalDePassos = 0; void montarPlano() { passos[0].quando = "semana 1"; passos[0].oQue = "publicar o projeto final no repositorio, com README"; passos[0].horasEstimadas = 3; passos[1].quando = "semana 2"; passos[1].oQue = "conectar a placa em um servidor de verdade, e nao na bancada"; passos[1].horasEstimadas = 5; passos[2].quando = "semana 3"; passos[2].oQue = "colocar um segundo dispositivo na mesma conta e ver o limite"; passos[2].horasEstimadas = 5; passos[3].quando = "mes 2"; passos[3].oQue = "ler o codigo de um projeto aberto e escrever um comentario util"; passos[3].horasEstimadas = 10; passos[4].quando = "mes 3"; passos[4].oQue = "escrever um post sobre o que quebrou, e o porque"; passos[4].horasEstimadas = 8; passos[5].quando = "continuo"; passos[5].oQue = "escolher um caminho: mais firmware ou mais servidor"; passos[5].horasEstimadas = 0; totalDePassos = 6; } // ------------------------------------------------------------------ prova Exercicio provas[3]; int totalDeProvasFeitas = 0; void imprimirProva() { Serial.println("========================================"); Serial.println(" a prova: tres exercicios, sem professor"); Serial.println("========================================"); Serial.println("cada exercicio corresponde a um bloco do inventario."); Serial.println("resolva no seu projeto, com a placa na mão, sem abrir aula."); Serial.println("o que voce nao conseguir, escreva. e o mapa do reforco."); Serial.println(); provas[0].enunciado = "a placa saiu da rede e nao voltou. o que voce olha primeiro?"; provas[0].respostaEsperada = "o log do serial: ele tem o banner de boot?"; provas[0].pontos = 1; provas[1].enunciado = "o alerta disparou duas vezes para o mesmo evento. onde esta o defeito?"; provas[1].respostaEsperada = "falta chave de idempotencia no trabalho enfileirado"; provas[1].pontos = 1; provas[2].enunciado = "um colega nao consegue rodar seu projeto. o que falta?"; provas[2].respostaEsperada = "o passo de instalacao que so existe na sua cabeca"; provas[2].pontos = 1; for (int i = 0; i < TOTAL_DE_PROVAS; i++) { Serial.println("prova " + String(i + 1) + ": " + String(provas[i].enunciado)); Serial.println(" resposta esperada: " + String(provas[i].respostaEsperada)); Serial.println(); } Serial.println("as tres respostas sao curtas de proposito. quem nao sabe"); Serial.println("responder em uma frase nao consolidou aquele bloco, e o"); Serial.println("instructor ve isso no numero, nao na opiniao."); Serial.println(); } // ------------------------------------------------------------------ saida void imprimirInventario() { Serial.println("========================================"); Serial.println(" o que fica: oito habilidades"); Serial.println("========================================"); int consolidadas = 0; for (int i = 0; i < totalDeHabilidades; i++) { Serial.println(); Serial.println(String(i + 1) + ". " + String(habilidades[i].nome)); Serial.println(" resolve: " + String(habilidades[i].resolve)); Serial.println(" onde vi: " + String(habilidades[i].ondeViou)); if (habilidades[i].consolidada) consolidadas++; } Serial.println(); Serial.println("consolidadas: " + String(consolidadas) + " de " + String(totalDeHabilidades)); Serial.println(); Serial.println("a oitava esta sem consolidada de proposito: explicar para o"); Serial.println("outro e a unica que so se prova na apresentacao do dia 15."); Serial.println("quem nao marcou ela nao vai ter chance de provar depois."); Serial.println(); } void imprimirPlano() { Serial.println("========================================"); Serial.println(" os proximos 90 dias"); Serial.println("========================================"); int horas = 0; for (int i = 0; i < totalDePassos; i++) { Serial.println(" " + String(passos[i].quando) + " | " + String(passos[i].horasEstimadas) + " h | " + String(passos[i].oQue)); horas += passos[i].horasEstimadas; } Serial.println(); Serial.println("horas estimadas no bloco de 90 dias: " + String(horas)); Serial.println(); Serial.println("sao 31 horas em 90 dias. e pouco, e e por isso que funciona:"); Serial.println("plano de 200 horas em 90 dias e plano de nenhum."); Serial.println("o professor pede o numero porque e ele que impede o"); Serial.println("plano de virar 'quando eu tiver tempo'."); Serial.println(); } void imprimirPortfolio() { Serial.println("========================================"); Serial.println(" o portfolio, em tres coisas"); Serial.println("========================================"); Serial.println(" 1. o repositorio do projeto final, com o README que roda"); Serial.println(" 2. o post sobre o que quebrou, com o porque de cada quebra"); Serial.println(" 3. o codigo de um colega, com tres comentarios seus"); Serial.println(); Serial.println("o item 2 e o que diferencia o portfolio do repositorio."); Serial.println("repositorio mostra o que deu certo. o post mostra o que voce"); Serial.println("aprendeu no que deu errado, e e isso que o entrevistador"); Serial.println("pergunta primeiro."); Serial.println(); Serial.println("repositorio privado nao e portfolio: e um rascunho."); Serial.println(); } void imprimirProximoPasso() { Serial.println("========================================"); Serial.println(" o proximo curso"); Serial.println("========================================"); Serial.println("quem terminou este ano com as sete camadas firmes tem dois"); Serial.println("caminhos, e a aula 2 do dia 14 e exatamente isso:"); Serial.println(); Serial.println(" mais firmware: OTA, FreeRTOS, interrupcao, energia"); Serial.println(" mais servidor: WebSocket, fila real, broker de mensagens"); Serial.println(); Serial.println("escolher e a parte dificil, e escolher tarde custa mais."); Serial.println("o plano de 90 dias ja tem a decisao no ultimo passo."); Serial.println(); } // ---------------------------------------------------------------- setup void setup() { Serial.begin(115200); delay(300); pinMode(PIN_LED_STATUS, OUTPUT); pinMode(PIN_BOTAO_PROVA, INPUT_PULLUP); digitalWrite(PIN_LED_STATUS, HIGH); Serial.println(); Serial.println("========================================"); Serial.println(" o que levar para depois — v" + String(VERSAO_FIRMWARE)); Serial.println("========================================"); Serial.println("esta aula nao tem codigo novo: e inventario e plano."); Serial.println("cpu: " + String(getCpuFrequencyMhz()) + " MHz | heap: " + String(ESP.getFreeHeap()) + " bytes"); Serial.println(); montarInventario(); montarPlano(); imprimirInventario(); imprimirPlano(); imprimirProva(); imprimirPortfolio(); imprimirProximoPasso(); Serial.println("========================================"); Serial.println(" fim do conteudo do ano"); Serial.println("========================================"); Serial.println("o botao marca cada prova que voce fez. aperte tres vezes"); Serial.println("se voce resolveu as tres, e a placa conta."); } void loop() { digitalWrite(PIN_LED_STATUS, !digitalRead(PIN_LED_STATUS)); static unsigned long ultimoToque = 0; if (digitalRead(PIN_BOTAO_PROVA) == LOW && millis() - ultimoToque > 1500) { ultimoToque = millis(); if (totalDeProvasFeitas < TOTAL_DE_PROVAS) { totalDeProvasFeitas++; } Serial.println("[prova] " + String(totalDeProvasFeitas) + " de " + String(TOTAL_DE_PROVAS) + " registrada | heap " + String(ESP.getFreeHeap()) + " B"); } Serial.println("[encerramento] viva | v" + String(VERSAO_FIRMWARE) + " | provas " + String(totalDeProvasFeitas) + "/" + String(TOTAL_DE_PROVAS) + " | heap " + String(ESP.getFreeHeap()) + " B"); delay(7000); }
Sem saída de compilação gravada. Rode python3 validar.py -t 3 dia13 aula2.
