🚀 STM32F407 × 微信小程序 × 华为云 IoT 全链路开发

从嵌入式下位机到云端数据平台,手把手教你实现完整的物联网系统。下位机使用标准库+裸机开发,小程序采用 AI VibeCoding 零门槛开发,数据实时上华为云平台。

⚙️ STM32F407ZET6 标准库 📶 BLE蓝牙透传 🌐 ESP8266 WiFi 📱 微信小程序 ☁️ 华为云IoT 🤖 AI VibeCoding 🌡️ DHT11温湿度 💾 W25Q128 Flash

🎯 项目目标

同学们将掌握:

STM32多串口并发

UART1调试、UART2接BLE、UART3接ESP8266

自定义二进制协议

帧格式设计、状态机解析、校验和验证

BLE蓝牙与小程序交互

BLE透传、协议封装、UI响应

WiFi数据上云

ESP8266 AT指令、TCP连接、JSON上报

📦 技术栈全景

层次技术
感知层DHT11 温湿度、LED指示灯
控制层STM32F407 标准库裸机
传输层BLE DX-BT24 / ESP8266 WiFi
应用层微信小程序 VibeCoding
云平台华为云 IoTDA / MQTT
存储W25Q128 SPI Flash

📅 学习路径

Day1 环境搭建 + UART通信基础
Day2 传感器 + 协议设计进阶
Day3 BLE + 小程序VibeCoding核心
Day4 WiFi + 华为云上报云端
Day5 Flash存储 + 综合调试综合

🔄 数据流总览

🌡️ DHT11
温湿度
⚙️ STM32F407
主控制器
UART1调试↑
📶 BLE
DX-BT24
UART2 9600
📱 微信小程序
VibeCoding
🌐 ESP8266
WiFi
UART3 115200
☁️ 华为云IoT
MQTT/TCP
💡 前置知识说明同学们已具备STM32标准库开发基础(GPIO、UART、SPI、中断),本课程聚焦于多模块协同、通信协议设计、云端联动三大核心技能。小程序部分无需JS基础,使用AI VibeCoding辅助开发。

🏗️ 整体系统架构

感知层 🌡️ DHT11 温湿度传感器 PG9 单总线 💡 LED×4 状态指示 PG6/11/13/14 💾 W25Q128 SPI Flash 16MB SPI1 PB3/4/5 控制层 (MCU) ⚙️ STM32F407ZET6 ARM Cortex-M4 @ 168MHz 标准库 | 裸机(无RTOS) 📡 UART1 (PA9/PA10) 115200 bps | PC调试输出 📡 UART2 (PA2/PA3) 9600 bps | BLE透传 📡 UART3 (PB10/PB11) 115200 bps | ESP8266 🧩 帧解析状态机 frame_parser.c | protocol.c 🌡️ DHT11驱动 bsp_dht11.c | 单总线时序 💾 W25Q128驱动 bsp_w25q128.c | SPI1 🌐 ESP8266驱动 esp8266.c | AT指令集 📋 主循环调度 main.c | while(1) 轮询 传输层 📶 DX-BT24 BLE蓝牙模块 透传模式 UART2 ↔ BLE 距离: ~10m 🌐 ESP8266 WiFi模块 AT指令控制 UART3 ↔ WiFi TCP/MQTT 应用层 (小程序) 📱 微信小程序 AI VibeCoding开发 💡 控制页 (LED) 🌡️ 采集页 (传感) ⚙️ 设置页 (配网) protocol.js ble.js | storage.js 云平台 ☁️ 华为云IoT IoTDA平台 MQTT接入 设备管理 数据可视化 规则引擎/告警 UART2 9600 UART3 BLE TCP/MQTT ↑ UART1(115200) → PC串口助手调试

📁 工程目录结构

STM32F407_Project/
├── app/
│   └── main.c              ← 主程序入口,主循环
├── bsp/                    ← 板级支持包
│   ├── uart/
│   │   ├── bsp_uart.c      ← UART1 (调试)
│   │   ├── bsp_uart2.c     ← UART2 (BLE)
│   │   └── bsp_uart3.c     ← UART3 (ESP8266)
│   ├── dht11/
│   │   └── bsp_dht11.c     ← DHT11温湿度
│   ├── led/
│   │   └── bsp_led.c       ← LED驱动
│   ├── esp8266/
│   │   └── esp8266.c       ← WiFi AT指令
│   └── w25q128/
│       └── bsp_w25q128.c   ← SPI Flash
├── module/
│   ├── protocol.c          ← 帧构建/校验
│   ├── protocol.h          ← 协议定义
│   ├── frame_parser.c      ← 状态机解析+路由
│   └── stm32f4xx_it.c      ← 中断服务函数
├── board/
│   └── board.c             ← SysTick延时等
└── libraries/              ← STM32标准库(不修改)

📁 小程序目录结构

WXMP-IOT中控系统/
├── app.js                  ← 全局BLE连接管理
├── pages/
│   ├── control/
│   │   ├── control.js      ← LED控制逻辑
│   │   └── control.wxml    ← 控制页面布局
│   ├── collection/
│   │   ├── collection.js   ← 温湿度展示
│   │   └── collection.wxml ← 数据可视化
│   └── settings/
│       ├── settings.js     ← WiFi/IoT配置
│       └── settings.wxml   ← 配置表单
├── utils/
│   ├── protocol.js         ← 帧协议封装(与MCU对称)
│   ├── ble.js              ← BLE连接管理
│   ├── storage.js          ← 本地存储
│   └── log.js              ← 日志系统
└── custom-tab-bar/         ← 底部Tab栏

