STM32 ESP8266 WiFi模块驱动

发布于:2025-08-13 ⋅ 阅读:(15) ⋅ 点赞:(0)

STM32 ESP8266 WiFi模块驱动

1. 简介

ESP8266是一款高度集成的WiFi芯片,可以为其他设备提供WiFi联网功能。本笔记记录了基于STM32 HAL库的ESP8266驱动实现,包括硬件连接、初始化配置、AT指令交互等关键部分。

项目源码仓库:STM32_Sensor_Drives

2. 硬件连接

在这里插入图片描述

2.1 引脚定义

ESP8266与STM32的连接引脚定义如下:

/******************************** ESP8266 连接引脚定义 ***********************************/
#define      macESP8266_CH_PD_PORT                            GPIOA
#define      macESP8266_CH_PD_PIN                             GPIO_PIN_11
#define      macESP8266_RST_PORT                              GPIOA
#define      macESP8266_RST_PIN                               GPIO_PIN_12

#define      macESP8266_USART_BAUD_RATE                       115200
#define      macESP8266_USART_TX_PORT                         GPIOB   
#define      macESP8266_USART_TX_PIN                          GPIO_Pin_10
#define      macESP8266_USART_RX_PORT                         GPIOB
#define      macESP8266_USART_RX_PIN                          GPIO_Pin_11
#define      macESP8266_USARTx                                huart3

2.2 GPIO初始化

gpio.c中,我们初始化了ESP8266所需的GPIO引脚:

void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);

  /*Configure GPIO pins : PA4 PA11 PA12 */
  GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_11|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  // ... 其他GPIO配置 ...
}

3. 数据结构定义

3.1 ESP8266工作模式枚举

/******************************* ESP8266 数据类型定义 ***************************/
typedef enum{
    STA,        // 客户端模式
    AP,         // 热点模式
    STA_AP      // 客户端+热点模式
} ENUM_Net_ModeTypeDef;


typedef enum{
	 enumTCP,    // TCP协议
	 enumUDP,    // UDP协议
} ENUM_NetPro_TypeDef;
	
typedef enum{
	Multiple_ID_0 = 0,
	Multiple_ID_1 = 1,
	Multiple_ID_2 = 2,
	Multiple_ID_3 = 3,
	Multiple_ID_4 = 4,
	Single_ID_0 = 5,
} ENUM_ID_NO_TypeDef;
	
typedef enum{
	OPEN = 0,      // 开放模式
	WEP = 1,       // WEP加密
	WPA_PSK = 2,   // WPA-PSK加密
	WPA2_PSK = 3,  // WPA2-PSK加密
	WPA_WPA2_PSK = 4, // WPA/WPA2混合加密
} ENUM_AP_PsdMode_TypeDef;

3.2 数据接收缓冲区结构

/******************************* ESP8266 外部全局变量声明 ***************************/
#define RX_BUF_MAX_LEN     1024                                     //最大接收缓存字节数

extern struct  STRUCT_USARTx_Fram                                  //串口数据帧的处理结构体
{
    char  Data_RX_BUF [ RX_BUF_MAX_LEN ];  // 数据接收缓冲区
    union {
    __IO uint16_t InfAll;
    struct  {
          __IO uint16_t FramLength       :15;  // 数据帧长度
          __IO uint16_t FramFinishFlag   :1;   // 数据帧接收完成标志
      } InfBit;
    }Inf;
	
} strEsp8266_Fram_Record;

4. 函数宏定义

/*********************************************** ESP8266 函数宏定义 *******************************************/
#define     macESP8266_CH_ENABLE()                 HAL_GPIO_WritePin(macESP8266_CH_PD_PORT, macESP8266_CH_PD_PIN, GPIO_PIN_SET)
#define     macESP8266_CH_DISABLE()                HAL_GPIO_WritePin(macESP8266_CH_PD_PORT, macESP8266_CH_PD_PIN, GPIO_PIN_RESET)

