WIFI模块原理与应用
引言
随着物联网技术快速发展,越来越多的智能设备需要通过无线方式接入互联网。在众多无线通信方案中,**WIFI模组(ESP8266/ESP32系列)**因其成熟的生态和广泛的应用,成为实现远程控制、数据采集等功能的理想选择。
为了简化设备连接和数据管理,物联网云平台应运而生,成为万物互联时代的关键基础设施。

ESP8266模块特点

硬件接线
- 供电电压:WIFI模块必须采用3.3V供电

AT指令
WIFI模块通过串口接收AT指令进行控制,所有指令必须大写 并以\r\n结尾。

配置步骤:
通过串口进行调试。
- 测试指令 :
AT\r\n- 检测模块是否正常工作

- 设置模式 :
AT+CWMODE_DEF=3\r\n- 设置为STA模式(设备模式)

- 连接路由 :
AT+CWJAP_DEF="SSID","password"\r\n- 连接指定WIFI网络

- 使能透传 :
AT+CIPMODE=1\r\n- 启用透传模式

- 建立连接 :
AT+CIPSTART="TCP","server_ip",port\r\n- 连接服务器

- 进入透传 :
AT+CIPSEND\r\n- 进入透传数据传输模式

- 退出透传 :发送
+++(不带回车换行)退出透传模式
重要提示:模块在透传模式下不会响应AT指令,配置参数时必须先退出透传模式。
IoT云平台接入
云平台基本概念
物联网云平台是连接设备、处理数据、支持应用开发的核心组件,具有以下特点:
- 支持海量设备连接(如阿里云支持亿级连接)
- 提供设备端SDK,支持多种协议(TCP、MQTT等)
- 实现设备远程监控、状态管理和数据采集
- 显著降低开发成本,提高系统可靠性
常用平台:巴法云、机智云、阿里云物联网平台等
接入原理
设备 → WIFI模块 → 云平台服务器 → 应用程序
- 主题(Topic) :消息的分类标识,设备通过订阅/发布模式进行通信
- 订阅者(Subscriber):接收特定主题消息的设备
- 发布者(Publisher):向特定主题发送消息的设备
巴法云接入流程(TCP设备云)
服务器配置
- 服务器地址 :
bemfa.com - 端口 :
8344
消息格式
TCP协议使用键值对格式进行通信,字段间用 & 分隔,每条指令以 \r\n 结尾。
字段说明
| 字段 | 说明 | 示例 |
|---|---|---|
| cmd | 消息类型(详见下表) | cmd=1 |
| uid | 用户私钥(从控制台获取) | uid=xxxxxxxx |
| topic | 主题名称(设备标识) | topic=light001 |
| msg | 消息内容 | msg=on |
消息类型(cmd)
| 值 | 功能 | 说明 |
|---|---|---|
| 1 | 订阅消息 | 订阅主题,接收消息 |
| 2 | 发布消息 | 向主题发送消息 |
| 3 | 订阅+历史 | 订阅主题并拉取最新消息 |
| 7 | 获取时间 | 获取服务器时间 |
| 9 | 获取历史 | 拉取主题最新消息 |
协议规范
- 分隔符 :字段间使用
&分隔 - 结尾符 :每条指令必须以
\r\n结尾 - 心跳机制:建议60秒发送一次心跳,超过65秒未发送会断线
心跳机制
发送任意数据都可作为心跳消息,建议定期发送以保持连接:
ping\r\n
接入流程
- 注册账号:获取唯一用户ID(UID)

- 创建主题:定义设备通信的主题名称



- 订阅主题:设备订阅主题

- 发布消息:向主题发送数据

- 接收消息:MCU处理接收到来自订阅主题的消息
注意
- **双重身份:**设备可以即是订阅者又是发布者
- 消息回传:云平台会将主题消息发送给所有订阅者,包括发布者自身

