Focado no desenvolvimento de soluções ESP32

Prática de desenvolvimento de IoT de alarme de fumaça STM32 + ESP32

O desenvolvimento de dispositivos terminais IoT é essencialmente uma prática de engenharia de sistemas em ambientes com recursos limitados. Dominando drivers periféricos MCU, protocolos de comunicação multimodo (Wi‑Fi/MQTT), aquisição de sensor de baixa potência, e a colaboração entre dispositivos e nuvem constituem os quatro pilares da construção de sistemas IoT embarcados confiáveis. Seus princípios básicos residem em camadas padronizadas de abstração de hardware, pilhas de protocolos de comunicação desacopladas, e agendamento híbrido de tarefas em tempo real e em segundo plano. Esta abordagem técnica melhora significativamente a capacidade de manutenção do produto, reutilização entre plataformas, e robustez industrial, amplamente utilizado na proteção inteligente contra incêndio, monitoramento ambiental, alerta de borda, e outros cenários. Esta prática usa um alarme de fumaça como um transportador típico.

O desenvolvimento de sistemas IoT é frequentemente considerado pelos iniciantes como “empilhamento de protocolos” ou “emenda de módulos”. No entanto, o núcleo de projetos reais de nível industrial nunca é uma lista de funções, mas o pensamento de engenharia em nível de sistema – como construir um ambiente sustentável, escalável, link de dados ponta a ponta diagnosticável em um MCU com recursos limitados.

Esta série de tutoriais usa um alarme de fumaça como transportador, evitando conceitos abstratos e apresentando apenas o processo de implementação de link completo de um engenheiro embarcado: da análise de requisitos, seleção de hardware, configuração periférica, integração da pilha de protocolos de comunicação, acoplamento na nuvem, para interação com o APP. Todo o código é projetado de forma colaborativa com base na biblioteca STM32 HAL e nas plataformas duplas ESP-IDF, cobrindo três camadas principais: percepção (drivers de sensores), rede (Adaptação multimodo Wi‑Fi/Bluetooth/NB‑IoT), e aplicação (lógica local + controle remoto).

1.1 Ensinando Posicionamento e Valor de Engenharia

Este tutorial tem como alvo três grupos técnicos claros:

  • Alunos com especialização em eletrônica/informação/IoT: Necessidade de concluir projetos de curso ou graduação que exijam demonstrabilidade, defensibilidade, e reprodutibilidade;
  • Engenheiros embarcados júnior: Dominar operações básicas de GPIO/UART, mas não ter experiência em programar múltiplos periféricos em RTOS;
  • Empreendedores/criadores de IoT: Necessidade de verificar protótipos dentro 3 semanas, altamente sensível ao poder, custo, e ciclo de desenvolvimento.

Todas as seleções técnicas seguem três restrições rígidas:

  1. Disponibilidade de hardware: Todos os módulos prontos para uso da LCSC (não PCB personalizado), Custo da lista técnica ≤ ¥ 85 (excluindo gabinete);
  2. Programabilidade de firmware: Nenhum depurador dedicado como o J‑Link; apenas USB-to-TTL necessário para atualização de firmware e captura de log;
  3. Substituibilidade de protocolo: Pilha de comunicação subjacente dissociada da lógica de negócios; mudar MQTT para CoAP/LwM2M requer apenas duas alterações de ponteiro de função.

Estas restrições não são compromissos, mas verdadeiras fronteiras industriais. Como consultor técnico de um fabricante de equipamentos contra incêndio, Certa vez, encontrei uma desconexão de massa a -20°C devido à falta de tolerância a falhas de temporização SPI em um driver de sensor. A solução final não foi a substituição do chip, mas a reescrita da lógica de atraso do CS. A verdadeira capacidade de engenharia sempre cresce nas lacunas das restrições.

1.2 Arquitetura do sistema: Modelo de desacoplamento de três camadas

O alarme de fumaça tem uma forma física mínima: STM32F103C8T6 (64KB Flash / 20KB de RAM), Sensor de fumaça MP‑2.5, Indicador LED, campainha, Módulo Wi-Fi ESP32‑WROOM‑32. A sua arquitetura de software deve apoiar a expansão futura em nós agrícolas inteligentes (sensores de umidade/luz do solo) ou gateways de iluminação inteligentes (Coordenador Zigbee). Design estrito em camadas é adotado:

folha