#define     macESP8266_RST_HIGH_LEVEL()            HAL_GPIO_WritePin(macESP8266_RST_PORT, macESP8266_RST_PIN, GPIO_PIN_SET)
#define     macESP8266_RST_LOW_LEVEL()             HAL_GPIO_WritePin(macESP8266_RST_PORT, macESP8266_RST_PIN, GPIO_PIN_RESET)

5. 串口重定向

为了方便打印调试信息,重定向了printf函数:

/* 串口重定向相关定义 */
extern UART_HandleTypeDef *current_huart;
#define printf_log(...) do { \
    current_huart = &huart2; \
    printf(__VA_ARGS__); \
} while(0)

#define printf_wifi(...) do { \
    current_huart = &macESP8266_USARTx; \
    printf(__VA_ARGS__); \
} while(0)

/* printf重定向实现 */
int fputc(int ch, FILE *f)
{
    if (f == stdout) // 仅处理标准输出
    {
        HAL_UART_Transmit(current_huart, (uint8_t *)&ch, 1, 100); // 阻塞发送
        if (ch == '\n')                                           // 发送\n时自动补充\r
            HAL_UART_Transmit(current_huart, (uint8_t *)"\r", 1, 100);
    }
    return ch;
}

6. ESP8266初始化与配置

6.1 ESP8266启动函数

/**
 * @brief  ESP8266 (Sta Tcp Client)透传
 * @param  无
 * @retval 无
 */
void ESP8266_start(void)
{
    printf_log("\r\n正在配置 ESP8266 ......\r\n");
    HAL_UART_Receive_IT(&macESP8266_USARTx, &UART_TEMP_CHAR, 1);

    macESP8266_CH_ENABLE();  // 使能ESP8266
    ESP8266_AT_Test();       // AT测试
    ESP8266_Net_Mode_Choose(STA_AP);  // 设置为STA+AP模式

    // 连接到指定的WiFi热点
    while (!ESP8266_JoinAP(macUser_ESP8266_ApSsid, macUser_ESP8266_ApPwd))
        ;
    ESP8266_Cmd("AT+CIFSR", "OK", 0, 1000);  // 查询IP地址
    ESP8266_Cmd("AT+CIPMUX=1", "OK", 0, 1000);  // 启用多连接

    ESP8266_Cmd("AT+CIPSERVER=1,8288", "OK", 0, 1000);  // 创建TCP服务器
    // ESP8266_Cmd("AT+CIPSTART="TCP",192.168.1.1,8000","OK",0,1000);

    printf_log("\r\n配置 ESP8266 完毕\r\n");
}

6.2 ESP8266复位函数

/*
 * 函数名:ESP8266_Rst
 * 描述  :重启WF-ESP8266模块
 * 输入  :无
 * 返回  : 无
 * 调用  :被 ESP8266_AT_Test 调用
 */
void ESP8266_Rst(void)
{
#if 0
	 ESP8266_Cmd ( "AT+RST", "OK", "ready", 2500 );

#else
    macESP8266_RST_LOW_LEVEL();  // 复位引脚拉低
    HAL_Delay(500);
    macESP8266_RST_HIGH_LEVEL();  // 复位引脚拉高
#endif
}

7. AT指令交互

7.1 AT指令发送与响应检查

/*
 * 函数名:ESP8266_Cmd
 * 描述  :对WF-ESP8266模块发送AT指令
 * 输入  :cmd,待发送的指令
 *         reply1,reply2,期待的响应,为NULL表不需响应,两者为或逻辑关系
 *         waittime,等待响应的时间
 * 返回  : 1,指令发送成功
 *         0,指令发送失败
 * 调用  :被外部调用
 */
