Implementação de Driver de Comandos AT para ESP8266 em C

Esta implementação fornece uma biblioteca robusta para o gerenciamento do módulo ESP8266 através de comandos AT, focando em operações não bloqueantes. Diferente de implementações convencionais que utilizam loops de espera (dead loops) ou atrasos excessivos, este código utiliza uma máquina de estados e um manipulador de base tempoarl de 1ms para garantir a fluidez do sistema princiapl.

Características Principais

  • Execução Assíncrona: Nenhuma função de comando AT bloqueia o processador por mais de 2ms.
  • Máquina de Estados: Controle rigoroso sobre o envio de comandos, espera de resposta e processamento de dados.
  • Suporte a Servidor: Otimizado para funcionar como servidor, permitindo múltiplas conexões de clientes.
  • Análise de Dados Inteligente: Processamento de pacotes +IPD e monitoramento de status de conexão em tempo real.

Estrutura de Dados e Definições

#ifndef DRIVER_ESP8266_H
#define DRIVER_ESP8266_H

#include "stdint.h"

#define TAM_MAX_DADOS_ESP      64
#define ESP_SSID_PADRAO        "Rede_Teste_ESP"
#define ESP_SENHA_PADRAO       "12345678"

typedef struct {
    uint8_t id_conexao;
    uint16_t tamanho;
    char buffer_dados[TAM_MAX_DADOS_ESP];
} PacoteRedeESP;

typedef enum {
    RES_ESP_AGUARDANDO = 0,
    RES_ESP_SUCESSO,
    RES_ESP_FALHA,
    RES_ESP_PROCESSANDO
} ResultadoFalsaESP;

// Protótipos de Funções
void ESP_ProcessarBaseTempo(void);
uint8_t ESP_InicializarModoAP(void);
void ESP_TratarDadosUART(char dado);
ResultadoFalsaESP ESP_EnviarMensagemRede(const PacoteRedeESP *pacote);

#endif

Lógica de Processamento e Máquina de Estados

O núcleo do driver reside na função de base temporal. Ela deve ser chamada em um timer de 1ms para gerenciar timeouts e transições de estado entre o envio do comando AT e a recepção da confirmação (como "OK", "ERROR" ou ">").

#include "driver_esp8266.h"
#include "string.h"

typedef enum {
    ESTADO_ESP_IDLE = 0,
    ESTADO_ESP_ENVIANDO_AT,
    ESTADO_ESP_ENVIANDO_DADOS,
    ESTADO_ESP_FINALIZANDO
} EstadoOperacaoESP;

typedef struct {
    char *comando_str;
    uint16_t timeout_limite;
    const char *resposta_esperada;
    ResultadoFalsaESP status_atual;
} GerenciadorComandoAT;

static GerenciadorComandoAT g_cmdAT;
static EstadoOperacaoESP g_estadoModulo = ESTADO_ESP_IDLE;
static uint8_t g_statusConexoes = 0; // Mapa de bits para IDs 0-4

/**
 * @brief Gerencia a temporização e fluxo dos comandos AT.
 * Deve ser chamada a cada 1ms.
 */
void ESP_ProcessarBaseTempo(void) {
    static uint16_t contador_timeout = 0;

    switch (g_estadoModulo) {
        case ESTADO_ESP_IDLE:
            break;

        case ESTADO_ESP_ENVIANDO_AT:
            // Lógica de monitoramento de resposta via flag de interrupção UART
            if (g_cmdAT.status_atual != RES_ESP_AGUARDANDO) {
                g_estadoModulo = ESTADO_ESP_FINALIZANDO;
            } else if (++contador_timeout > g_cmdAT.timeout_limite) {
                g_cmdAT.status_atual = RES_ESP_FALHA;
                g_estadoModulo = ESTADO_ESP_FINALIZANDO;
            }
            break;

        case ESTADO_ESP_FINALIZANDO:
            contador_timeout = 0;
            g_estadoModulo = ESTADO_ESP_IDLE;
            break;

        default:
            g_estadoModulo = ESTADO_ESP_IDLE;
            break;
    }
}

/**
 * @brief Função exemplo para testar a comunicação (comando AT básico).
 */
ResultadoFalsaESP ESP_ComandoPing(void) {
    if (g_estadoModulo == ESTADO_ESP_IDLE) {
        g_cmdAT.comando_str = "AT\r\n";
        g_cmdAT.timeout_limite = 500;
        g_cmdAT.resposta_esperada = "OK";
        g_cmdAT.status_atual = RES_ESP_AGUARDANDO;
        
        // Função de envio físico da UART (dependente de hardware)
        UART_EnviarString(g_cmdAT.comando_str);
        
        g_estadoModulo = ESTADO_ESP_ENVIANDO_AT;
        return RES_ESP_PROCESSANDO;
    }
    return (g_estadoModulo == ESTADO_ESP_FINALIZANDO) ? g_cmdAT.status_atual : RES_ESP_AGUARDANDO;
}

Processamento de Dados Recebidos

A análise dos dados vindos do ESP8266 é feita caractere por caractere dentro da rotina de interrupção da UART para identificar padrões como +IPD (dados de entrada) ou alterações no status da conexão (CONNECT/CLOSED).

void ESP_TratarDadosUART(char dado) {
    static char buffer_circular[10];
    static uint8_t index_buffer = 0;

    // Deslocamento de buffer para análise de strings curtas (janela deslizante)
    for (int i = 0; i < 9; i++) {
        buffer_circular[i] = buffer_circular[i+1];
    }
    buffer_circular[9] = dado;

    // Detectar fechamento de conexão: "n,CLOSED"
    if (dado == 'D' && buffer_circular[8] == 'E' && buffer_circular[7] == 'S') {
        uint8_t id = buffer_circular[5] - '0';
        g_statusConexoes &= ~(1 << id);
    }

    // Detectar início de dados de rede: "+IPD,"
    if (buffer_circular[6] == '+' && buffer_circular[7] == 'I' && 
        buffer_circular[8] == 'P' && buffer_circular[9] == 'D') {
        // Iniciar captura de pacote de rede
    }
    
    // Verificação de resposta de comando OK/ERROR
    if (dado == '\n' && buffer_circular[8] == '\r') {
        // Analisar se buffer temporário contém g_cmdAT.resposta_esperada
    }
}

Configuração de Modo Servidor

Para inicializar o módulo como um Access Point com servidor ativo na porta 80, o fluxo de comandos deve seguir a ordem: Reset -> Modo 3 (AP+STA) -> Múltiplas Conexões (CIPMUX=1) -> Servidor (CIPSERVER=1,80).

uint8_t ESP_ConfigurarServidorWeb(void) {
    // Exemplo simplificado de sequência
    // Cada chamada deve verificar o retorno RES_ESP_SUCESSO antes de prosseguir
    ESP_EnviarComandoFisico("AT+CWMODE=3\r\n");
    ESP_EnviarComandoFisico("AT+CIPMUX=1\r\n");
    ESP_EnviarComandoFisico("AT+CIPSERVER=1,80\r\n");
    return 0;
}

Esta arquitetura permite que o microcontrolador realize outras tarefas críticas de processamento ou controle de sensores enquanto o ESP8266 processa as requisições de rede em segundo plano, utilizando a base de tempo de 1ms para orquestrar a comunicação.

Tags: ESP8266 Comandos AT Sistemas Embarcados linguagem C firmware

Publicado em 6-10 01:15 por Thomas