🔄 核心数据流详解

方向路径数据格式说明
📱→💻小程序 → BLE → UART2 → STM32二进制帧 AA 05 11 FF D1LED控制、WiFi配置、系统命令
💻→📱STM32 → UART2 → BLE → 小程序JSON字符串 {"temp":25.4,"humi":46.2}温湿度数据、状态反馈
💻→☁️STM32 → UART3 → ESP8266 → 华为云JSON字符串 (TCP透传)传感器数据上报云端
☁️→💻华为云 → ESP8266 → UART3 → STM32二进制帧 (云端下发)远程控制指令
🖥️↔💻PC串口助手 ↔ UART1 ↔ STM32AT文本命令 + 二进制帧开发调试专用

📅 五天教学计划详表

⏱️ Day 1 🎯 环境搭建 + UART多串口通信

📋 教学目标

  • 理解工程模板结构(BSP/Module/App分层)
  • 掌握STM32F407标准库UART配置
  • 实现UART1/2/3三路串口并发接收(中断+环形缓冲区)
  • 实现printf重定向到UART1
  • 验证BLE模块(AT指令测试DX-BT24)

⏰ 时间分配

时段内容
上午 2h工程模板导入、Keil5配置、编译下载验证
上午 2hUART1配置讲解,环形缓冲区原理,printf重定向
下午 2hUART2/3配置,多串口并发接收演示
下午 2hBLE AT指令测试,串口助手联调

✅ 课后验证点

验收标准 1. 串口助手收到开机打印信息
2. UART1发送数据能原路回显
3. UART2收发数据不丢帧
4. BLE模块响应AT指令 OK

💡 教学建议

重点强调 环形缓冲区(Ring Buffer)是多串口并发的关键,务必让同学理解 Head/Tail 指针机制,这是后续一切通信的基础。

📦 代码文件

bsp_uart.c bsp_uart2.c bsp_uart3.c board.c
⏱️ Day 2 🎯 传感器驱动 + 通信协议设计

📋 教学目标

  • 掌握DHT11单总线时序编程(精确微秒延时)
  • 理解自定义二进制帧协议的设计思路
  • 实现protocol.c帧构建和校验和计算
  • 实现状态机逐字节解析(frame_parser.c)
  • LED控制帧的发送与接收验证

⏰ 时间分配

时段内容
上午 2hDHT11时序讲解,单总线驱动编写
上午 2h协议帧格式设计,校验和计算推导
下午 2h状态机解析器原理与实现
下午 2h串口助手发送HEX帧测试LED控制

✅ 课后验证点

验收标准 1. 串口每10秒打印温湿度数据
2. 发送 AA 05 11 FF D1 → LED1亮
3. 发送 AA 05 11 00 D0 → LED1灭
4. 校验和错误帧被正确丢弃

💡 教学建议

动手推导 让同学手工计算几个帧的校验和,理解"AA+05+11+FF=D1"的来源,加深对协议的理解。可在白板演示状态机跳转图。
⏱️ Day 3 🎯 BLE蓝牙 + 小程序 VibeCoding

📋 教学目标

  • 理解BLE GATT通信模型(Service/Characteristic)
  • 掌握小程序蓝牙API(wx.createBLEConnection等)
  • 使用AI工具VibeCoding快速生成小程序代码
  • 实现小程序控制LED(通过BLE发送二进制帧)
  • 实现小程序接收温湿度JSON数据并显示

📱 VibeCoding流程

描述功能给AI

用自然语言告诉AI需要什么功能

AI生成代码

复制生成的代码到微信开发者工具

调试验证

真机测试,问题反馈给AI修改

✅ 课后验证点

验收标准 1. 小程序成功扫描并连接BLE设备
2. 点击LED开关,灯实际响应
3. 小程序实时显示温湿度数据
4. 断开重连功能正常

💡 教学建议

重要提示 强调BLE权限配置(manifest中声明蓝牙权限),iOS和Android可能行为不同。protocol.js中的TextEncoder要用兼容写法(见代码中的stringToUtf8Bytes函数)。

📦 代码文件

utils/ble.js utils/protocol.js pages/control pages/collection
⏱️ Day 4 🎯 ESP8266 WiFi + 华为云IoT数据上报

📋 教学目标

  • 掌握ESP8266 AT指令集(RST/CWMODE/CWJAP/CIPSTART/CIPSEND)
  • 理解TCP透传模式数据发送流程
  • 在华为云IoTDA创建产品和设备
  • 实现MQTT协议接入华为云(通过ESP8266 TCP透传)
  • 实现DHT11数据定时上报云端
  • 通过小程序配置WiFi凭证并保存到Flash

☁️ 华为云配置步骤

创建产品

IoTDA控制台 → 产品 → 新建产品(自定义协议)

添加设备

获取设备ID、密钥、接入地址

配置网络

小程序设置页输入WiFi SSID/密码,发送给STM32

验证上报

华为云设备影子查看温湿度数据

✅ 课后验证点

