当前位置: 首页 > news >正文

STM32 ESP8266 WiFi模块驱动

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时自动补充\rHAL_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();  // 使能ESP8266ESP8266_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 0ESP8266_Cmd ( "AT+RST", "OK", "ready", 2500 );#elsemacESP8266_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);elsesprintf(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);elsesprintf(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名称和密码即可。

http://www.lryc.cn/news/617649.html

相关文章:

  • JVM管理数据的方式
  • CV 医学影像分类、分割、目标检测,之分类项目拆解
  • 【Lua】题目小练10
  • explicit的作用是什么
  • GaussDB安全配置全景指南:构建企业级数据库防护体系
  • Mybatis学习之逆向工程(十)
  • Java项目基本流程(三)
  • SSM+Dubbo+Zookeeper框架和springcloud框架,写业务的时候主要区别在哪?
  • K8S学习----应用部署架构:传统、虚拟化与容器的演进与对比
  • Jenkins 搭建鸿蒙打包
  • 基于 ZooKeeper 的分布式锁实现原理是什么?
  • 车载软件架构 --- 车辆量产后怎么刷写Flash Bootloader
  • 品质检验·稽核管理·客诉管理一站式数字化平台——全星质量管理 QMS 软件系统
  • 打烊频率?阶段说了算
  • 【AI论文】R-Zero:从零数据起步的自进化推理大语言模型
  • 从源码看 Coze:Agent 的三大支柱是如何构建的?
  • AI测试平台实战:深入解析自动化评分和多模型对比评测
  • [CSP-J 2021] 小熊的果篮
  • 记录一些sonic自动化运行中的问题
  • “一车一码一池一充”:GB 17761-2024新国标下电动自行车的安全革命
  • 【C++竞赛】核桃CSP-J模拟赛题解
  • DreaMoving:基于扩散模型的可控视频生成框架
  • Android Coil3视频封面抽取封面帧存Disk缓存,Kotlin
  • 嵌入式学习的第四十八天-中断+OCP原则
  • 美股期权历史市场数据波动率分析教程
  • 软件测评中HTTP 安全头的配置与测试规范
  • U-Boot常用命令完全指南
  • 【浮点数存储】double类型注意点
  • nginx 设置二级目录-实战
  • 【LLM】OpenAI开源GPT级模型,120B及20B参数GPT-OSS