uint8_t ESP8266_Cmd(char *cmd, char *reply1, char *reply2, uint32_t waittime)
{
    strEsp8266_Fram_Record.Inf.InfBit.FramLength = 0; // 从新开始接收新的数据包

    printf_wifi("%s\r\n", cmd);  // 发送AT指令

    if ((reply1 == NULL) && (reply2 == NULL)) // 不需要接收数据
        return 1;

    HAL_Delay(waittime); // 延时等待响应

    strEsp8266_Fram_Record.Data_RX_BUF[strEsp8266_Fram_Record.Inf.InfBit.FramLength] = '\0';

    printf_log("%s", strEsp8266_Fram_Record.Data_RX_BUF);  // 打印响应数据

    // 检查响应是否包含期望的字符串
    if ((reply1 != NULL) && (reply2 != NULL))
    {
        if (strstr(strEsp8266_Fram_Record.Data_RX_BUF, reply1) != NULL ||
            strstr(strEsp8266_Fram_Record.Data_RX_BUF, reply2) != NULL)
            return 1;
        return 0;
    }
    else if (reply1 != NULL)
    {
        if (strstr(strEsp8266_Fram_Record.Data_RX_BUF, reply1) != NULL)
            return 1;
        return 0;
    }
    else
    {
        if (strstr(strEsp8266_Fram_Record.Data_RX_BUF, reply2) != NULL)
            return 1;
        return 0;
    }
}

7.2 AT测试函数

/*
 * 函数名:ESP8266_AT_Test
 * 描述  :对WF-ESP8266模块进行AT测试启动
 * 输入  :无
 * 返回  : 无
 * 调用  :被外部调用
 */
void ESP8266_AT_Test(void)
{
    char count = 0;

    macESP8266_RST_HIGH_LEVEL();
    HAL_Delay(1000);
    while (count < 10)
    {
        if (ESP8266_Cmd("AT", "OK", NULL, 500))  // 发送AT测试指令
            return;
        ESP8266_Rst();  // 如果失败则复位ESP8266
        ++count;
    }
}

8. WiFi连接功能

8.1 设置工作模式

/*
 * 函数名:ESP8266_Net_Mode_Choose
 * 描述  :选择WF-ESP8266模块的工作模式
 * 输入  :enumMode,工作模式
 * 返回  : 1,选择成功
 *         0,选择失败
 * 调用  :被外部调用
 */
uint8_t ESP8266_Net_Mode_Choose(ENUM_Net_ModeTypeDef enumMode)
{
    switch (enumMode)
    {
    case STA:  // 客户端模式
        return ESP8266_Cmd("AT+CWMODE=1", "OK", "no change", 2500);

    case AP:   // 热点模式
        return ESP8266_Cmd("AT+CWMODE=2", "OK", "no change", 2500);

    case STA_AP:  // 客户端+热点模式
        return ESP8266_Cmd("AT+CWMODE=3", "OK", "no change", 2500);

    default:
        return 0;
    }
}

8.2 连接WiFi热点

/*
 * 函数名:ESP8266_JoinAP
 * 描述  :WF-ESP8266模块连接外部WiFi
 * 输入  :pSSID,WiFi名称字符串
 *       :pPassWord,WiFi密码字符串
 * 返回  : 1,连接成功
 *         0,连接失败
 * 调用  :被外部调用
 */
uint8_t ESP8266_JoinAP(char *pSSID, char *pPassWord)
{
    char cCmd[120];

    sprintf(cCmd, "AT+CWJAP=\"%s\",\"%s\"", pSSID, pPassWord);

    return ESP8266_Cmd(cCmd, "OK", NULL, 5000);
}

8.3 创建WiFi热点

/*
 * 函数名:ESP8266_BuildAP
 * 描述  :WF-ESP8266模块创建WiFi热点
 * 输入  :pSSID,WiFi名称字符串
 *       :pPassWord,WiFi密码字符串
 *       :enunPsdMode,WiFi加密方式代号字符串
 * 返回  : 1,创建成功
 *         0,创建失败
 * 调用  :被外部调用
 */
uint8_t ESP8266_BuildAP(char *pSSID, char *pPassWord, ENUM_AP_PsdMode_TypeDef enunPsdMode)
{
    char cCmd[120];

    sprintf(cCmd, "AT+CWSAP=\"%s\",\"%s\",1,%d", pSSID, pPassWord, enunPsdMode);

    return ESP8266_Cmd(cCmd, "OK", 0, 1000);
}

9. TCP/IP通信功能

9.1 启用多连接