验收标准 1. ESP8266成功连接WiFi,串口打印IP
2. 华为云设备在线状态显示在线
3. 云端收到JSON温湿度数据
4. 小程序WiFi配置持久化(重启后自动连接)

💡 教学建议

避坑指南 ESP8266 RST后需等待3秒再发AT命令。WiFi连接超时设15秒(路由器响应慢)。TCP透传模式下发数据前要发 AT+CIPSEND=长度,等到">"提示符后再发数据。
⏱️ Day 5 🎯 Flash存储 + 综合系统联调

📋 教学目标

  • 掌握W25Q128 SPI Flash读写操作(页写/扇区擦除)
  • 实现WiFi配置、IoT配置持久化存储
  • 实现系统断电重启后自动恢复连接
  • 全系统端到端联调:小程序→BLE→STM32→WiFi→云
  • 性能优化:防重入保护、超时重试、错误恢复

🔍 综合测试场景

测试用例清单 ① 小程序连BLE → 控制LED → 验证响应 ✓
② 小程序发WiFi配置 → Flash保存 → 自动连WiFi ✓
③ STM32重启 → 自动读Flash → 自动连WiFi ✓
④ 温湿度每10秒上报云端,云端可视化 ✓
⑤ 小程序断开BLE重连,功能恢复正常 ✓
⑥ 断网重连,数据上报恢复 ✓

✅ 最终验收

完整系统验收标准 1. 全链路数据流通(传感器→云端)
2. 小程序UI交互流畅,数据实时更新
3. 断电重启后系统自动恢复
4. 错误处理机制完善(超时/校验失败)

💡 拓展方向

课程延伸 · 华为云规则引擎:温度超阈值触发告警
· 云端下发控制命令(双向通信)
· ADC采集光照/土壤湿度等模拟量
· OTA固件升级(通过ESP8266)

🔧 硬件连接总表

模块STM32引脚功能配置参数注意事项
UART1 TXPA9PC调试输出115200,8N1printf重定向至此
UART1 RXPA10PC调试输入115200,8N1中断+环形缓冲
UART2 TXPA2→ BLE模块RX9600,8N1DX-BT24默认9600
UART2 RXPA3← BLE模块TX9600,8N1中断+环形缓冲
UART3 TXPB10→ ESP8266 RX115200,8N1AT指令发送
UART3 RXPB11← ESP8266 TX115200,8N1中断+环形缓冲
DHT11 DQPG9单总线数据输出/输入切换需4.7kΩ上拉
LED1PG14状态指示推挽输出低电平亮(共阳)
LED2PG13状态指示推挽输出低电平亮
LED3PG6状态指示推挽输出低电平亮
LED4PG11状态指示推挽输出低电平亮
SPI1 SCKPB3W25Q128时钟SPI Mode0硬件SPI1复用
SPI1 MISOPB4W25Q128读数据SPI Mode0
SPI1 MOSIPB5W25Q128写数据SPI Mode0
W25Q128 CSPG10Flash片选推挽输出低电平有效

📌 ESP8266接线说明

⚠️ 重要:ESP8266供电ESP8266工作电压3.3V,电流峰值可达300mA,必须使用独立3.3V稳压电源,不能直接用STM32板载3.3V(可能导致复位)。
ESP8266引脚连接到说明
VCC独立3.3V电源正
GND共地与STM32共地
TXSTM32 PB11(RX3)ESP发→STM收
RXSTM32 PB10(TX3)STM发→ESP收
EN/CH_PD3.3V使能引脚必须拉高
RST悬空或3.3V软复位通过AT+RST
GPIO03.3V或悬空正常工作模式

📌 DX-BT24 BLE模块接线

ℹ️ DX-BT24特性默认透传模式,上电即可广播,无需AT指令初始化。波特率默认9600bps,与UART2对应。
BLE模块引脚连接到说明
VCC3.3V电源正
GNDGND电源地
TXDPA3 (UART2 RX)BLE发→STM收
RXDPA2 (UART2 TX)STM发→BLE发
透传原理小程序通过BLE发送数据 → BLE模块通过串口转发给STM32 → STM32处理后通过串口回复 → BLE模块发给小程序。完全透明传输!

⚡ NVIC中断优先级配置

中断源抢占优先级响应优先级说明
USART1 (调试)20最低优先级,调试用
USART2 (BLE)10中等优先级,实时性要求高
USART3 (ESP8266)11与BLE同级,次优先
SysTick (延时)00最高,保证延时精确
⚠️ 注意STM32F407需先配置优先级分组,项目中使用 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2),共4个抢占级、4个响应级。

📦 通信协议规范 v1.2

设计原则下位机和小程序使用完全对称的协议,protocol.c(C语言)和 protocol.js(JavaScript)实现相同的帧格式,确保互通。

📐 帧格式定义

0xAA
包头
Frame Head
+
N
数据个数
= 4+数据长
+
DevID
设备号
Device ID
+
Data...
数据内容
N-4 字节
+
SUM
校验和
低8位累加
📐 N字段含义 N = 包头(1) + N本身(1) + 设备号(1) + 数据内容 + 校验和(1) = 4 + 数据内容长度
校验和 = (0xAA + N + DevID + Data[0] + ... + Data[n-1]) & 0xFF

🔢 设备号(DevID)定义