CamadaComponenteResponsabilidadesPrincipais restrições
Camada de PercepçãoSTM32F103Aquisição de dados de sensores, lógica de alarme local, gerenciamento de baixo consumo de energiaTodos os drivers de sensor fornecem padrão init() / read() / deinit(); ADC suporta gatilho de software/temporizador
Camada de RedeESP32-WROOM-32Gerenciamento de Wi-Fi, Criptografia TLS, Cliente MQTT, OTALoop de eventos nativo ESP-IDF; sem bloqueio em retornos de chamada de Wi-Fi; Batimento cardíaco MQTT = 60s
Camada de AplicaçãoSTM32+ESP32Mecanismo de regras de negócios, análise de comando, sincronização de statusUART2 (STM32) ↔UART0 (ESP32); quadro com CRC16 + 0terminador x0D0A

Esta estratificação não é um modelo ideal de livro didático, mas uma estratégia de sobrevivência aprendida com as armadilhas. Versões anteriores colocavam lógica de reconexão MQTT no STM32, causando estouro de buffer UART quando o Wi-Fi caiu. Finalmente, o tratamento de exceções de rede foi totalmente movido para ESP32; STM32 recebe apenas pacotes de status JSON estruturados (por exemplo, {"wifi":"connected","mqtt":"ready"}), dissociando completamente os dois.

O STM32F103C8T6 foi escolhido não por recursos de ponta, mas por árvore de clock precisa e correspondência de periféricos. Um alarme de fumaça não requer ADC de ponto flutuante ou de alta velocidade, mas exige:

  • Base de tempo precisa de 1ms (para filtragem por média móvel de concentração de fumaça);
  • Canais UART independentes (UART1 para logs de depuração, UART2 dedicado ao ESP32);
  • GPIO suficiente para acionar LEDs, campainhas, e pinos de habilitação do sensor;
  • SRAM no chip atendendo à pilha mínima do FreeRTOS (≥512 bytes por tarefa).

O clock de 72 MHz do F103C8T6 vem do HSI via PLL. APB1 (PCLK1) funciona a 36 MHz, atendendo perfeitamente à precisão de interrupção de 1 ms do TIM2:

texto simples

// Key TIM2 initialization (HAL Library)
htim2.Instance = TIM2;
htim2.Init.Prescaler = 36000 - 1; // 36MHz / 36000 = 1kHz
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 1000 - 1; // 1s overflow

O Prescaler não é arbitrário: configurando-o para 35999 fornece um temporizador de 1kHz. Para uma interrupção de 1ms, definir ARR para 0 e use o evento de atualização como o tick de 1ms. Esses detalhes determinam a estabilidade para todas as operações críticas em termos de tempo.

2.1 Projeto de circuito de interface de sensor

O MP-2.5 produz saída analógica de 0,1–4,0V correspondente a 0–10000ppm de fumaça. Armadilhas críticas de design:

  • Supressão de ruído de energia: O sensor é altamente sensível à ondulação. Quando a ondulação do VCC >50mV, As leituras ADC saltam ±15%. Solução: coloque 10μF de tântalo + 100capacitores cerâmicos nF próximos ao sensor VCC; alimente este trilho do STM32 VREF + (não principal 3,3V);
  • Estabilidade de referência ADC: VREF+ precisa de desacoplamento de 100nF; Período de amostragem ADC ≥1,5μs (Seção RM0008 12.4.3) para evitar distorções;
  • Condicionamento de sinal: Interferência de alta frequência requer filtro passa-baixa RC (R=1kΩ, C=100nF, corte ≈1,6kHz) para suprimir harmônicos de rede de 50 Hz.

De verdade Layout da placa de circuito impresso, compartilhar GND entre MP-2.5 e MOSFET de campainha causou um 30% Queda de ADC quando a campainha tocou. Correção final: sensor GND conectado separadamente ao STM32 AGND, ancorado em estrela na AVSS. Isto é obrigatório para aquisição analógica de alta precisão.

2.2 Projeto de interface de comunicação STM32 – ESP32

UART2 (STM32) ↔UART0 (ESP32) parece simples, mas esconde quatro riscos principais:

  1. Compatibilidade de nível: STM32 GPIO = 3,3 V TTL; ESP32 UART0 RX máx. 3,6V, TX = 3,3V (conexão direta segura);
  2. Sem controle de fluxo: Sem RTS/CTS; protocolo de software necessário para evitar perda de pacotes;
  3. Erro na taxa de transmissão: F103 HSI (±1%), ESP32 ESCURO (±2%), erro total máximo 3%; escolha a taxa de transmissão tolerante;
  4. Estouro de buffer: Buffer UART RX padrão ESP32 = 128 bytes; STM32 pode estourar JSON de 200 bytes.

