最后代码修改注意事项
175.10最后代码修改注意事项
/* ==================== Gizwits/gizwits_product.c ==================== */
extern UART_HandleTypeDef huart3; /* 引用 usart.c 中定义的 USART3 句柄;视频中的小笔误最终改成了 huart3。 */
void timerInit(void) /* 课程已有的定时器启动函数。 */
{ /* 函数体开始。 */
HAL_TIM_Base_Start_IT(&htim2); /* 以中断模式启动 TIM2,继续为按键和机智云协议提供节拍。 */
HAL_TIM_Base_Start_IT(&htim4); /* 以中断模式启动 TIM4,让 ZigBee 心跳超时计数真正运行。 */
} /* 定时器启动函数结束。 */
void uartInit(void) /* 课程已有的串口接收启动函数。 */
{ /* 函数体开始。 */
HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);//开启下一次接收中断 /* 先挂起 USART2 的单字节中断接收,供 ESP8266/机智云协议使用。 */
HAL_UART_Receive_IT(&huart3, uart3_recv_buff, 5); /* 首次挂起 USART3 的 5 字节中断接收;只开 NVIC 还不会替代这一步。 */
} /* 串口接收启动函数结束。 */
/* HAL_UART_RxCpltCallback() 的 USART3 分支处理完一包数据后的原语句。 */
HAL_UART_Receive_IT(&huart3, uart3_recv_buff, 5); /* HAL 的定长中断接收完成一次即结束,因此这里重新挂起下一包 5 字节接收。 */
/* userHandle() 中本节为覆盖旧字符而修改的两条显示语句。 */
sprintf(OLED_BUFF,"H:%2d%%T:%2dC ",currentDataPoint.valuetemp1,currentDataPoint.valuehumi1); /* 末尾增加空格,用它擦除上一次较长内容遗留的字符。 */
OLED_ShowString(35,2,OLED_BUFF,16); /* 从 OLED 的 x=35、第 2 个 16 像素文本行显示缓冲区内容。 */
/* 工程已有的 printf 重定向代码,本节用它查看串口日志。 */
PUTCHAR_PROTOTYPE /* 根据编译器宏展开为 __io_putchar() 或 fputc()。 */
{ /* 单字符输出函数开始。 */
/* Place your implementation of fputc here */
/* e.g. write a character to the USART1 and Loop until the end of transmission */
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF); /* 把 printf 的一个字符经 USART1 阻塞发送。 */
return ch; /* 返回已经发送的字符。 */
} /* 单字符输出函数结束。 */
/* ==================== Src/main.c ==================== */
timerInit(); /* 生成的外设初始化完成后,尽早启动 TIM2 和 TIM4。 */
uartInit(); /* 尽早挂起 USART2、USART3 的第一次中断接收。 */
userInit(); /* 再执行传感器、OLED 等耗时较多的用户初始化。 */
gizwitsInit(); /* 初始化机智云协议相关状态。 */
keyInit(); /* 初始化机智云按键状态机。 */
void key2LongPress(void) /* KEY2 长按回调,课程用它进入 AirLink 配网。 */
{ /* 长按回调开始。 */
//AirLink mode
GIZWITS_LOG("KEY2 PRESS LONG ,AirLink mode\n"); /* 通过日志串口打印已经进入 AirLink 模式。 */
#if !MODULE_TYPE /* 仅在当前模块类型配置允许时编译下面的 Wi-Fi 配网调用。 */
gizwitsSetMode(WIFI_AIRLINK_MODE); /* 请求 ESP8266 进入 AirLink 配网模式。 */
#endif /* 条件编译结束。 */
} /* KEY2 长按回调结束。 */
/* ==================== Inc/main.h ==================== */
#define KEY2_Pin GPIO_PIN_8 /* 工程把逻辑 KEY2 配置在 GPIO 第 8 脚,即 PA8。 */
#define KEY2_GPIO_Port GPIOA /* KEY2 所属端口为 GPIOA。 */
/* ==================== Src/tim.c、Src/usart.c ==================== */
HAL_NVIC_SetPriority(TIM4_IRQn, 0, 0); /* 设置 TIM4 全局中断的抢占优先级和子优先级。 */
HAL_NVIC_EnableIRQ(TIM4_IRQn); /* 在 NVIC 中放行 TIM4 全局中断。 */
HAL_NVIC_SetPriority(USART3_IRQn, 0, 0); /* 设置 USART3 全局中断优先级。 */
HAL_NVIC_EnableIRQ(USART3_IRQn); /* 在 NVIC 中放行 USART3 全局中断。 */
/* ==================== Src/stm32f1xx_it.c ==================== */
void TIM4_IRQHandler(void) /* TIM4 的中断向量入口。 */
{ /* TIM4 中断服务函数开始。 */
HAL_TIM_IRQHandler(&htim4); /* 交给 HAL 清标志并进一步调用定时器周期回调。 */
} /* TIM4 中断服务函数结束。 */
void USART3_IRQHandler(void) /* USART3 的中断向量入口。 */
{ /* USART3 中断服务函数开始。 */
HAL_UART_IRQHandler(&huart3); /* 交给 HAL 处理接收状态;满 5 字节后会进入接收完成回调。 */
} /* USART3 中断服务函数结束。 */
源码范围说明:顶部只摘录 175 视频实际修改、检查或直接用于调试的工程语句,并逐行加注释。
HAL_UART_Receive_IT()、HAL_TIM_Base_Start_IT()的 HAL 库内部实现没有在本课展开,因此不强行补入;CubeMX 自动生成文件也只保留与本次故障链直接相关的 NVIC 和中断入口。各片段来自不同函数、不同文件,不能把整段直接粘进同一个函数。OLED 格式化语句中H接valuetemp1、T接valuehumi1与成员命名语义疑似相反,本课只增加末尾空格,并未修改这项旧逻辑,故顶部忠实保留最终工程原句。
一、最后代码修改及注意事项
这节不是继续增加功能,而是把 174 编译通过但上板失败的工程调通。烧录后的主要现象是 OLED 显示 Zig:ERR、手机 App 无法正常控制窗帘或灯、远端温湿度没有更新。多个功能同时依赖 STM32 的 USART3 与 51 端通信,因此应先检查公共通信链路,而不是分别修改每个业务功能。
1.1 问题现象分析
原笔记中的“b 处显示 error”“b 通信”是转写错误。屏幕实际状态是 Zig:ERR,表示 175 以前写好的 zig_count 没有被有效心跳持续清零。这个现象可能来自多层原因:
- USART3 句柄或接线错误,STM32 根本没有收到 51 发来的 5 字节帧;
- USART3 全局中断未使能,或没有调用
HAL_UART_Receive_IT()挂起第一次接收; - 收满一包后没有再次调用接收函数,只能成功接收一次;
- TIM4 未以中断模式启动,心跳超时计数逻辑没有按设计运行;
- ZigBee 模块参数、供电或杜邦线接触不良。
因此 Zig:ERR 只是“规定时间内没收到有效心跳”的结果,不等于已经证明 ZigBee 模块本身损坏。课程最后通过补齐软件链路、调整初始化顺序并检查硬件连接恢复了运行。
1.2 代码修改内容
1.2.1 小问题修改
视频提到先发现了一个串口句柄的笔误,但口述没有给出可可靠还原的完整错误文本。配套最终工程可以确认正确声明是:
extern UART_HandleTypeDef huart3;
它与后续 HAL_UART_Receive_IT(&huart3, ...)、USART3_IRQHandler() 和 PB10/PB11 接线相互对应。这里不把原笔记乱码“一月二题”“一没写写的”继续当作源码,也不臆造视频修改前的错误行。
1.2.2 大问题分析
一次 USART3 中断接收能进入业务回调,需要整条调用链成立:
CubeMX 使能 USART3 global interrupt
→ 生成 USART3_IRQn 的 NVIC 配置和 USART3_IRQHandler()
→ uartInit() 调用 HAL_UART_Receive_IT(..., 5) 挂起第一次接收
→ 收满 5 字节后 HAL 进入 HAL_UART_RxCpltCallback()
→ 业务代码校验、分流
→ 再次调用 HAL_UART_Receive_IT(..., 5) 挂起下一包
“勾选全局中断”和“启动一次异步接收”是两个不同条件。前者让 CPU 能响应 USART3 的中断请求,后者告诉 HAL 接收缓冲区地址、长度并建立本次接收状态;只做其中一个都不能完成这里的 5 字节接收。
HAL_UART_Receive_IT(&huart3, uart3_recv_buff, 5) 是一次性的定长接收。只有累计收到 5 字节才触发完成回调;回调执行后必须再次调用它,才能等待下一包。课程代码没有检查这个函数的返回值,若它返回 HAL_BUSY 或 HAL_ERROR,程序不会留下明确故障信息,这也是调试时应注意的限制。
TIM4 链路同样需要同时满足:
CubeMX 使能 TIM4 global interrupt
→ 生成 TIM4_IRQn 的 NVIC 配置和 TIM4_IRQHandler()
→ HAL_TIM_Base_Start_IT(&htim4) 启动定时器及更新中断
→ HAL_TIM_IRQHandler(&htim4)
→ HAL_TIM_PeriodElapsedCallback(&htim4)
→ zig_count++
仅写回调函数不会让定时器自动开始计数;仅调用 HAL_TIM_Base_Start_IT() 而没有 NVIC 中断入口也到不了用户回调。
课程最终把 timerInit(); uartInit(); 放到 CubeMX 外设初始化和 MX_NVIC_Init() 之后、userInit() 之前。原因是 51 端上电后会主动发送数据,若 STM32 先执行耗时的传感器和显示初始化,早期字节可能在接收尚未挂起时到达,形成盲区,甚至留下溢出状态。视频把旧位置失败猜成“HAL 库 bug”,但没有证据证明 HAL 自身存在缺陷;从最终修改看,更准确的结论是接收启动时机过晚,提前挂起接收缩短了丢失首包的窗口。
1.3 自己做时的注意事项
- 屏幕从较长内容切换到较短内容时,OLED 驱动不会自动擦除右侧旧像素。课程在格式字符串末尾增加一个空格,用新写入的空白字符覆盖残留的
C,解决类似21 CC的显示。 - 该修改只处理残留字符,不会修复数值、标签或传感器读取错误。最终源码的
H/T与valuetemp1/valuehumi1对应关系还应结合数据点定义单独核对。 - 杜邦线松动、面包板接触不良、未共地以及 TX/RX 接反,都会造成与软件故障相似的现象。先用万用表或连续性测试确认连接,再追业务代码。
- 可拆卸原型便于学习,但长期运行更适合焊接或使用可靠连接器,并做好供电去耦。
1.4 ZigBee调试
排查时可先拔下两端 ZigBee 模块,用有线串口直接连接 STM32 与 51:
| STM32 | 方向 | 51 单片机 | 作用 |
|---|---|---|---|
| PB10 / USART3_TX | → | P3.0 / RXD | STM32 向 51 发送控制帧 |
| PB11 / USART3_RX | ← | P3.1 / TXD | 51 向 STM32 回传 ACK、温湿度和心跳 |
| GND | ↔ | GND | 建立共同电位基准 |
TX 必须交叉接 RX,并且第三根 GND 不能省。若两块板分别供电,不要再用第四根线把它们的 VCC 直接并在一起;连接信号线前还要确认两端逻辑电平兼容,不确定时使用电平转换。这个直连测试只验证 MCU 串口、协议和业务代码,直连正常而装回模块失败,才把范围缩小到 ZigBee 配置、供电或无线链路。
1.5 机智云APP使用
1.5.1 信号检测问题
本工程通过 ESP8266 接入 Wi-Fi。ESP8266 工作在 2.4 GHz 频段,所以配网时手机应连接可用的 2.4 GHz 网络,并确认路由器没有启用会阻止设备接入的隔离或认证方式。App 暂时发现不了设备,只能说明配网或联网链路尚未完成,不能据此判断手机“没有检测到模块无线信号”。
1.5.2 配对问题
原笔记的“一二引脚”“ER 按键”“AR link”均是转写错误。配套 STM32 开发板原理图显示,板载物理 KEY2 接在 PE2,而当前工程却把逻辑 KEY2 配置为 PA8。课程临时用杜邦线把 PE2 接到 PA8,于是按下板载 KEY2 时,低电平也能送到程序实际读取的 PA8。
长按 KEY2 约 2~3 秒后,机智云按键状态机调用 key2LongPress(),继而执行 gizwitsSetMode(WIFI_AIRLINK_MODE),这才是 AirLink 模式。杜邦线是对“现有硬件按键位置与现有工程引脚配置不一致”的补偿,不是 C8T6 外设本身要求这样连接。更正式的处理应在硬件和 CubeMX/代码之间统一按键引脚。
1.5.3 板子选择问题
视频建议有能力的学习者改用 STM32F103C8T6 最小系统板,并提醒不要买成 C6T6。与本项目相关的关键差异是:
| 型号 | 密度/典型 Flash | 本课相关定时器 | USART | 对本项目的影响 |
|---|---|---|---|---|
| STM32F103C6T6 | 低密度 / 32 KB | TIM1、TIM2、TIM3;无 TIM4 | USART1、USART2;无 USART3 | 不能原样使用当前 USART3 与 TIM4 方案 |
| STM32F103C8T6 | 中密度 / 64 KB | TIM1、TIM2、TIM3、TIM4 | USART1、USART2、USART3 | 具备本课使用的 USART3 与 TIM4 |
原笔记称 C8T6 有“串口4”不准确:C8T6 有 USART1~USART3,没有 UART4。换成 C8T6 也不是只换芯片名称,还要重新核对封装引脚、外设复用、下载接口、供电和所有外接模块连线。视频口述的“z1t6”应为课程所用开发板上的 ZET6;而配套工程 .ioc 当前选择的是 STM32F103C8Tx,硬件与工程目标型号本身也应在复现时再次统一。
1.6 窗口调试
这里的“窗口”实际指电脑上的串口调试窗口。最终工程把 printf/GIZWITS_LOG 重定向到 USART1,配置为 115200 bit/s、8 数据位、无校验、1 停止位。配套开发板原理图又把板载 CH340C 接到 USART1,因此可在电脑串口终端选择对应端口和 115200 8-N-1,复位开发板后查看启动与协议日志。
115200 是波特率,不是“复位键”。用于 ESP8266/机智云数据传输的是 USART2;用于观察日志的是 USART1,两者不要混淆。日志能帮助判断程序运行到哪一步、是否进入 AirLink,但不能单独证明 USART3 到 51 的物理链路正确。
1.7 配对问题
推荐按以下顺序重新配对:
- 手机连接 2.4 GHz Wi-Fi;
- 长按映射到 PA8 的 KEY2,串口日志确认进入 AirLink;
- 在 App 中开始添加设备并输入正确网络信息;
- 若模块长期卡在旧状态,切断开发板外部电源、USB/ST-Link 以及其他可能的反向供电,让 ESP8266 真正掉电,再重新上电配网。
“全断电再上电”用于清除模块当前运行状态,但不保证一定连接成功。若仍失败,还应检查路由器频段、密码、模块串口通信、复位/使能脚、供电跌落以及机智云产品配置是否匹配。
1.8 供电问题
原笔记“电脑 USB 只有 500 mA、必须换手机充电器、ESP8266 必须接 5 V 不能接 3.3 V”不能照做。应区分芯片/裸模块的 3.3 V 电源脚与带稳压器开发板的 5 V 输入脚:
- ESP8266EX 芯片工作电压为 2.5~3.6 V,常用模块建议使用稳定的 3.3 V 电源;裸 ESP-01/ESP-01S 或标有
3V3/VCC的电源脚不能直接接 5 V。 - 只有明确带板载 3.3 V 稳压器、并标有
5V或VIN输入的载板,才可按该载板说明把 5 V 接到其输入端;5 V 逻辑电平也不能直接灌入 ESP8266 GPIO。 - 配套 STM32 开发板原理图明确把 ESP8266 接口 J2 的电源脚接到
3V3,不是 5 V。 - 电源需要在 Wi-Fi 发射电流峰值出现时仍保持稳定。Espressif 的入门资料建议供电能力至少 500 mA,但 USB 端口、充电器标称电流不是唯一判断依据;线缆压降、板上稳压器能力、接触电阻和模块附近去耦同样重要。
因此本项目应先测量模块 3.3 V 引脚在联网瞬间是否明显跌落,再决定更换合适的 3.3 V 稳压电源。手机充电器本身输出通常是 5 V,不能因为它“电流更大”就越过稳压环节直接接裸模块。
参考资料
- 本节最终工程的 gizwits_product.c、main.c、main.h、tim.c、usart.c、stm32f1xx_it.c 与 STM32F103C8x.ioc:核对串口/定时器启动、重新挂起接收、初始化顺序、KEY2 映射和生成的中断链路。
- STM32 开发板原理图 与 51 开发板原理图:核对 PE2 板载 KEY2、PA8 工程映射、USART1/CH340C、ESP8266 的 3V3 接口,以及 PB10/PB11 到 P3.0/P3.1 的直连关系。
- ST 官方 STM32F103x4/x6 低密度数据手册 与 STM32F103x8/xB 中密度数据手册:核对 C6T6、C8T6 的存储容量、USART 和 TIM4 资源差异。
- Espressif 官方 ESP8266EX 数据手册、ESP8266 硬件入门说明 与 ESP8266 技术资源/FAQ:核对 2.4 GHz、2.5~3.6 V 工作范围、3.3 V 推荐供电以及电源电流能力要求。