/*
 * 函数名:ESP8266_Enable_MultipleId
 * 描述  :WF-ESP8266模块启动多连接
 * 输入  :enumEnUnvarnishTx,配置是否多连接
 * 返回  : 1,配置成功
 *         0,配置失败
 * 调用  :被外部调用
 */
uint8_t ESP8266_Enable_MultipleId(FunctionalState enumEnUnvarnishTx)
{
    return ESP8266_Cmd("AT+CIPMUX=%d", "OK", 0, 500);
}

9.2 连接服务器

/*
 * 函数名:ESP8266_Link_Server
 * 描述  :WF-ESP8266模块连接外部服务器
 * 输入  :enumE,网络协议
 *       :ip,服务器IP字符串
 *       :ComNum,服务器端口字符串
 *       :id,模块连接服务器的ID
 * 返回  : 1,连接成功
 *         0,连接失败
 * 调用  :被外部调用
 */
uint8_t ESP8266_Link_Server(ENUM_NetPro_TypeDef enumE, char *ip, char *ComNum, ENUM_ID_NO_TypeDef id)
{
    char cStr[100] = {0}, cCmd[120];

    switch (enumE)
    {
    case enumTCP:
        sprintf(cStr, "\"%s\",\"%s\",%s", "TCP", ip, ComNum);
        break;

    case enumUDP:
        sprintf(cStr, "\"%s\",\"%s\",%s", "UDP", ip, ComNum);
        break;

    default:
        break;
    }

    if (id < 5)
        sprintf(cCmd, "AT+CIPSTART=%d,%s", id, cStr);

    else
        sprintf(cCmd, "AT+CIPSTART=%s", cStr);

    return ESP8266_Cmd(cCmd, "OK", "ALREAY CONNECT", 4000);
}

9.3 创建/关闭TCP服务器

/*
 * 函数名:ESP8266_StartOrShutServer
 * 描述  :WF-ESP8266模块开启或关闭服务器模式
 * 输入  :enumMode,开启/关闭
 *       :pPortNum,服务器端口号字符串
 *       :pTimeOver,服务器超时时间字符串,单位:秒
 * 返回  : 1,操作成功
 *         0,操作失败
 * 调用  :被外部调用
 */
uint8_t ESP8266_StartOrShutServer(FunctionalState enumMode, char *pPortNum, char *pTimeOver)
{
    char cCmd1[120], cCmd2[120];

    if (enumMode)  // 开启服务器
    {
        sprintf(cCmd1, "AT+CIPSERVER=%d,%s", 1, pPortNum);

        sprintf(cCmd2, "AT+CIPSTO=%s", pTimeOver);

        return (ESP8266_Cmd(cCmd1, "OK", 0, 500) &&
                ESP8266_Cmd(cCmd2, "OK", 0, 500));
    }
    else  // 关闭服务器
    {
        sprintf(cCmd1, "AT+CIPSERVER=%d,%s", 0, pPortNum);

        return ESP8266_Cmd(cCmd1, "OK", 0, 500);
    }
}

10. 数据收发功能

10.1 发送数据

/*
 * 函数名:ESP8266_SendString
 * 描述  :WF-ESP8266模块发送字符串
 * 输入  :enumEnUnvarnishTx,声明是否已使能了透传模式
 *       :pStr,要发送的字符串
 *       :ulStrLength,要发送的字符串的字节数
 *       :ucId,哪个ID发送的字符串
 * 返回  : 1,发送成功
 *         0,发送失败
 * 调用  :被外部调用
 */
uint8_t ESP8266_SendString(FunctionalState enumEnUnvarnishTx, char *pStr, uint32_t ulStrLength, ENUM_ID_NO_TypeDef ucId)
{
    char cStr[20];
    uint8_t bRet = 0;

    if (enumEnUnvarnishTx)  // 透传模式
    {
        printf_wifi("%s", pStr);
        bRet = 1;
    }
    else  // 非透传模式
    {
        if (ucId < 5)
            sprintf(cStr, "AT+CIPSEND=%d,%d", ucId, ulStrLength + 2);
        else
            sprintf(cStr, "AT+CIPSEND=%d", ulStrLength + 2);

        ESP8266_Cmd(cStr, "> ", 0, 1000);  // 等待发送指令的响应
        bRet = ESP8266_Cmd(pStr, "SEND OK", 0, 1000);  // 发送数据
    }

    return bRet;
}