Soluções de engenharia:

  • Taxa de transmissão: 921600bps (fora do padrão). UBRR=3 em F103 (erro 0.15%), <0.5% no ESP32, muito melhor que 115200bps (2.3% erro);
  • Formato do quadro:[0xAA][LEN_H][LEN_L][CMD][PAYLOAD...][CRC_H][CRC_L][0x0D][0x0A]LEN = comprimento da carga útil; CRC16‑CCITT cobre CMD até CRC_L;
  • Expansão do buffer ESP32: Definir rx_buffer_size = 1024 em uart_driver_install();
  • Segurança de transmissão STM32: Verificar huart2.gState == HAL_UART_STATE_READY antes HAL_UART_Transmit(); tente novamente após 10 ms se estiver ocupado.

Esta solução passou nos testes de produção em massa de -40 °C a 85 °C com taxa de erro de bit <10⁻⁹ (GB/T 17626.3 Padrão EMC).

O alarme de fumaça tem conflitos inerentes em tempo real:

  • Difícil em tempo real: A campainha deve disparar dentro de 200 ms se a fumaça exceder o limite (limite audível humano);
  • Suave em tempo real: Indicação LED, rejeição chave, saída de log tolera atraso de 50ms;
  • Tempo não real: Upload na nuvem, A verificação OTA é executada de forma assíncrona.

Forçar causas de agendamento unificado do FreeRTOS:

  • Tarefa de campainha consumindo CPU, prejudicando a reconexão Wi-Fi;
  • Atraso nas tarefas de baixa prioridade, LED piscando fora de sincronia.

Modelo de agendamento híbrido:

  • Contexto de interrupção: A interrupção de atualização de 1 ms do TIM2 executa amostragem ADC e filtragem de média móvel;
  • Loop principal de metal puro: while(1) lida com máquina de estado de LED, verificação de chave, Registros UART;
  • Tarefas RTOS: Apenas duas tarefas do FreeRTOS: wifi_task (Comunicação ESP32) e cloud_task (Mensagens MQTT).

Inovação chave: Isole tarefas difíceis em tempo real do RTOS e lide com elas diretamente em interrupções. TIM2 ISR deve:

  • Execute em ≤5μs (~360 ciclos a 72MHz);
  • Não chame nenhuma função da biblioteca HAL (não HAL_Delay());
  • Acesse variáveis ​​globais apenas com volatile e seções críticas.

Implementação:

texto simples

// TIM2 ISR (simplified)
void TIM2_IRQHandler(void)
{
 if(__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) != RESET)
 {
 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE);

 // Non‑blocking ADC start
 HAL_ADC_Start(&hadc1);

 // 1ms tick for LED blink
 ms_tick++;

 // Moving average filter (window = 8)
 static uint16_t smoke_buf[8] = {0};
 static uint8_t buf_idx = 0;
 uint16_t adc_val;

 if(HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK)
 {
 adc_val = HAL_ADC_GetValue(&hadc1);
 smoke_buf[buf_idx] = adc_val;
 buf_idx = (buf_idx + 1) & 0x07;
 uint32_t sum = 0;
 for(uint8_t i=0; i<8; i++) sum += smoke_buf[i];
 current_smoke_ppm = sum >> 3; // divide by 8
 }
 }
}

ADC inicia e retorna imediatamente; resultados lidos na próxima interrupção. Este pipeline mantém a execução do ISR em 3,2 μs (medido por osciloscópio), bem abaixo do limite de segurança de 5μs.

3.1 Particionamento de tarefas e otimização de memória do FreeRTOS

O gerenciamento de memória é crítico no F103 com apenas 20 KB de RAM. Alocação precisa de pilha:

  • wifi_task: Analisa respostas AT, máximo de JSON ~ 150 bytes → pilha 512 bytes;
  • cloud_task: Publicação/assinatura MQTT, armazena tópico/carga útil → pilha 768 bytes;
  • Desabilitar alocação dinâmica: Definir configUSE_MALLOC_FAILED_HOOK = 1; substituir pvPortMalloc() com estática xTaskCreateStatic();
  • Interromper agrupamento prioritário: NVIC_PriorityGroup_2 (2 preventivo + 2 sub); TIM2 (preventivo 0) > todas as tarefas RTOS (preventivo 1).

Comunicação entre tarefas: fila + grupo de eventos:

  • smoke_queue: Mantém valores de fumaça filtrada (uint16_t), escrito por TIM2 ISR via xQueueSendFromISR();
  • wifi_event_group: Bits para status de conexão Wi‑Fi/IP/MQTT.

O julgamento do alarme passa para cloud_task: acionar somente se 3 leituras consecutivas >800ppm. Equilibra velocidade e prevenção de falsos alarmes.

