STM32CubeIDE与CH340驱动的温湿度系统串口通信开发指南

发布时间:2026/9/12 0:13:08
STM32CubeIDE与CH340驱动的温湿度系统串口通信开发指南
简介面向毕业设计与嵌入式物联网开发的完整工程包作者基于STM32CubeIDE集成开发环境配合CH340串口芯片构建了智能农业大棚温湿度监测系统。工程围绕STM32主控实现了对DHT系列传感器数据的采集、解析并经CH340完成USB与PC间串口通信为种植环境实时监测提供了一套可复用的软硬件方案。压缩包共179个文件约6.07MB结构清晰。除核心C源码与H头文件外还包含STM32CubeMX生成的.ioc配置、工程文件.project/.cproject、编译中间文件.o/.d、可执行固件.bin/.elf以及项目说明文档.md便于读者直接打开工程、查看配置或烧录验证。目前已有144人浏览学习。凭借完整的源码和项目说明使用者可深入理解STM32的GPIO、ADC、UART等外设配置掌握传感器驱动编写与数据上传逻辑尤其适合作为毕业设计参考或智能农业入门实践具备较强借鉴意义。1. 拿到温湿度系统源码最先卡住的往往不是代码而是环境大多数人拿到这类“智能农业大棚温湿度系统”压缩包后第一反应是打开源码研究采集算法结果一上午耗在 STM32CubeIDE 建不了工程、CH340 识别不出 COM 口、串口助手收不到数据。这些环节跟大棚、跟温湿度没有任何关系却决定了这套系统能不能在你自己的电脑上跑起来。把标题拆开看实际上是三条链路STM32CubeIDE 负责编译、烧录和调试CH340 负责打通电脑与单片机之间的 USB 转串口通道而温湿度传感系统是典型的物联网端侧应用——传感器采集环境数据单片机处理后通过 UART 上送。任何一环断了源码写得再好也看不到现象。这篇文章适合两类人刚开始用 HAL 库做小系统的开发者以及有几年经验但第一次拿到 CubeIDE 工程、想快速迁移到自己板子上的工程师。下面按“环境→数据链路→排错→文档”的顺序讲每步都给你可以直接抄的命令、代码和参数表。2. STM32CubeIDE 与 CH340先把最容易绊倒人的工具链铺平2.1 STM32CubeIDE 安装与工程管理为什么这个环境适合复现别人的工程STM32CubeIDE 基于 Eclipse GCC官方免费这也是越来越多源码包默认用它组织工程的原因。相比 Keil它对新手更友好的一点是.ioc文件把引脚、时钟、外设配置固化在工程里拿到源码后不需要手动对着手册配寄存器CubeMX的图形界面会告诉你哪个引脚是干什么的。Keil 工程经常出现“设备头文件路径不对、编译报错几百条”CubeIDE 在包管理完整的情况下基本是打开即编译。先说安装相关有三个高频问题值得提前处理2.1.1 离线安装库、中文界面与自动补全配置STM32CubeIDE 装好后第一次创建或打开工程时往往卡在“下载固件包”。这是因为 IDE 需要从 ST 官网拉取对应芯片的固件库网络不理想时进度条半天不动。常见做法是提前下载好固件包放到本地仓库目录后离线安装# Linux 下固件包默认位置 ~/.stm32cubeide/plugin/com.st.stm32cube.ide.mcu.externaltools.*/tools/repository # Windows 下一般在 C:\Users\用户名\STM32Cube\Repository把手动下载的固件 zip 解压到上述目录后打开 IDE 的Help Manage Embedded Software Packages能看到对应版本已变为绿色勾选状态后续创建工程不再需要联网拉取。中文界面不是必须的但如果确实需要汉化走 Eclipse 的语言包机制Help Install New Software添加中文语言包站点装完重启即可。实际开发中更值得花时间的是自动补全默认补全触发字符不包含-和.导致结构体成员补全不出来。在Window Preferences C/C Editor Content Assist里把自动触发字符补上.-输入sensor_data.后就会弹提示这个配置对阅读源码效率的提升非常明显。2.1.2 打开已有工程并确认芯片型号拿到源码包不要直接双击.project就完事先看工程目录里的xxx.ioc文件名以及Drivers/CMSIS/Device/ST下的芯片系列确定目标 MCU。以最常见的 STM32F103C8T6 为例打开方式是File Open Projects from File System选择源码目录后 IDE 会自动识别.project文件。打开后第一步不是编译而是进Device Configuration Tool双击.ioc确认两个地方芯片型号是否一致以及调试口是否被禁用。很多工程用的是 SWD 下载而.ioc里默认的PA13/PA14如果被复用为 GPIO烧录器将无法连接目标板表现为 Debug 报 “No target connected”。提示拿到别人的工程先看一眼Project Properties C/C Build Settings MCU里的芯片型号。型号不一致时直接在.ioc里切换芯片CubeIDE 会尝试把旧引脚映射到新芯片但不保证完全映射正确需人工核对。2.2 CH340 驱动串口链路里 80% 的故障都发生在这里2.2.1 驱动安装失败的三种表现与处理CH340 这块 USB 转串口芯片本身很成熟但“驱动装不上”依然是排查耗时最长的环节。常见的表现有三种。第一种设备管理器里出现带感叹号的“USB Serial”设备双击提示“设备无法启动”。这通常不是驱动坏了而是系统中存在多个版本的 CH340 驱动冲突。处理办法是右键设备选择“卸载设备”在弹出的对话框里勾选“删除此设备的驱动程序软件”然后重新插拔 USB 线让系统重新枚举。第二种驱动安装时提示“预安装成功”但插上开发板后设备管理器没有任何变化不出现 COM 口。所谓“预安装成功”只是把驱动文件复制进了系统驱动库真正的设备匹配发生在硬件插上的那一刻。此时打开设备管理器查看“通用串行总线控制器”如果出现“未知 USB 设备设备描述符请求失败”大概率是 USB 线质量问题或 CH340 芯片供电异常与驱动无关。换一根带屏蔽层的 USB 线或者换一个后置 USB 口再试。第三种设备管理器里能看到 COM3但任何串口软件打开都报“端口被占用”。这是最蒙人的明明没有打开任何串口工具却提示占用。原因是某些工程软件如 Altium Designer、QGIS 或旧版调试器在后台占用了该串口用下面这条命令查占用情况# 查看当前 CH340 端口的状态和设备实例 ID Get-PnpDevice -Class Ports | Where-Object {$_.FriendlyName -like *CH340*} | Format-List FriendlyName, InstanceId, Status如果端口处于 Started 状态但仍打不开先用系统自带的“超级终端”或串口调试助手关闭后重试仍不行就重启usbser.sys相关服务最简单是直接重启电脑比手动禁用启用设备快得多。2.2.2 从原理图确认 CH340 与 STM32 的走线很多源码包带有“项目说明”和原理图其中与上位机通信的信号线只有两对。以最常见的 CH340T 搭配 STM32F103C8T6 为例CH340 引脚STM32 引脚方向说明TXDPA10USART1_RXCH340 发送STM32 接收必须交叉RXDPA9USART1_TXCH340 接收STM32 发送必须交叉V3对地接 0.1uF 电容3.3V 供电时该脚必须接去耦电容GNDGND必须共地否则串口电平无法形成回路这里最常见的低级错误就是把两条线一顺接为 TXD 对 PA9、RXD 对 PA10结果串口助手完全收不到数据。记住口诀发送对接收接收对发送。2.3 烧录通道的选择CH340 承担的是串口不是调试器CH340 只做串口转换它本身不能给 STM32 烧录调试除非目标芯片里已经预置了 ISP bootloader。常见的做法有两种。如果你手上有 ST-Link 或 J-Link直接通过 SWD 口烧录CH340 只负责运行时的串口数据回传两者互不干扰。如果手上只有一块带 CH340 的板子而没有调试器也可以走串口 ISP 下载先把板子上的 BOOT0 跳线拉到 1高电平BOOT1 保持 0按一下复位键此时使用 STM32CubeProgrammer 选择 UART 模式就能通过 CH340 下载固件。但要注意串口 ISP 下载的是.hex或.bin不能像 SWD 那样在线调试断点。对学习调试来说个人建议还是配一个便宜的 ST-Link因为查看寄存器值和变量内容对理解 HAL 库运行机制帮助很大。有些板子把 CH340 和 SWD 都引出两种方式可以并存不需要做任何切换。3. 大棚温湿度系统的数据链路设计从传感器寄存器到串口一条龙3.1 传感器选型与采集协议I2C 与单总线的取舍这个标题没有限定具体传感器型号但“农业大棚温湿度”场景下常见的有三类DHT11/DHT22 这类单总线器件SHT30/SHT31 这类 I2C 器件以及 RS485 总线的工业传感器。最常见也最容易上手的组合是 DHT11 或 DHT22因为它们便宜、资料多、代码网上遍地都是。但单总线有个天然缺陷时序极其敏感读取时要求关闭中断否则 30us 级别的电平窗口很容易被其他中断打断导致偶发读到 0xFF 或校验失败。如果希望数据更稳定SHT30 是更好的选择。它走 I2C 协议用硬件 I2C 外设或模拟 I2C 均可不需要关中断且自身的温湿度精度±0.2℃ 和 ±2%RH比 DHT11 高一个量级。对大棚这类温度变化不剧烈的场合SHT30 的长时间漂移也更小。下面代码以 SHT30 为例展示完整读取链路如果手头是 DHT11只需把传感器层换掉上层的帧格式完全不用变。3.2 核心代码骨架初始化、读取、组帧、发送四个环节3.2.1 串口重定向 printf 的最小实现CubeIDE 自带的 ARM GCC 编译器与 Keil 不同标准库的printf不能直接扔给串口必须重定向底层函数。很多工程样例只写了fputc在 Keil 里能跑拿到 CubeIDE 里却看不到输出原因就是 GCC 的最终输出出口是_write。兼容两者的写法如下#include stdio.h // 单字符输出底层函数阻塞等待发送寄存器为空 int __io_putchar(int ch) { // UART_FLAG_TXE 置位表示发送数据寄存器空可以写入下一个字节 while (__HAL_UART_GET_FLAG(huart1, UART_FLAG_TXE) RESET) {} huart1.Instance-TDR (uint8_t)ch; // 写 TDR 即触发发送 return ch; } // ARM GCC 环境下 printf 的最终出口函数 int _write(int fd, char *ptr, int len) { for (int i 0; i len; i) { // 逐个字节发送避免内部缓冲导致串口数据断流 __io_putchar(ptr[i]); } return len; }逻辑说明__HAL_UART_GET_FLAG读取串口状态寄存器中的 TXE 位只有该位为 1 时才表示可以写入新数据这种轮询方式虽然简单但能保证printf在高速率下不丢字符。TDR是数据发送寄存器对它的写入会触发硬件开始发送。参数说明huart1是 CubeMX 生成的串口句柄名字与.ioc中实际声明的变量对应如果工程用的是 USART2需要改成huart2。这段代码放在任意.c文件里但要注意该文件必须能访问huart1的定义通常直接放在main.c中/* USER CODE BEGIN */区域即可。3.2.2 温湿度读取与数据组帧SHT30 的读取流程是先发送测量命令等待芯片完成转换再读取 6 字节数据。6 字节中第 0、1 字节为温度原始值第 2 字节为温度 CRC第 3、4 字节为湿度原始值第 5 字节为湿度 CRC。完整代码#define SHT30_ADDR (0x44 1) // 器件地址 0x44HAL 库要求左移一位 #define CMD_MEASURE_H 0x2C // 单次测量模式高位命令 #define CMD_MEASURE_L 0x06 // 单次测量模式低位命令 typedef struct { int16_t temperature; // 单位 0.1℃例如 235 表示 23.5℃ int16_t humidity; // 单位 0.1%例如 615 表示 61.5% } env_data_t; HAL_StatusTypeDef sht30_read_once(I2C_HandleTypeDef *hi2c, env_data_t *out) { uint8_t cmd[2] {CMD_MEASURE_H, CMD_MEASURE_L}; uint8_t raw[6] {0}; // 发送测量命令超时设为 50ms if (HAL_I2C_Master_Transmit(hi2c, SHT30_ADDR, cmd, 2, 50) ! HAL_OK) return HAL_ERROR; HAL_Delay(12); // 等待传感器完成测量规格书要求至少 9ms // 一次性读出 6 字节超时 50ms if (HAL_I2C_Master_Receive(hi2c, SHT30_ADDR, raw, 6, 50) ! HAL_OK) return HAL_ERROR; // 温度计算公式T 175 * raw / 65535 - 45 int32_t t_raw (raw[0] 8) | raw[1]; // 湿度计算公式RH 100 * raw / 65535 int32_t h_raw (raw[3] 8) | raw[4]; // 乘 1000 再除最后除以 10保留一位小数且避免浮点运算 out-temperature (int16_t)((17500 * t_raw / 65535) - 4500); out-humidity (int16_t)((10000 * h_raw / 65535)); // 生产环境应在此补 CRC 校验SHT30 校验多项式为 0x31 return HAL_OK; }逻辑说明HAL_I2C_Master_Transmit负责发送命令字发送完必须延时给芯片留出转换时间这个 12ms 是经验值略大于规格书的 9ms但不能超过 30ms否则传感器会进入空闲状态。(raw[0] 8) | raw[1]把大端序的原始数据拼成一个 16 位整数后面的运算全部用整数完成避免嵌入式环境里浮点库带来的代码体积膨胀。参数说明SHT30_ADDR写为(0x44 1)是因为 HAL 库的DevAddress参数要求 8 位地址即 7 位地址左移一位。这里最容易出错的是在 CubeMX 的 I2C 配置界面中把器件地址填成0x44会导致第一字节错误变成0x22表现为传感器无应答。3.3 帧格式与解析给上位机预留稳定的协议接口传感器读完不是直接printf(temp%d)就完了。大棚系统往往后续要接多个传感器、执行器或上传云端一个固定的二进制帧格式会让扩展容易得多。常见的帧结构如下偏移含义值/范围说明0帧头0xAA固定值用于同步定位帧起点1数据长度0x05表示偏移 2 至 6 共 5 字节有效数据2数据类型0x010x01 为温湿度预留其他类型3-4温度int16 大端实际值 原始值 / 105-6湿度int16 大端实际值 原始值 / 107CRC8覆盖偏移 0-6多项式 0x31初值 0xFF组帧代码如下uint8_t crc8(uint8_t *data, uint8_t len) { uint8_t crc 0xFF; // 初值与多数协议兼容 for (uint8_t i 0; i len; i) { crc ^ data[i]; for (uint8_t b 0; b 8; b) { // 按多项式 0x31 做无进位除法等效于 CRC-8/MAXIM crc (crc 0x80) ? (crc 1) ^ 0x31 : (crc 1); } } return crc; } void env_frame(uint8_t type, env_data_t *d, uint8_t *out, uint8_t *len) { out[0] 0xAA; out[1] 5; out[2] type; out[3] (uint8_t)(d-temperature 8); // 高字节在前 out[4] (uint8_t)(d-temperature 0xFF); out[5] (uint8_t)(d-humidity 8); out[6] (uint8_t)(d-humidity 0xFF); out[7] crc8(out, 7); // CRC 覆盖前 7 字节 *len 8; }逻辑说明CRC8 的循环部分是对多项式 0x31 的逐位模拟每读入一个字节执行 8 次移位和异或。(crc 0x80)判断当前最高位是否为 1为 1 时左移后异或多项式否则直接左移。这段逻辑不依赖查表代码量小适合放在资源紧张的小 MCU 上。参数说明out[3]和out[4]分别存放温度高、低字节采用大端序是为了和 SHT30 的原始数据字节序一致避免上位机再做一次字节交换。类型字段type留给扩展比如未来接入土壤湿度时可以把类型定义为0x02帧长相应调整上位机解析逻辑只需要按类型分流。4. 串口数据为什么不对分层、时钟与中断丢包的排查路径4.1 先分层把故障定位到驱动、硬件还是协议串口数据异常是最难排查的一类问题因为任何一层出错都会表现为“串口助手里的数据不对”。我一般按三层来切端口层、硬件层、协议层。端口层看设备管理器确认 CH340 是否出现、COM 口号是多少。硬件层做一次“回环测试”把 CH340 模块的 TXD 和 RXD 用杜邦线短接在串口助手里发送一个字符串如果能在同一窗口收到自己发的数据说明 USB 转串口芯片和驱动链路是通的。如果没有回显、发送区接收区都空再测 STM32 侧的PA9/PA10与 CH340 模块走线是否接反。协议层排错是最耗时的常见现象是“能收到东西但内容对不上”。此时不要盯着 ASCII 字符看改按十六进制显示帧数据先看帧头 0xAA 是否稳定出现。如果帧头都乱七八糟问题多半在波特率偏移或信号质量上如果帧头正常但 CRC 经常失败则重点查传感器端的时序和供电。4.2 三个必调参数波特率、数据位、系统时钟配置串口通信的参数在两端之间必须完全一致缺少任何一个字符整帧解析就全废了。最容易被忽略的不是波特率而是隐藏波特率偏移的系统时钟配置。参数常见取值不一致时的现象波特率9600 / 115200可收到数据但全为乱码帧头 0xAA 变 0x55数据位8偶发多一位或少一位帧错位校验位None极少数帧会被 CRC 拦截停止位1基本无感但高速下可能丢字节如果上位机设置 115200、工程里初始化也是 115200却依然乱码优先检查时钟树。CubeMX 中常见的坑是外部晶振实际是 8MHz但工程里给 HSE 填的是 25MHz导致系统主频按错误的倍频计算UART 波特率随之整体偏移。查看.ioc中RCC HSE的频率值再对照原理图上的晶振丝印确认。没有外部晶振的板子必须把 HSE 改为旁路或直接选 HSI否则芯片可能完全无法启动。4.3 中断接收丢数据的处理让接收缓冲区成为环形结构很多入门工程在串口中断里只做一个HAL_UART_Receive_IT加一个变量数据多了就丢帧。原因很简单中断回调把收到的字节存入一个固定位置主循环还没来得及读走下一个字节就覆盖了。常见做法是把接收缓冲改成环形缓冲区#define RX_BUF_SIZE 256 static uint8_t rx_buf[RX_BUF_SIZE]; static volatile uint16_t head 0; static volatile uint16_t tail 0; // 写入一个字节缓冲区满时丢弃新字节 static void put_rx_byte(uint8_t byte) { uint16_t next (head 1) % RX_BUF_SIZE; if (next ! tail) { // 头 1 等于尾说明缓冲区已满 rx_buf[head] byte; head next; } } // 中断回调里只做入队不做协议解析 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart-Instance USART1) { put_rx_byte(rx_byte); HAL_UART_Receive_IT(huart1, rx_byte, 1); // 重新开启下一次接收 } }逻辑说明head和tail分别是写入指针和读出指针判空条件为head tail判满条件为(head 1) % RX_BUF_SIZE tail大小为 256 时最多缓存 255 个字节留一个位置用于区分空和满。主循环或帧解析函数从rx_buf[tail]取值并推进tail即可。参数说明中断回调里必须再次调用HAL_UART_Receive_IT因为 HAL 库的函数默认只接收一个字节后就停止接收。漏掉这一行整个程序可能只收到第一帧就再也不进中断。这是串口工程里出现频率最高的一类 bug比波特率配置问题还要常见。注意不要试图在中断回调里做大循环或调用printf串口中断优先级低时会把主循环卡死优先级高时会影响传感器时序。回调里只放最短的入队代码解析和转发交给主循环。5. 把“项目说明”写成能复现的文档三张表加一个验证脚本5.1 项目说明里必须有的三张表一份源码包如果只有代码没有硬件描述换一个人拿到手基本无从下手。项目说明至少要包含三张表引脚分配表、串口参数表、传感器参数表。引脚表描述 STM32 的哪个引脚连接到哪个外部器件串口表描述波特率、数据位、停止位和校验位传感器表描述器件型号、量程和输出格式。很多工程只写一句“PA9/PA10 为串口”缺了 CH340 的接线关系导致用户在硬件层反复试错。5.2 一个 10 分钟跑通的验证流程拿到源码后按下面的步骤能在 10 分钟内验证系统是否正常第一步打开 CubeIDE 直接编译第二步确认 CH340 驱动且串口号已知第三步连接 SHT30 与 STM32 后上电用串口助手打开对应端口第四步观察是否按预期周期收到帧头AA开头的数据。如果收不到短接 CH340 的 TXD 和 RXD 做回环测试缩小问题范围。验证上位机解析时用一段 Python 脚本比任何串口助手都直观import serial ser serial.Serial(COM3, 115200, timeout1) while True: data ser.read(8) # 读取一帧 if len(data) 8 and data[0] 0xAA: # 校验帧头 temp (data[3] 8 | data[4]) / 10.0 hum (data[5] 8 | data[6]) / 10.0 print(ftemp{temp:.1f}C, hum{hum:.1f}%)注意这里没有做 CRC 校验加上 CRC 判断后能过滤掉约一半的硬件噪声干扰。验证脚本在pip install pyserial后即可运行Windows 下把COM3换成实际端口号。5.3 给后续扩展留的接口从串口到云端如果这套系统要接入物联网平台串口只是半程。常见做法是加一个 ESP8266 或 ESP32 作为 WiFi 透传模块STM32 的串口一直接到 ESP 的 UARTESP 内部运行 AT 固件或 MicroPython把收到的二进制帧打包成 MQTT 消息上行。此时 STM32 侧的代码几乎不用改只需将帧频控制在 1 秒 1 帧以内避免小模组缓冲溢出。帧格式设计成二进制而不是文本在云端解析时也更方便这一点在项目说明里就应该写清楚而不是等对接时再补。本文还有配套的精品资源点击获取