10.2 接收数据

/*
 * 函数名:ESP8266_ReceiveString
 * 描述  :WF-ESP8266模块接收字符串
 * 输入  :enumEnUnvarnishTx,声明是否已使能了透传模式
 * 返回  : 接收到的字符串首地址
 * 调用  :被外部调用
 */
char *ESP8266_ReceiveString(FunctionalState enumEnUnvarnishTx)
{
    char *pRecStr = 0;

    strEsp8266_Fram_Record.Inf.InfBit.FramLength = 0;
    strEsp8266_Fram_Record.Inf.InfBit.FramFinishFlag = 0;

    while (!strEsp8266_Fram_Record.Inf.InfBit.FramFinishFlag)
        ;  // 等待接收完成
    strEsp8266_Fram_Record.Data_RX_BUF[strEsp8266_Fram_Record.Inf.InfBit.FramLength] = '\0';

    if (enumEnUnvarnishTx)  // 透传模式
        pRecStr = strEsp8266_Fram_Record.Data_RX_BUF;
    else  // 非透传模式
    {
        if (strstr(strEsp8266_Fram_Record.Data_RX_BUF, "+IPD"))
            pRecStr = strEsp8266_Fram_Record.Data_RX_BUF;
    }

    return pRecStr;
}

10.3 UART接收中断回调

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart == &macESP8266_USARTx)
    {
        if (strEsp8266_Fram_Record.Inf.InfBit.FramLength < (RX_BUF_MAX_LEN - 1))
                strEsp8266_Fram_Record.Data_RX_BUF[strEsp8266_Fram_Record.Inf.InfBit.FramLength++] = UART_TEMP_CHAR;

        if (HAL_UART_GetState(&macESP8266_USARTx) == HAL_UART_STATE_READY)
        {
            strEsp8266_Fram_Record.Inf.InfBit.FramFinishFlag = 1;
            ucTcpClosedFlag = strstr(strEsp8266_Fram_Record.Data_RX_BUF, "CLOSED\r\n") ? 1 : 0;
            strEsp8266_Fram_Record.Data_RX_BUF[strEsp8266_Fram_Record.Inf.InfBit.FramLength] = '\0';
            if (strEsp8266_Fram_Record.Data_RX_BUF[strEsp8266_Fram_Record.Inf.InfBit.FramLength-1] == '}'){
                printf_log(strEsp8266_Fram_Record.Data_RX_BUF);
                strEsp8266_Fram_Record.Inf.InfBit.FramLength = 0;
            }
            
        }
        HAL_UART_Receive_IT(&macESP8266_USARTx, &UART_TEMP_CHAR, 1);
    }
}

11. 主程序调用

main.c中,我们初始化外设并调用ESP8266启动函数:

int main(void)
{
    /* 初始化HAL库 */
    HAL_Init();

    /* 配置系统时钟 */
    SystemClock_Config();

    /* 初始化外设 */
    MX_GPIO_Init();
    MX_USART2_UART_Init();
    MX_USART3_UART_Init();
    
    /* 启动ESP8266 WiFi模块 */
    ESP8266_start();

    /* 主循环 */
    while (1)
    {
        HAL_Delay(200);
    }
}

12. 总结

本驱动实现了基于STM32 HAL库的ESP8266 WiFi模块驱动,主要功能包括:

  1. ESP8266初始化与复位
  2. AT指令交互
  3. WiFi连接与热点创建
  4. TCP/IP服务器创建与客户端连接
  5. 数据收发功能

通过这些功能,可以实现STM32与ESP8266的通信,进而实现WiFi联网功能,为物联网应用提供基础。

使用时,只需修改macUser_ESP8266_ApSsidmacUser_ESP8266_ApPwd为实际的WiFi名称和密码即可。


网站公告

今日签到

点亮在社区的每一天
去签到