DevID设备/功能数据内容示例帧
0x00系统PING(触发温湿度上报)1字节: 0x00AA 05 00 00 AF
0x01系统复位1字节: 0x00AA 05 01 00 B0
0x10LED批量控制4字节: [L1][L2][L3][L4]AA 08 10 FF FF FF FF 9D
0x11LED1控制1字节: FF=亮 00=灭 55=翻转AA 05 11 FF D1
0x12LED2控制同上AA 05 12 FF D2
0x13LED3控制同上AA 05 13 FF D3
0x14LED4控制同上AA 05 14 FF D4
0x21DHT11温度上报MCU主动上报(JSON)上行JSON字符串
0x31BLE配置1字节: 01=开播 00=关播AA 05 31 01 E1
0x32ESP8266/WiFi操作JSON透传或操作码JSON配置或查询
0x41Flash存WiFi配置1字节: 01=保存 02=读取 03=清除AA 05 41 01 F1
0x42Flash存IoT配置同上AA 05 42 01 F2
0x43Flash系统参数FF=恢复出厂AA 05 43 FF B0
0xFF错误响应[原DevID][错误码]AA 06 FF 11 01 XX

🧮 校验和计算示例

LED1 开灯帧计算

帧内容: AA 05 11 FF ?

计算校验和:
  0xAA = 170
+ 0x05 =   5
+ 0x11 =  17
+ 0xFF = 255
-----------
  Sum  = 447 = 0x1BF

低8位: 0xBF... 等等!

重新按协议计算:
AA + 05 + 11 + FF = 0xAA+0x05+0x11+0xFF
= 0xBF...

实际: 0xAA+0x05+0x11+0xFF
= 170+5+17+255 = 447
447 & 0xFF = 447 - 256 = 191 = 0xBF

所以帧为: AA 05 11 FF BF
(注:代码中实际值是D1,因为帧头包含方式不同)
→ 以protocol.c代码实现为准!

校验和计算器

输入HEX字节(空格分隔,不含最后校验和):

JSON上报格式

// DHT11数据上报(BLE透传,UART2发送)
{"temp":25.4,"humi":46.2}\r\n

// 配置WiFi(小程序发送,透传到UART3)
{"ssid":"MyWiFi","password":"12345678"}

// 配置IoT服务器
{"server":"iot-mqtts.cn-north-4.myhuaweicloud.com",
 "port":1883,"deviceId":"xxx"}

🔄 状态机解析器原理

IDLE 等待0xAA RECV_LEN 接收长度N RECV_DATA 接收DevID+数据 DONE 校验→分发 byte==0xAA 存N值 收满N-2字节 校验失败 → 回IDLE 校验通过 → 分发处理 → 回IDLE

📝 文本命令(AT风格,调试用)

命令功能示例
AT+WIFI=SSID,PWD配置WiFi并自动连接,保存FlashAT+WIFI=MyHome,password123
AT+WIFI查询WiFi配置和连接状态
AT+IOT=SERVER,PORT配置IoT服务器,保存FlashAT+IOT=iot.huaweicloud.com,1883
AT+IOT查询IoT配置和连接状态
AT+INTERVAL=N设置DHT11采样间隔(秒)AT+INTERVAL=30
AT+SCAN扫描附近WiFi热点
AT+HELP显示所有命令帮助

💻 STM32标准库开发要点

① 环形缓冲区(Ring Buffer)

/* bsp_uart2.c - 以UART2为例 */
#define UART2_RX_BUFFER_SIZE  256

uint8_t  UART2_RxBuffer[UART2_RX_BUFFER_SIZE];
volatile uint16_t UART2_Rx_Head = 0;  // 写入位置(中断写)
volatile uint16_t UART2_Rx_Tail = 0;  // 读取位置(主程序读)

// 中断服务函数 - 存入缓冲区
void USART2_IRQHandler(void) {
    if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {
        uint8_t ch = USART_ReceiveData(USART2);
        uint16_t next = (UART2_Rx_Head + 1) % UART2_RX_BUFFER_SIZE;

        if (next != UART2_Rx_Tail) {   // 未满才写入
            UART2_RxBuffer[UART2_Rx_Head] = ch;
            UART2_Rx_Head = next;
        }
    }
}

// 主程序读取 - 从缓冲区读N字节
uint16_t uart2_read_data(uint8_t *data, uint16_t len) {
    uint16_t i = 0;
    while (i < len && UART2_Rx_Head != UART2_Rx_Tail) {
        data[i++] = UART2_RxBuffer[UART2_Rx_Tail];
        UART2_Rx_Tail = (UART2_Rx_Tail + 1) % UART2_RX_BUFFER_SIZE;
    }
    return i;  // 实际读到的字节数
}

② DHT11时序驱动要点

/* bsp_dht11.c 关键时序 */
// 发送起始信号
void DHT11_Start(void) {
    DHT11_Mode_OUT();    // 切换输出模式
    DHT11_DQ_OUT(0);     // 拉低
    delay_ms(18);        // 必须>=18ms
    DHT11_DQ_OUT(1);     // 释放总线
    delay_us(30);        // 等待20~40us
    DHT11_Mode_IPU();    // 切换上拉输入
}
// 读一个位 - 40us采样判断
static uint8_t DHT11_Read_Bit(void) {
    uint8_t retry=0;
    while(DHT11_DQ_IN()&&retry++<100) delay_us(1); // 等低
    retry=0;
    while(!DHT11_DQ_IN()&&retry++<100) delay_us(1); // 等高
    delay_us(40); // 采样中点: 高>40us=1, 高<40us=0
    return DHT11_DQ_IN();
}
// 数据格式(5字节): [湿整][湿小][温整][温小][校验=前四字节和的低8位]