- 心跳机制:需要周期性发送心跳包维持连接,建议使用定时器
- 消息构造:必须严格按照平台要求的格式构造消息
- 连接管理:正确处理连接断开和重连逻辑
STM32代码实现
c
#define BUFFERSIZE 512 // 缓冲区大小
volatile uint8_t wifi_recvbuf[BUFFERSIZE] = {0}; // 接收数据缓冲区数组,用于存储从WIFI模块接收的数据
volatile uint32_t wifi_counter = 0; // 接收数据计数器,记录当前缓冲区中有效数据的长度
UART3初始化函数
c
/**
* @brief UART3串口初始化函数,用于配置STM32与WIFI模块的通信接口
* @param baud 波特率设置参数,WIFI模块默认为115200bps
* @return void 无返回值
* @note 使用GPIOB的PB10(TX)和PB11(RX)引脚,配置为USART3功能
* 数据格式:8位数据位,1位停止位,无校验位,无硬件流控
* 使能接收中断,采用中断方式处理接收数据
* 优先级分组为组4,抢占优先级范围0-15
*/
static void UART3_Config(u32 baud)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// 1. 开启GPIOB时钟(AHB1总线)
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
// 2. 开启USART3时钟(APB1总线)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
// 3. 配置引脚复用功能
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);
// 4. 配置GPIO参数
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 复用功能模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // 高速模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 上拉电阻
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 5. 配置USART参数
USART_InitStructure.USART_BaudRate = baud;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART3, &USART_InitStructure);
// 6. 配置USART3中断
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 7. 使能接收中断
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
// 8. 清空发送寄存器
while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
// 9. 清除中断标志
USART_ClearITPendingBit(USART3, USART_IT_RXNE);
// 10. 使能USART3
USART_Cmd(USART3, ENABLE);
}
WIFI发送AT指令函数
c
void UART3_SendStr(char * str)
{
while(*str != '\0')
{
//等待发送数据寄存器为空
while( USART_GetFlagStatus(USART3,USART_FLAG_TXE) == RESET );
USART_SendData(USART3,*str++);
}
}
/**
* @brief 向WIFI模块发送AT指令并等待响应
* @param str 待发送的AT指令字符串,必须以"\r\n"结尾
* @param time 超时时间(毫秒),在规定时间内未收到响应则判定失败
* @return bool 指令执行结果,true表示成功,false表示失败或超时
* @note 成功条件:接收到"OK"或">"响应
* 函数会清空接收缓冲区,发送指令后轮询等待响应
* 超时机制防止程序死等,提高系统鲁棒性
* 典型应用:测试连接、设置参数、建立连接等
*/
bool WIFI_SendAT(char *str, uint16_t time)
{
// 初始化接收缓冲区
memset((char *)wifi_recvbuf, 0, BUFFERSIZE);
wifi_counter = 0;
// 发送AT指令
UART3_SendStr(str);
// 超时等待响应
while(--time)
{
delay_ms(1);
// 检查是否收到成功响应
if(strstr((char *)wifi_recvbuf, "OK") || strstr((char *)wifi_recvbuf, ">"))
{
break;
}
}
// 判断超时状态
if(time > 0)
return true; // 成功收到响应
else
return false; // 超时未收到响应
}
WIFI模块初始化
c
/**
* @brief WIFI模块完整初始化函数,配置模块参数并连接云平台
* @return void 无返回值
* @note 执行顺序:硬件初始化→退出透传→测试连接→设置模式→连接路由
* →使能透传→连接服务器→进入透传
* 每个步骤都有状态检查,失败时输出错误信息
* 连接服务器地址为巴法云:bemfa.com:8344
*/
volatile uint8_t wifi_init_flag = 0;
void WIFI_Config(void)
{
// 1. 硬件初始化
UART3_Config(115200);
// 2. 退出透传模式(确保在AT指令模式)
UART3_SendStr("+++");
delay_ms(1000);
// 3. 发送测试指令
if(WIFI_SendAT("AT\r\n", 5000))
printf("WIFI模块在线\r\n");
else
printf("WIFI模块离线\r\n");
// 4. 设置WIFI为STA模式
if(WIFI_SendAT("AT+CWMODE_DEF=1\r\n", 5000))
printf("WIFI模式设置成功\r\n");
else
printf("WIFI模式设置失败\r\n");
// 5. 连接路由器
if(WIFI_SendAT("AT+CWJAP_DEF=\"wby\",\"12345678\"\r\n", 10000))
printf("WIFI连接路由成功\r\n");
else
printf("WIFI连接路由失败\r\n");
// 6. 设置透传模式
if(WIFI_SendAT("AT+CIPMODE=1\r\n", 10000))
printf("设置透传模式成功\r\n");
else
printf("设置透传模式失败\r\n");
// 7. 连接云平台服务器
if(WIFI_SendAT("AT+CIPSTART=\"TCP\",\"bemfa.com\",8344\r\n", 10000))
printf("连接服务器成功\r\n");
else
printf("连接服务器失败\r\n");
// 8. 进入透传模式
if(WIFI_SendAT("AT+CIPSEND\r\n", 10000))
printf("进入透传成功\r\n");
else
printf("进入透传失败\r\n");
// 设置初始化完成标志
wifi_init_flag = 1;
}
消息发布函数
c
void UART3_SendData(char * str, int len)
{
while(len--)
{
//等待发送数据寄存器为空
USART_SendData(USART3,*str++);
while( USART_GetFlagStatus(USART3,USART_FLAG_TXE) == RESET );
}
}
/**
* @brief 向巴法云平台发布消息到指定主题
* @param topic 主题名称字符串,用于标识消息分类
* @param msgstring 消息内容字符串,实际传输的数据
* @param time 超时时间(毫秒),等待服务器响应的最大时间
* @return bool 发布结果,true表示成功,false表示失败或超时
* @note 消息格式:cmd=2&uid=用户ID&topic=主题名&msg=消息内容\r\n
* 成功响应:服务器返回"cmd=2&res=1"表示接收成功
* 必须确保WIFI已连接并处于透传模式
* 消息最大长度受缓冲区限制(256字节)
*/
bool Bemfa_Publish(char *topic, char *msgstring, uint16_t time)
{
char buf[256] = {0};
// 清空接收缓冲区
memset((char *)wifi_recvbuf, 0, BUFFERSIZE);
wifi_counter = 0;
// 构造发布报文
sprintf(buf, "cmd=2&uid=%s&topic=%s&msg=%s\r\n", BEMFA_UID, topic, msgstring);
// 发送报文
UART3_SendData(buf, strlen(buf));
// 等待服务器响应
while(--time)
{
delay_ms(1);
if(strstr((char *)wifi_recvbuf, "cmd=2&res=1"))
{
break;
}
}
// 返回结果
if(time > 0)
return true;
else
return false;
}
主题订阅函数
c
/**
* @brief 订阅巴法云平台的指定主题
* @param topic 要订阅的主题名称字符串
* @param time 超时时间(毫秒),等待服务器响应的最大时间
* @return bool 订阅结果,true表示成功,false表示失败或超时
* @note 订阅格式:cmd=1&uid=用户ID&topic=主题名\r\n
* 成功响应:服务器返回"cmd=1&res=1"表示订阅成功
* 订阅后,该主题的所有消息都会推送到设备
* 一个设备可以订阅多个主题
*/
bool Bemfa_Subscribe(char *topic, uint16_t time)
{
char buf[256] = {0};
// 清空接收缓冲区
memset((char *)wifi_recvbuf, 0, BUFFERSIZE);
wifi_counter = 0;
// 构造订阅报文
sprintf(buf, "cmd=1&uid=%s&topic=%s\r\n", BEMFA_UID, topic);
// 发送报文
UART3_SendData(buf, strlen(buf));
// 等待服务器响应
while(--time)
{
delay_ms(1);
if(strstr((char *)wifi_recvbuf, "cmd=1&res=1"))
{
break;
}
}
// 返回结果
if(time > 0)
return true;
else
return false;
}
USART3中断服务函数
c
/**
* @brief USART3中断服务函数,处理来自WIFI模块的数据接收
* @return void 无返回值
* @note 触发条件:USART3接收到数据(RXNE标志置位)
* 数据存储:将接收到的字节存入环形缓冲区
* 溢出处理:缓冲区满时重置计数器(建议改进为循环队列)
* 转发功能:初始化完成后,将数据转发到USART1(调试串口)
* 中断标志:必须手动清除RXNE标志
*/
void USART3_IRQHandler(void)
{
// 检查接收中断是否发生
if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
{
// 检查缓冲区是否溢出
if(wifi_counter < BUFFERSIZE)
{
// 存储接收到的数据
wifi_recvbuf[wifi_counter++] = USART_ReceiveData(USART3);
// 初始化完成后,将数据转发到调试串口
if(wifi_init_flag)
{
USART_SendData(USART1, wifi_recvbuf[wifi_counter - 1]);
}
}
else
{
// 缓冲区溢出处理(建议使用环形缓冲区)
wifi_counter = 0;
}
// 清除中断标志位
USART_ClearITPendingBit(USART3, USART_IT_RXNE);
}
}
测试
c
int main(void)
{
//1.进行NVIC优先级分组 分组4: 抢占优先级4bit(0~15)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
//2.硬件初始化
UART_PC_Init(115200); // 蓝牙**控灯示例有该函数的具体实现**
WIFI_Config();
//3.订阅主题
Bemfa_Subscribe("led002",5000);
/* Infinite loop */
while (1)
{
//4.向服务器的主题发布消息
Bemfa_Publish("led002","on",5000);
delay_ms(5000);
Bemfa_Publish("led002","off",5000);
delay_ms(5000);
}
}



