1. 硬件准备与环境搭建
第一次接触STM32和ESP8266的组合时,我完全被各种接线和配置搞晕了。后来发现只要理清思路,这套组合其实比想象中简单得多。我们先来看看需要准备哪些硬件:
- STM32F103C8T6开发板(俗称蓝板):性价比之王,淘宝30块就能买到
- ESP8266-01模块:注意要买带底板的那种,直接插线就能用
- USB转TTL模块:用于调试ESP8266
- 杜邦线若干:建议买20cm长度的,太短了接线不方便
硬件连接有个小技巧:先把ESP8266单独接上USB转TTL,用串口助手测试AT指令是否正常。我遇到过新买的模块波特率不是115200的情况,这时候需要先发送"AT+UART_DEF=115200,8,1,0,0\r\n"配置波特率。
开发环境推荐使用Keil MDK,安装过程要注意两点:
- 记得安装STM32F1的Device Family Pack
- 在Manage Run-Time Environment里勾选CMSIS和Device Startup
第一次编译时可能会遇到找不到头文件的问题,这是因为没有正确设置Include Paths。我通常会把以下路径加进去:
- \Drivers\CMSIS\Include
- \Drivers\STM32F1xx_HAL_Driver\Inc
- \Drivers\CMSIS\Device\ST\STM32F1xx\Include
2. ESP8266基础配置
ESP8266的AT指令让我又爱又恨,爱的是功能强大,恨的是响应经常不稳定。经过多次踩坑,我总结出一套稳定的初始化流程:
// 初始化序列 esp8266_send_cmd("AT", "OK", 100); // 测试模块是否正常 esp8266_send_cmd("AT+CWMODE=1", "OK", 100); // 设置为Station模式 esp8266_send_cmd("AT+CIPMUX=0", "OK", 100); // 单连接模式这里有个坑要注意:发送AT指令后一定要加回车换行符"\r\n",很多新手会漏掉这个导致模块无响应。我专门写了个发送函数:
void sendATCommand(char* cmd) { USART_SendString(USART3, cmd); USART_SendString(USART3, "\r\n"); Delay_ms(500); // 留出响应时间 }WiFi连接是最容易出问题的环节。建议先用手机热点测试,因为很多校园网和企业网络会有认证页面,ESP8266无法自动跳转。连接成功后记得保存配置:
esp8266_send_cmd("AT+CWJAP_DEF=\"SSID\",\"password\"", "OK", 5000);3. OneNET平台接入实战
第一次接触OneNET时,我被各种产品、设备、数据流的概念绕晕了。其实可以这样理解:
- 产品:相当于项目大类
- 设备:具体的硬件终端
- 数据流:设备上传的数据字段
创建产品时要注意几个关键参数:
- 联网方式选择WiFi
- 接入协议选择HTTP
- 操作系统选Android(实测选其他也没影响)
设备添加成功后,要记下三个关键信息:
- 设备ID(10位数字)
- API Key(长度不固定)
- 产品ID(可选)
数据上传的HTTP报文格式有严格要求,我刚开始总是返回400错误,后来发现是JSON格式不对。正确的模板应该是:
{ "datastreams": [ { "id": "temperature", "datapoints": [ { "value": 25.5 } ] } ] }4. STM32与ESP8266通信实现
硬件连接很简单:
- ESP8266的TX接STM32的PB11(USART3_RX)
- ESP8266的RX接STM32的PB10(USART3_TX)
- 共地连接必不可少
串口配置要注意三点:
- 波特率必须一致(建议115200)
- 开启接收中断
- 设置合适的缓冲区大小
我封装了一个完整的发送接收流程:
void ESP8266_SendData(float temp, float humi) { char json[256]; sprintf(json, "{\"datastreams\":[{\"id\":\"temp\",\"datapoints\":[{\"value\":%.1f}]}," "{\"id\":\"humi\",\"datapoints\":[{\"value\":%.1f}]}]}", temp, humi); char header[512]; sprintf(header, "POST /devices/%s/datapoints HTTP/1.1\r\n" "api-key: %s\r\n" "Host: api.heclouds.com\r\n" "Content-Length: %d\r\n\r\n", DEVICE_ID, API_KEY, strlen(json)); USART_SendString(USART3, "AT+CIPSEND="); USART_SendNumber(USART3, strlen(header)+strlen(json)); USART_SendString(USART3, "\r\n"); Delay_ms(100); USART_SendString(USART3, header); USART_SendString(USART3, json); }5. 常见问题排查指南
遇到问题时,建议按照以下步骤排查:
- ESP8266无响应
- 检查供电是否充足(建议3.3V 500mA以上)
- 确认波特率设置正确
- 检查TX/RX线是否接反
- WiFi连接失败
- 确认SSID和密码正确
- 尝试更换2.4GHz网络(ESP8266不支持5GHz)
- 检查路由器是否开启了MAC过滤
- OneNET接入失败
- 检查设备ID和API Key是否正确
- 确认网络时间同步(ESP8266需要正确的时间戳)
- 尝试用Postman测试API接口
- 数据上传成功但平台不显示
- 检查数据流ID是否匹配
- 确认数值类型正确(字符串需要加引号)
- 查看平台的数据存储策略(有时会有几分钟延迟)
6. 项目优化与扩展
基础功能实现后,可以考虑以下几个优化方向:
数据压缩传输对于电池供电的设备,可以压缩JSON数据:
// 原始数据 {"datastreams":[{"id":"temp","datapoints":[{"value":25.5}]}]} // 压缩后 {"ds":[{"id":"t","dp":[{"v":25.5}]}]}低功耗设计
- 使用STM32的STOP模式降低功耗
- 设置ESP8266的睡眠模式
- 减少数据上传频率
本地缓存添加EEPROM或Flash存储,在网络异常时暂存数据:
typedef struct { float temp; float humi; uint32_t timestamp; } SensorData; void saveToFlash(SensorData data) { FLASH_Unlock(); FLASH_ErasePage(0x0800F000); FLASH_ProgramWord(0x0800F000, *(uint32_t*)&data.temp); FLASH_ProgramWord(0x0800F004, *(uint32_t*)&data.humi); FLASH_ProgramWord(0x0800F008, data.timestamp); FLASH_Lock(); }安全增强
- 启用OneNET的token鉴权
- 添加数据签名验证
- 使用HTTPS协议(需要ESP8266支持)
在实际项目中,我发现STM32的USART3和TIM2中断有时会冲突,导致数据丢失。解决方案是调整中断优先级,确保串口中断优先于定时器中断。还有一个坑是ESP8266的TCP连接默认超时时间是180秒,长时间不上传数据会导致连接断开,需要定期发送心跳包保持连接。