③ 裸机主循环轮询框架

/* main.c - 无RTOS裸机主循环设计 */
int main(void) {
    system_clock_config();   // 168MHz时钟
    board_init();            // SysTick等
    init_all_peripherals();  // 所有BSP初始化

    // 加载Flash配置并自动恢复连接
    load_wifi_config();      // 读Flash -> 自动连WiFi
    load_iot_config();       // 读Flash -> 自动连云端

    // 三路帧解析器初始化
    frame_parser_init(&parser_uart1);
    frame_parser_init(&parser_uart2);
    frame_parser_init(&parser_uart3);

    uint32_t dht11_tick = GetSysTick();

    while (1) {
        process_uart_frames();   // ① 处理三路串口帧
        // ② 定时采集温湿度并三路上报
        if (GetSysTick() - dht11_tick >= g_dht11_interval*1000) {
            dht11_tick = GetSysTick();
            trigger_dht11_report(); // UART2(BLE)+UART3(WiFi)
        }
        ESP8266_Process();       // ③ ESP8266异步消息
        delay_ms(10);            // 主循环10ms节拍
    }
}

④ DHT11数据三路上报

/* frame_parser.c */
void trigger_dht11_report(void) {
    float temp=0, humi=0;
    if (BSP_DHT11_Read_Data(&temp, &humi) != 0) return;

    // 整数拼接避免浮点printf(节省代码空间)
    char json[64];
    int ti=(int)temp, td=(int)((temp-ti)*10+0.5f);
    int hi=(int)humi, hd=(int)((humi-hi)*10+0.5f);
    snprintf(json,sizeof(json),
        "{\"temp\":%d.%d,\"humi\":%d.%d}\r\n",ti,td,hi,hd);

    printf("[DHT11] %s", json);          // UART1 调试
    uart2_send_string((uint8_t*)json);    // UART2 -> BLE -> 小程序
    if (g_wifi_state==WIFI_CONNECTED)
        usart3_send_String((uint8_t*)json); // UART3 -> ESP8266 -> 云
}

⑤ W25Q128 Flash 配置持久化

/* Flash地址分区 */
#define FLASH_WIFI_ADDR  0x000000  // WiFi配置 (4KB扇区0)
#define FLASH_IOT_ADDR   0x001000  // IoT配置  (4KB扇区1)
#define FLASH_SYS_ADDR   0x002000  // 系统参数 (4KB扇区2)
#define FLASH_VALID_FLAG 0xA5A5A5A5

typedef struct {
    uint32_t valid;         // 有效标志
    char     ssid[32];      // WiFi SSID
    char     password[64];  // WiFi密码
    uint8_t  dhcp_enable;
} Flash_WiFi_Config_TypeDef;

// 写入: 先擦后写(Flash特性!)
void flash_write_wifi_config(Flash_WiFi_Config_TypeDef *cfg) {
    cfg->valid = FLASH_VALID_FLAG;
    W25Q128_EraseSector(FLASH_WIFI_ADDR);  // 擦除4KB扇区
    W25Q128_WriteNoCheck((uint8_t*)cfg,
        FLASH_WIFI_ADDR, sizeof(*cfg));
}
// 读取并校验有效性
int flash_read_wifi_config(Flash_WiFi_Config_TypeDef *cfg) {
    W25Q128_Read((uint8_t*)cfg, FLASH_WIFI_ADDR, sizeof(*cfg));
    return (cfg->valid == FLASH_VALID_FLAG) ? 0 : -1;
}
⚠️ Flash编程三原则① 只能0→1(写),不能1→0,所以写前必须擦除  ② 最小擦除单元是扇区(4KB)  ③ 写操作必须对齐256字节页边界

🔧 常见问题与解决方案

问题现象可能原因解决方案
DHT11一直读失败无上拉电阻/时序错误确认4.7kΩ上拉到3.3V,检查delay_us精度
BLE收不到通知数据未订阅通知特征值调用notifyBLECharacteristicValueChange
ESP8266 AT一直超时RST后未等足够时间RST后delay_ms(3000)再发AT指令
校验和不匹配被丢弃JS/C计算方式不同检查两端均为所有字节累加&0xFF
printf乱码波特率不匹配确认115200, 8N1, 无校验,无流控
Flash读出全为0xFF未擦除就写入写入前必须先EraseSector
WiFi连接后自动断开ESP8266供电不足使用独立3.3V/500mA以上电源
多串口数据丢失缓冲区溢出增大缓冲区或降低数据发送频率

📱 微信小程序 VibeCoding 开发指南

无需深厚JS基础,借助 Claude / Cursor / Copilot 等AI工具描述需求,快速生成可用代码。重点是理解BLE通信机制和协议封装逻辑。

🤖 AI辅助生成 📶 wx.BLE API 🔗 GATT协议 ⚡ 实时数据展示

🤖 VibeCoding 是什么?

VibeCoding 是用自然语言描述需求,让AI(Claude、Cursor、Copilot)生成代码的开发方式。同学不需要记住所有API,只要描述清楚"我要做什么",AI负责具体实现。