ESP32‑WROOM‑32 executa ESP‑IDF v4.4, mas componente oficial do MQTT não é usado por três razões:

  • MQTT oficial depende de lwIP, que não cabe na RAM limitada do F103;
  • Os comandos AT oferecem um controle mais preciso (por exemplo, DNS estático);
  • Locais industriais geralmente precisam de IP estático (sem DHCP em algumas fábricas).

Por isso, ESP32 usa modo AT puro; STM32 controla todos os Wi-Fi/MQTT via UART. Firmware AT padrão (v2.2.0.0) tem falhas fatais:

  • Corrigido o tempo limite de TLS de 10s (servidores MQTT públicos como EMQX geralmente precisam de 15s);
  • MQTT SUBSCRIBE não possui QoS2 (exigido para alertas de incêndio com perda zero);
  • Sem interface AES de hardware; O handshake TLS usa 95% CPU.

Correções profundas de firmware AT personalizadas:

  1. Modificar components/at/src/at_port/at_port_uart.c para parametrizar o tempo limite do TLS (AT+MQTTTLS=1,15000);
  2. Adicionar campo QoS2 a AT+MQTTSUB em components/at/src/at_cmd_src/at_cmd_mqtt.c;
  3. Habilite o AES de hardware ESP32 em idf.py menuconfig; chave de pré-carregamento com aes_encrypt_init() antes do aperto de mão TLS.

Melhorias:

  • Handshake TLS de 15,2s → 3,8s;
  • Entrega QoS2 de 82% → 99.99%;
  • Pico de carga da CPU de 95% → 45%.

Máquina de estado de comando STM32 AT:

texto simples

// AT state machine (pseudo code)
typedef enum {
 AT_STATE_IDLE,
 AT_STATE_WAITING_OK,
 AT_STATE_WAITING_IP,
 AT_STATE_MQTT_CONNECTED
} at_state_t;

at_state_t at_state = AT_STATE_IDLE;
uint8_t at_retry_cnt = 0;

void at_send_command(const char* cmd) {
 HAL_UART_Transmit(&huart2, (uint8_t*)cmd, strlen(cmd), 100);
 at_state = AT_STATE_WAITING_OK;
 at_retry_cnt = 0;
}

// UART2 RX interrupt parsing
void USART2_IRQHandler(void) {
 uint8_t rx_byte;
 HAL_UART_Receive(&huart2, &rx_byte, 1, 1);

 switch(at_state) {
 case AT_STATE_WAITING_OK:
 if(strstr(rx_buffer, "OK")) {
 at_state = AT_STATE_IDLE;
 } else if(strstr(rx_buffer, "ERROR")) {
 if(++at_retry_cnt < 3)
 at_send_command(last_cmd);
 else
 at_switch_apn();
 }
 break;
 // other states...
 }
}

O sistema utiliza um privado híbrido + arquitetura de nuvem pública:

  • Nuvem privada: Cluster EMQX (v5.0) na LAN corporativa para acesso ao dispositivo, mecanismo de regras, alerta;
  • Nuvem pública: WeChat Mini Program APP via API HTTPS para nuvem privada.

Isso evita a dependência de fornecedores de nuvem pública e mantém o alcance do WeChat. Design chave: protocolo de sincronização de estado:

  • STM32 não se conecta diretamente à nuvem; todos os dados passam pelo ESP32;
  • ESP32 ↔ EMQX usa MQTT sobre TLS:device/{product_key}/{device_id}/up (ligação ascendente)device/{product_key}/{device_id}/down (link descendente);
  • Mini programa busca status via API REST EMQX, sem conexão longa.

JSON de uplink padrão:

texto simples

{
 "ts": 1712345678901,
 "smoke_ppm": 1250,
 "battery_mv": 3280,
 "wifi_rssi": -62,
 "event": "alarm_high"
}

event valores:

  • normal: <300ppm;
  • warn: 300–800 ppm (LED piscando lentamente);
  • alarm_high: ≥800 ppm (campainha + piscar rápido);
  • alarm_clear: <300ppm por 10s.

A lógica do APP é simplificada: monitor event para conduzir a IU, não há necessidade de interpretar ppm bruto. A reutilização como detector de formaldeído requer apenas a alteração do limite no STM32 – APP inalterado. Este é o valor dos protocolos padrão.

5.1 Atualização OTA confiável

OTA é fundamental para dispositivos IoT, mas o Flash de 64 KB do F103 não pode conter bancos duplos. Atualização diferencial + verificar & reversão:

  • Pacote de atualização = patch bsdiff (12% de tamanho real);
  • Patch armazenado em SPI Flash externo (W25Q32);
  • Após verificação, desbloquear Flash, apagar aplicativo, escrever patch;
  • Reverter para o setor de backup se a verificação falhar.