错误处理机制
c
// 建议添加错误重试机制
#define MAX_RETRY_COUNT 3
bool WIFI_ConnectWithRetry(void)
{
uint8_t retry_count = 0;
while(retry_count < MAX_RETRY_COUNT)
{
if(WIFI_SendAT("AT\r\n", 5000))
return true;
retry_count++;
delay_ms(1000); // 重试间隔
}
return false;
}
心跳包实现
c
// 使用定时器发送心跳包 65s内发送
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
{
// 发送心跳包
Bemfa_Publish("heartbeat", "ping\r\n", 1000);
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
消息解析处理
c
// 解析云平台下发的控制指令
void ParseControlMessage(char *message)
{
if(strstr(message, "cmd=3")) // 控制指令
{
// 解析具体控制内容
// 例如:打开/关闭LED、调节参数等
}
}
常见问题与解决方案
WIFI模块无法连接
- 检查供电:确保使用3.3V稳定供电
- 检查接线:TX/RX交叉连接,GND共地
- 检查波特率:确保MCU与模块波特率一致(默认115200)
- 检查AT指令:确保指令格式正确(大写+回车换行)
连接云平台失败
- 检查网络:确保WIFI已连接互联网
- 检查服务器地址:确认服务器IP和端口正确
- 检查UID:确保用户ID正确无误
- 检查防火墙:某些网络环境可能屏蔽特定端口
数据传输不稳定
- 增加超时时间:适当延长指令等待时间
- 添加重试机制:失败时自动重试
- 优化缓冲区:使用环形缓冲区避免数据丢失
- 定期发送心跳:维持长连接稳定性
扩展
生态建立(接入米家)

若米家有接入智能音箱,可以通过小爱同学(米家)智能控制,参考小爱同学接入

微信小程序开发
- 巴法云提供小程序开发支持
- 可实现手机远程控制设备
- 支持实时数据显示和历史查询
- 可定制化用户界面
巴法云提供官方小程序

想要开发自己的个性小程序,可以参考巴法云教程