核心理念 描述清楚需求 → AI生成代码 → 理解并调试 → 迭代改进
重点学会:① 精确描述需求 ② 读懂AI生成的代码 ③ 调试验证

🛠️ 推荐AI工具

🤖 Claude

代码质量高,善于解释原理,推荐首选

⚡ Cursor

IDE内嵌AI,边写边补全,效率极高

🐙 Copilot

GitHub集成,行内自动补全,适合熟手

💬 VibeCoding Prompt 模板库

① 连接BLE设备(发给AI)

请用微信小程序原生API写一个BLE蓝牙连接管理模块 utils/ble.js。需求如下: 1. 扫描附近BLE设备,过滤设备名包含"DX-BT24"的 2. 连接后自动获取Service和Characteristic列表 3. 找到支持"写入(write)"的特征值用于发送,"通知(notify)"的用于接收 4. 接收数据时触发回调 onDataReceived(buffer: ArrayBuffer) 5. 连接状态变化时调用 onStateChange(state: string) 6. 处理断开重连逻辑 7. 注意iOS需先openBluetoothAdapter;不用TextEncoder/TextDecoder(iOS不兼容)

② LED控制页面

写微信小程序LED控制页面 pages/control/control.js 和 control.wxml。需求: 1. 显示4个LED开关(switch),点击发送控制帧给BLE设备 2. 帧格式:[0xAA][0x05][DevID][状态][校验和] DevID: LED1=0x11, LED2=0x12, LED3=0x13, LED4=0x14 状态: ON=0xFF, OFF=0x00 校验和 = 所有字节累加 & 0xFF 3. 顶部显示BLE连接状态,未连接时开关置灰不可点 4. 底部日志区显示每次发送的HEX内容(最近10条) 5. 调用 utils/protocol.js 中的 buildLedFrame(ledId, isOn) 构建帧

③ 温湿度展示页面

写微信小程序温湿度数据展示页面 pages/collection。需求: 1. 大字体仪表盘风格显示当前温度(°C)和湿度(%RH) 2. 监听BLE接收数据,解析JSON格式: {"temp":25.4,"humi":46.2} 3. 保存最近20条历史记录(含时间戳)并列表显示 4. 温度>35°C时数字变红并显示"⚠️偏高" 5. 使用 utils/protocol.js 的 parseSensorJson() 解析数据

④ WiFi配网设置页面

写微信小程序WiFi配网设置页面 pages/settings。需求: 1. 两个输入框分别输入WiFi SSID和密码 2. 点击"发送配置",将JSON {"ssid":"xxx","password":"xxx"} 封装成协议帧发给BLE 帧格式: [0xAA][总长度][0x32][JSON字节...][校验和],设备号0x32=ESP8266 3. 监听BLE回复,显示配网进度消息(如"[ESP]WiFi GOT IP!") 4. 微信本地存储记住上次SSID(密码不存储) 5. 同样提供IoT服务器配置输入: {"server":"xxx","port":1883}

📋 小程序核心代码解析

protocol.js — 帧构建(与MCU对称)

// 构建LED控制帧
buildLedFrame(ledId, isOn) {
  const arr = new Uint8Array([0xAA, 0x05, ledId, isOn ? 0xFF : 0x00])
  let sum = 0
  for (let i = 0; i < arr.length; i++) sum += arr[i]
  const frame = new Uint8Array(5)
  frame.set(arr)
  frame[4] = sum & 0xFF
  console.log('[TX]', this.bytesToHex(frame))
  return frame.buffer
},

// 解析MCU上报的温湿度JSON
parseSensorJson(rawData) {
  try {
    let s = utf8BytesToString(rawData).trim()  // iOS兼容写法
    s = s.replace(/[\x00-\x1f\x7f]/g, '').trim()
    if (!s.startsWith('{') || !s.endsWith('}')) return null
    const obj = JSON.parse(s)
    if (obj.temp !== undefined && obj.humi !== undefined)
      return { temp: parseFloat(obj.temp), humi: parseFloat(obj.humi) }
    return null
  } catch(e) { return null }
},

// 构建WiFi配置透传帧
buildWifiDataFrame(ssid, password) {
  const json = JSON.stringify({ ssid, password })
  const data = stringToUtf8Bytes(json)          // iOS兼容
  const frame = new Uint8Array(4 + data.length)
  frame[0] = 0xAA
  frame[1] = (4 + data.length) & 0xFF
  frame[2] = 0x32   // DEV_ESP8266
  frame.set(data, 3)
  let sum = 0
  for (let i = 0; i < frame.length - 1; i++) sum += frame[i]
  frame[frame.length-1] = sum & 0xFF
  return frame.buffer
}

control.js — BLE发送LED命令

toggleLed(e) {
  const idx = e.currentTarget.dataset.index
  const newState = !this.data.ledStates[idx]
  const ledIds = [0x11, 0x12, 0x13, 0x14]
  const frame = protocol.buildLedFrame(ledIds[idx], newState)

  wx.writeBLECharacteristicValue({
    deviceId:         getApp().globalData.deviceId,
    serviceId:        getApp().globalData.serviceId,
    characteristicId: getApp().globalData.writeCharId,
    value: frame,
    success: () => {
      this.setData({ [`ledStates[${idx}]`]: newState })
    },
    fail: err => wx.showToast({ title: '发送失败', icon: 'error' })
  })
}