Principais pontos de verificação:

  • Download: CRC32 por 1 KB na lista de servidores;
  • Escrever: Leia imediatamente após a programação;
  • Bota: Valide o ponteiro da pilha em 0x08000000; reversão em valor inválido.Implantado em 2000 dispositivos para 18 meses com 0 falhas de atualização.

O maior desafio na depuração de IoT incorporada é que os problemas podem ocorrer em qualquer camada:

  • ADC STM32 anormal? → Verifique a forma de onda PA0 quanto a ruído de energia;
  • ESP32 não consegue se conectar ao Wi-Fi? → Capture UART2 para confirmar comandos AT enviados;
  • MQTT não alcança a nuvem? → Porta do roteador espelhado, filtrar MQTT com Wireshark;
  • Dados do APP atrasados? → Verifique o mecanismo de regras EMQX SQL para produto cartesiano.

Conjunto de ferramentas de depuração:

  • Hardware: Osciloscópio DS1054Z (com decodificação de protocolo):
    • Ruído de pico-pico PA0 <20mV;
    • Nível ocioso USART2 TX alto (senão o ESP32 detecta incorretamente o bit de início);
  • Firmware: DIZ RTT (substitui printf):SEGGER_RTT_printf(0, "SMOKE:%d BATT:%dmV\r\n", current_smoke_ppm, battery_mv);Latência zero, sem UART, multicanal;
  • Rede: Wireshark + Captura de firmware do Sniffer ESP32 802.11 quadros;
  • Nuvem: Painel EMQX Client List para status em tempo real.

Dica mais esquecida: alinhamento de carimbo de data/hora. Sincronizar STM32, ESP32, EMQX, Miniprograma via NTP (ESP32 como cliente) até ±500ms. De outra forma, "alarme 5 minutos atrás” versus registro de data e hora “2024‑04‑05T10:23:45Z” confunde operações.

A lacuna entre os projetos estudantis e a produção em massa é a adaptabilidade ambiental. O alarme de fumaça deve passar em testes industriais:

  • ESD: Descarga de contato ±8kV (CEI 61000‑4‑2):
    • Adicione diodos TVS (SMAJ3.3A) para interfaces USB/sensor;
    • Terra de cobre da borda do PCB, furos ≤20mm;
  • Envelhecimento em alta temperatura: 85°C por 72h:
    • Desvio MP-2.5 <±5% F.S.;
    • Sensor de temperatura interna STM32 vs termômetro infravermelho;
  • Vibração: 5Varredura de –500Hz, 3aceleração g, 2h; verifique as juntas de solda.

Em testes de pré-produção, O sucesso do Wi-Fi caiu de 99.9% para 82% após 48h a 45°C. Causa raiz: capacitor de carga de cristal ESP32 errado (12pF → mudança de frequência fixa de 10pF em alta temperatura). Esses detalhes só aparecem em testes reais de envelhecimento.

Lição sangrenta: sempre mantenha um backdoor de depuração no firmware de produção em massa. Adicionar em main() começar:

texto simples

if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_SET) {
 debug_mode = 1; // enable full logs
}

Segure reset 3s para exportar logs no site. Nos salvou de três grandes fracassos por apenas 200 bytes Flash.

O projeto de alarme de fumaça parece simples, mas condensa a capacidade de engenharia de IoT incorporada. Evita o excesso de engenharia e concentra-se no equilíbrio entre os recursos, custo, confiabilidade, e manutenibilidade. Quando você solda o último resistor, firmware instantâneo, e veja a curva de fumaça em tempo real no APP, a sensação única de realização como engenheiro excede em muito qualquer ilusão de tutorial rápido.

Imagem de Berg Zhou

Berg Zhou

Berg Zhou está focado no projeto esquemático do ESP32, Layout da placa de circuito impresso, desenvolvimento de firmware e produção em massa de PCBA. Proficiente em projeto de circuitos, seleção de componentes, testes de protótipos e soluções completas de OEM/ODM. Fornecer estável, módulos funcionais e placas de controle ESP32 confiáveis ​​e econômicos para clientes globais, apoiando o desenvolvimento personalizado e a fabricação em volume.

Postagens recentes

Tradução
Definir como idioma padrão
Whatsapp
Whatsapp
E-mail
E-mail
conversamos
conversamos
conversamos

Obtenha uma cotação

Nossos especialistas e técnicos de produtos responderão às suas perguntas dentro 24 horas.

Utilizamos cookies para garantir que lhe proporcionamos a melhor experiência no nosso site.