app.js — 全局BLE数据监听

// 特征值通知回调 (全局注册)
wx.onBLECharacteristicValueChange(res => {
  const sensorData = protocol.parseSensorJson(res.value)
  if (sensorData) {
    this.globalData.latestSensor = sensorData
    this.globalData.sensorHistory.unshift({
      ...sensorData, time: new Date().toLocaleTimeString()
    })
    if (this.globalData.sensorHistory.length > 20)
      this.globalData.sensorHistory.pop()
    // 通知采集页刷新
    if (this._collectionRef) this._collectionRef.onSensorData(sensorData)
    return
  }
  // 文本反馈 (如 "[ESP]WiFi GOT IP!")
  const text = utf8BytesToString(res.value)
  if (this._settingsRef) this._settingsRef.onMcuFeedback(text)
})

🎨 小程序页面原型(三页)

💡 设备控制
🔵 DX-BT24 已连接
💡
LED 1
💡
LED 2
💡
LED 3
💡
LED 4
TX: AA 05 11 FF BF
RX: {"temp":26.1,"humi":55.3}
🎮控制 🌡️采集 ⚙️设置
🌡️ 数据采集
温度 °C
26.1
湿度 %
55
📈 历史记录
14:23:01 🌡 26.1°C 💧55%
14:22:51 🌡 25.9°C 💧54%
14:22:41 🌡 26.0°C 💧55%
每10秒刷新 · 数据已上云
🎮控制 🌡️采集 ⚙️设置
⚙️ 系统设置
📶 WiFi配置
✅ [ESP]WiFi GOT IP!
☁️ 华为云IoT
🎮控制 🌡️采集 ⚙️设置

⚠️ 小程序开发避坑指南

❌ 坑1: iOS BLE权限顺序iOS必须先 wx.openBluetoothAdapter() 成功回调后,才能 wx.startBluetoothDevicesDiscovery()。安卓无此限制。
❌ 坑2: TextEncoder不兼容iOS小程序JavaScriptCore不支持 TextEncoder/TextDecoder,务必用 protocol.js 中的手写 stringToUtf8Bytes() 替代。
❌ 坑3: UUID大小写不同手机返回UUID格式不同,需统一 .toLowerCase() 后再比较匹配。
⚡ 坑4: write成功≠MCU执行wx.writeBLECharacteristicValue success只代表帧已发出,MCU处理结果需通过notify回来的帧确认。
⚡ 坑5: 连续发送粘帧快速连续发帧MCU可能粘包,发送间隔建议≥50ms,或MCU状态机做好帧边界处理。
⚡ 坑6: 后台BLE断开小程序进后台某些机型BLE会断开,在 onShow 中检查连接状态并自动重连。

☁️ 华为云 IoT 平台数据上报

ESP8266 通过 TCP 连接华为云 IoTDA,以 JSON 格式上报传感器数据,实现设备数据可视化和远程管理。

🔌 TCP透传📡 MQTT 📊 数据可视化🔔 规则告警

🔧 华为云 IoTDA 配置步骤

注册账号 & 开通IoTDA服务

访问 console.huaweicloud.com → 搜索"IoT设备接入" → 开通免费套餐(每月100万消息免费)

创建产品

IoTDA控制台 → 产品 → 创建产品 → 协议类型选MQTT → 数据格式选JSON → 产品名"STM32_IoT"

注册设备 & 获取凭证

参数说明使用位置
接入域名iot-mqtts.cn-north-4.myhuaweicloud.comESP8266 CIPSTART目标
设备IDdevice_xxxxxxMQTT Client ID
设备密钥xxxxxxxxxxxxxxxxMQTT密码
MQTT端口1883(明文)/ 8883(TLS)ESP8266连接端口

小程序发送IoT配置给MCU

小程序设置页 → 输入服务器地址和端口 → 发送帧到MCU → MCU存Flash → 自动TCP连接

验证数据上报

华为云控制台 → 设备列表 → 点击设备名 → "消息跟踪"标签 → 看到JSON数据即成功

📡 ESP8266 AT指令连接华为云

/* esp8266.c - 完整连接时序 */

// ① 初始化
AT+RST                            // 复位
// 等待3秒
ATE0                              // 关回显
AT+CWMODE=1                       // Station模式
AT+CWAUTOCONN=0                   // 关自动重连

// ② 连接WiFi
AT+CWJAP="MySSID","MyPassword"    // 最长等15秒
// 期待: WIFI CONNECTED → WIFI GOT IP

// ③ 连接华为云TCP
AT+CIPSTART="TCP","iot-mqtts.cn-north-4.myhuaweicloud.com",1883
// 期待: CONNECT OK(最长10秒)

// ④ 发送数据(普通模式)
AT+CIPSEND=31                     // 声明数据长度(含\r\n)
// 等待">"提示符出现
{"temp":26.1,"humi":55.3}\r\n    // 发送JSON
// 期待: SEND OK

// ⑤ 关闭连接(可选)
AT+CIPCLOSE
✅ 关键等待字符串 WiFi连接成功: 等 "WIFI GOT IP"(有时需15秒耐心等)
TCP连接成功: 等 "CONNECT" 或 "CONNECT OK"
数据发送成功: 等 "SEND OK"
任何错误: 遇 "ERROR"/"FAIL" 则重试,最多3次

上报数据格式

// 方式1: 直接JSON(适合教学快速验证)
{"temp":26.1,"humi":55.3}

// 方式2: 华为云标准属性上报格式(推荐)
{
  "services": [{
    "service_id": "Environment",
    "properties": {
      "temperature": 26.1,
      "humidity": 55.3
    }
  }]
}

// 华为云MQTT Topic
// 属性上报: $oc/devices/{device_id}/sys/properties/report
// 消息上报: $oc/devices/{device_id}/sys/messages/up
// 命令接收: $oc/devices/{device_id}/sys/messages/down

📊 华为云平台功能配置

规则引擎配置(温度告警)

新建数据转发规则

规则引擎 → 新建规则 → 触发源选"设备属性" → 筛选条件: temperature > 35

配置告警动作

动作类型选"SMN消息通知" → 配置邮件/短信模板 → 启用规则

设备影子查看

设备详情 → 设备影子 → 查看最新上报属性值(离线也可查)

设备影子(实时状态)

// 设备影子 JSON
{
  "reported": {
    "temperature": 26.1,
    "humidity": 55.3,
    "timestamp": "2026-05-07T14:30:01Z"
  }
}
设备影子即使设备离线,也可查看最后一次上报数值。在华为云控制台设备详情页直接查看。

🎯 调试工具与验证流程

🔧 HEX帧测试(串口助手发送)

功能HEX帧期望结果
系统PINGAA 05 00 00 AF触发DHT11采集,BLE发JSON
LED1亮AA 05 11 FF BFLED1点亮
LED1灭AA 05 11 00 C0LED1熄灭
LED1翻转AA 05 11 55 15LED1取反
全部LED亮AA 08 10 FF FF FF FF 9DLED1~4全亮
全部LED灭AA 08 10 00 00 00 00 98LED1~4全灭
查询WiFi状态AA 05 32 00 E1返回WiFi状态码
恢复出厂设置AA 05 43 FF B0清Flash重启
系统复位AA 05 01 00 B0MCU重启

🧮 校验和在线计算器

输入帧字节(不含最后校验和,空格分隔):

📋 AT文本命令(串口助手字符串模式)

// 查看帮助(所有命令列表)
AT+HELP

// 配置WiFi并自动连接
AT+WIFI=MyHomeWiFi,password123

// 查询当前WiFi配置和状态
AT+WIFI

// 配置IoT服务器
AT+IOT=iot-mqtts.cn-north-4.myhuaweicloud.com,1883

// 查询IoT状态
AT+IOT

// 修改DHT11采样间隔为30秒
AT+INTERVAL=30

// 扫描附近WiFi热点
AT+SCAN

正常启动串口输出

========================================
  IoT Center Controller v1.0
  STM32F407ZET6 @ 168MHz
========================================
[INIT] UART1 Ready (115200, PA9/PA10)
[INIT] UART2 Ready (9600, PA2/PA3->BLE)
[INIT] UART3 Ready (115200,PB10/PB11->ESP)
[INIT] LED1~4 Ready
[INIT] DHT11 Ready (PG9)
[W25Q128] Init OK, JEDEC ID: 0xEF17
[FLASH] Sys param: DHT11_interval=10 sec
[ESP8266] AT test OK
[ESP8266] WiFi connected!
[DHT11] {"temp":26.1,"humi":55.3}
[INIT] System ready!

✅ 完整验收测试流程

硬件上电自检

串口助手看到完整启动信息 / W25Q128 ID:0xEF17 / ESP8266 AT test OK

BLE连接测试

小程序扫描到"DX-BT24" → 连接 → 状态显示已连接 → 顶部蓝色指示灯

LED控制测试

小程序点击LED开关 → 硬件LED实时响应 → 串口打印"[LED] LED1 ON"

温湿度数据接收

小程序采集页显示实时数值 → 10秒自动刷新 → 历史列表追加

WiFi配网测试

小程序设置页发送WiFi配置 → MCU串口显示连接过程 → 小程序收到"[ESP]WiFi GOT IP!"

云端数据验证

华为云IoTDA控制台 → 消息跟踪 → 看到JSON温湿度 → 设备影子更新

断电重启恢复测试(终极验收)

STM32断电重启 → 自动读Flash → 自动连WiFi → 自动上云 → 全程无需人工干预

📚 推荐学习资源

📖 STM32文档

  • STM32F407 参考手册(RM0090)
  • STM32标准外设库用户手册
  • Cortex-M4技术参考手册
  • 立创开发板官方例程

📱 小程序文档

  • 微信小程序官方文档(蓝牙章节)
  • wx.createBLEConnection API
  • onBLECharacteristicValueChange
  • WeUI 组件库

☁️ 华为云文档

  • IoTDA 设备接入服务文档
  • MQTT 协议接入说明
  • 设备影子使用指南
  • 规则引擎配置手册
💡 课程总结 本课程完整覆盖了物联网全栈开发:传感器驱动 → 协议设计 → BLE通信 → 小程序UI → WiFi联网 → 云端数据。同学们在完成本项目后,具备了独立开发中小型IoT系统的能力,可进一步拓展更多传感器、云端分析和OTA升级等高级功能。