尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

STM32F103C8T6温湿度监测与继电器控制项目:原理图、仿真与代码全解析

发布时间:2026/9/23 22:01:23

资讯中心
01
ARTICLE

STM32F103C8T6温湿度监测与继电器控制项目:原理图、仿真与代码全解析

STM32F103C8T6温湿度监测与继电器控制项目:原理图、仿真与代码全解析
1. 先看全貌这个开源项目到底在解决什么问题做嵌入式这几年我在开源社区翻过不少STM32项目大部分情况是代码能跑但原理图只有个截图仿真根本没给。所以这次看到这个项目的时候我反而多留了个心眼——它把代码、原理图、仿真三件套配齐了这种项目在STM32方向里不算多但恰恰是最适合拿来系统的学一遍的。先说清楚这个项目是干什么的。它本质上是一个基于STM32F103C8T6的小型环境监测与开关控制系统通过DHT11采集温湿度在OLED屏幕上显示实时数据支持按键设置上下限阈值当温度或湿度越限时自动控制继电器通断来带动风扇、加热器这类负载同时把状态通过串口打印到上位机。功能链路是完整的采集 → 显示 → 判断 → 执行 → 上报。硬件成本很低一块核心板加几个外围器件就能搭起来很多课设和毕设题目也都长这样。但题目常见不等于实现合格它的价值主要体现在三件套的配合度上有代码可以改逻辑有原理图可以改硬件有仿真可以先把想法验证一遍再动手买元器件焊接。我在评价这类开源项目的时候通常会按三个维度来打分代码可维护性、原理图规范性、仿真可复现性。代码决定你改它的成本原理图决定你抄板的安全感仿真决定你调试的效率。这篇文章就是把这三个维度挨个拆开说清楚最后再补一组我复现时踩过的坑。1.1 硬件资源与引脚分配逻辑先看硬件分配。STM32F103C8T6这颗芯片大家应该很熟了Cortex-M3内核主频72MHz64KB Flash20KB RAM48个引脚。在这个项目里引脚划分得很典型功能模块引脚接口类型关键器件DHT11温湿度PA0单总线4.7k上拉电阻OLED显示屏PB6/PB7I2C0.96寸SSD1306继电器控制PB0GPIO输出三极管驱动续流二极管板载LED指示PB1GPIO输出330欧限流电阻阈值设置按键PA1/PA2GPIO输入10k上拉RC滤波串口日志PA9/PA10USART1CH340或直接USB转TTL调试下载PA13/PA14SWDST-Link引脚的分配思路其实有个隐性规律I2C和USART这类复用功能尽量放在默认映射位置这样初始化代码不用重映射省掉一堆麻烦按键和LED这类普通IO放在一起方便布线继电器这种可能会产生电磁干扰的执行器件跟传感器引脚保持一定距离。这种分配方式对于新手来说非常友好因为它能最大程度降低代码和原理图对不上的概率。我见过不少开源项目原理图里引脚乱飞代码里还得加AFIO重映射配置一不留神就把自己绕晕了。1.2 为什么代码原理图仿真三件套值得学其实很多人的学习路径是反的拿到代码直接烧烧进去发现灯不亮然后就开始瞎猜。这个项目给了三条路平行推进的可能性。仿真先行是最推荐的方式。在没打板之前用Proteus或者在线仿真平台把逻辑跑通确认传感器的数据读取时序、继电器翻转逻辑、串口报文格式都没有问题再回来看原理图去理解硬件为什么这么接最后才是买元器件动手。原理图是中间的翻译层。它把芯片引脚的电气行为翻译成实际的电路连接。很多人代码写得溜但一看原理图就懵其实是因为缺少引脚 ↔ 信号 ↔ 器件三者之间的对应训练。这个项目把三者绑在一起正好逼着你建立这种对应关系。代码则是最上层的表达。底层硬件怎么动作最终都要落在寄存器和GPIO电平上。有了仿真验证逻辑、原理图对照硬件再回头读代码你会发现很多东西是原来如此——比如为什么DHT11的时序要求那么严格为什么继电器控制要加一级三极管驱动这些都能在原理图和代码的相互印证中理解通透。2. 代码质量评价一份值得借鉴的STM32工程应该长什么样代码是这个项目里我最先看的部分。评价标准只有一条如果我想把这个项目移植到另一颗芯片上或者改造成别的功能我要不要重写2.1 工程结构与模块划分项目的代码基于标准外设库SPL开发工程目录分了几个层次典型结构大概是这样├── USER // main.c, stm32f10x_it.c, 系统配置 ├── HARDWARE // 外设驱动层dht11.c, oled.c, relay.c, key.c ├── APP // 应用逻辑层menu.c, control.c, protocol.c ├── SYSTEM // 延时、串口、中断优先级等基础支持 └── CORE // 内核相关文件启动文件、系统时钟这套划分方式很传统但确实好用。外设驱动层只干一件事把某个外设的操作封装成函数不掺杂业务逻辑。比如DHT11_Read_Temperature()就只负责读取和返回温度值至于是不是越限、要不要开继电器那是应用层control.c的事。应用逻辑层里有个典型的控制循环主函数大概长这样int main(void) { SystemInit(); Delay_Init(); USART1_Init(115200); OLED_Init(); DHT11_Init(); Relay_Init(); Key_Init(); while (1) { DHT11_Read_Data(); // 采集温湿度 Control_Threshold_Check(); // 阈值判断 OLED_Display_Update(); // 刷新显示 Protocol_Send_Report(); // 串口上报 Delay_Ms(500); // 主循环周期控制 } }主循环干净利落业务逻辑一眼就能看明白。这也是我评价一个STM32项目代码的第一个加分项主循环是不是能看懂。如果拿到一个项目main函数里一坨一坨的嵌套逻辑连初始化都要翻好几层才能找到那后续改代码的维护成本会成倍上涨。2.2 核心逻辑与关键时序实现DHT11是目前入门项目里出现频率最高的传感器之一它对时序的要求比较严格主机发出起始信号后DHT11会拉低80us再拉高80us表示响应然后每一位数据以50us低电平起始26-28us的高电平表示070us的高电平表示1。所以代码里读取数据时用的是阻塞延时配合GPIO电平读取注册了一个DHT11_Read_Bit()这样的函数通过延时判断高电平持续的时间来区分0和1。这段代码的写法通常很直接uint8_t DHT11_Read_Bit(void) { uint8_t i; while (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) RESET); // 等待低电平结束 Delay_Us(40); // 延时40us if (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) SET) // 高电平持续40us以上 { i 1; while (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) SET); // 等待高电平结束 } else { i 0; } return i; }这里有个新手容易踩的坑Delay_Us()必须是精确的微秒级延时。如果项目里用的是SysTick做系统时钟那就需要用汇编或者DWTData Watchpoint and Trace来做微秒延时单纯靠循环减法的延时在不同优化等级下误差会很大。这个项目采用的是基于SysTick的简洁延时实现实测下来在8MHz外部晶振、72MHz主频下还是比较稳的。2.3 按键消抖与状态机的设计思路按键处理这部分项目没有用简单的延时消抖而是做了一个小状态机我觉得这点很值得拿出来说一下。机械按键按下和松开的瞬间都会有抖动大概持续5到10ms如果不处理一次按下会被识别成多次触发。常见的消抖方式有两种一是检测到电平变化后延时10到20ms再次确认二是用定时器做扫描每隔5ms采样一次连续多次采样都稳定才判定为有效。这个项目用的是扫描式消抖并且把按键动作分成了按下、确认按下、释放、确认释放几个状态。这种思路的好处是实时性更好。比如用户连续按三下按键如果每次都用20ms阻塞延时消抖那整个流程会变得很迟钝而状态机方式下主循环照常跑定时器中断每5ms扫描一次按键既不会阻塞其他任务又能准确识别连续操作。对于同时要处理传感器读取、OLED刷新、串口上报的项目来说这种主循环定时器时间片的架构比裸奔阻塞延时靠谱得多。这也是我从这个项目里学到的比较核心的一个编程思路。2.4 评价代码时我最看重的三个细节第一是命名规范。这个项目里所有函数都带模块前缀DHT11_、OLED_、Relay_、KEY_变量命名也基本是语义化的比如temperature_val、humidity_val、threshold_temp_high。嵌入式项目最怕的就是a、b、c这种变量满天飞过两周自己都不知道写的什么。第二是注释的度。这个项目的注释不多但都写在关键节点上比如DHT11时序里的延时说明、继电器控制逻辑的触发条件。它没有每一行都注释因为那是废话它注释的是为什么这么写。这两者的区别很关键。第三是可移植性。外设驱动的头文件里把引脚、端口、时钟都用宏定义做了封装换芯片或者换板子的时候只需要改宏定义不需要动函数内部的逻辑。这一点在项目改造时能省下大量时间。比如把DHT11从PA0换到PB3只需要改#define DHT11_PORT GPIOB和#define DHT11_PIN GPIO_Pin_3然后记得在初始化函数里打开GPIOB的时钟就行。整体评价这份代码的工程质量在开源项目里属于中上水平虽然不算多惊艳但作为学习和改造的底子已经非常合格了。3. 原理图设计评价从最小系统到外设电路的规范性代码看完了接下来对照原理图。原理图评价的核心是安全性电源能不能稳住、信号会不会串扰、有没有为了省钱省掉必要的保护电路。3.1 最小系统设计的合理性先看电源部分。板子用USB的5V输入经过一颗AMS1117-3.3稳压芯片降到3.3V给MCU和其他外设供电。AMS1117是LDO线性稳压芯片输入输出压差小适合这种电流需求不大的场景。电源设计里有个细节我比较在意AMS1117的输入输出端都加了10uF和0.1uF的电容组合。10uF的钽电容或电解电容负责储能应对瞬态电流波动0.1uF的陶瓷电容负责滤除高频噪声。两者配合电源纹波才能控制在合理范围内。这个项目在这点上没省料值得表扬。然后看时钟电路。STM32F103C8T6支持外部8MHz晶振两个负载电容用的是20pF。这个取值是常见做法但如果你用的晶振负载电容是12pF或者18pF需要对应调整。我一般会根据晶振手册来配如果实在查不到用20pF也能正常工作只是频率精度可能略受影响。复位电路就是经典的10k上拉电阻加100nF电容到地按键一端接地按下时拉低复位引脚。SWD调试接口引出了SWDIO、SWCLK、GND三根线外加一个可选的复位脚。对于F103来说三线SWD已经足够下载和调试了。BOOT0的处理也值得说。这个项目把BOOT0通过10k电阻下拉到地保证从Flash启动。这里有个细节有些板子为了省事直接把BOOT0接地但接一个下拉电阻可以避免在下载或特殊操作时因为外部干扰导致意外进入Bootloader模式这种细节是原理图规范性的体现。3.2 外设电路的关键计算外设电路部分我重点说两个LED限流电阻和继电器驱动电路。LED限流电阻的计算是入门必会。LED正常工作电流取5mA左右红色LED的正向导通压降大概1.8V到2.0VSTM32 GPIO输出高电平是3.3V所以限流电阻R (3.3V - 1.8V) / 5mA 300欧项目里用了330欧取值很合理既保证了亮度又不会让GPIO输出过流。如果用的是蓝色或白色LED正向压降会到3.0V以上限流电阻就得相应减小这点画原理图的时候要留意。继电器驱动电路是很多新手容易看懵的地方。继电器的线圈需要比较高的电流一般几十到上百毫安STM32的GPIO根本拖不动所以需要三级管做电流放大。项目用了S8050这颗NPN三极管基极通过1k电阻接GPIO发射极接地集电极接继电器线圈线圈两端并联一颗1N4148续流二极管。这个续流二极管非常关键。继电器线圈是感性负载断电瞬间会产生很高的反向电动势如果不加续流二极管这个电压可能直接打坏三极管甚至MCU。续流二极管的接法要特别注意阳极接三极管集电极也就是线圈的低端阴极接电源正极这样才能在断电瞬间给线圈电流提供泄放回路。原理图里这个二极管的方向画反了的话一上电就短路那是灾难性的。3.3 原理图绘制规范与工具细节说到原理图绘制现在很多人在嘉立创EDA上画。热词里提到dht11原理图嘉立创画图确实嘉立创EDA免费、上手快还跟嘉立创PCB打板无缝衔接适合新手。画原理图有几个规范要遵守。第一是栅格设置嘉立创EDA默认栅格一般设为0.1inch或者2.54mm画图时开启对齐到栅格这样引脚对齐、连线整洁后续转PCB布线也会轻松很多。第二是网络标签的统一电源用3.3V、5V、GND信号用语义化命名比如DHT11_DATA、OLED_SDA不要在原理图里直接拉长线信号多了以后会乱成一团。第三是电源符号和接地符号要统一不要这里用VCC那里用3.3V最后网络表导出全乱套。封装选择上DHT11一般是个四脚直插模块继电器选用5V继电器注意引脚间距和焊盘尺寸要匹配。焊接的时候直插器件还好贴片电容电阻用0805封装比较适合手工焊接太小的0603对于新手来说难度会陡增。3.4 原理图设计中的风险点和改进建议再说几个我在原理图里经常发现的隐患这个项目避开了大部分但也留了一些可以优化的空间。第一去耦电容的位置。每个MCU的电源引脚旁边都要放一个0.1uF的陶瓷电容并且要尽量靠近芯片引脚放置走线要短。如果去耦电容放得离引脚很远高频噪声滤不掉可能导致芯片工作不稳定。第二SWD接口的上拉/下拉。SWDIO建议加上拉电阻SWCLK建议加下拉电阻这样在调试器未连接时引脚状态是确定的。这个项目把SWD接口直接引出没加电阻好在F103内部有上拉和下拉默认情况下问题不大但在电磁环境差的地方可能会出现调试器连接不稳定的情况。第三地平面。如果打双层板底层尽量保持完整的地平面特别是继电器这种大电流器件它的地回路要单独走线不要跟MCU的模拟地纠缠在一起。星型接地在大功率或高频场景下特别重要虽然这个项目电流不大但养成这种习惯没坏处。4. 仿真验证评价如何用仿真在打板前把逻辑跑通仿真这部分是很多开源项目的短板但恰恰是博主最看重的效率工具。先说结论仿真不能完全替代实物调试但可以帮你节省至少一半的调BUG时间尤其是逻辑层面的问题。4.1 Proteus仿真STM32的正确姿势Proteus是很多人大学时用过的仿真软件它对STM32F103系列有一定支持能力。用Proteus仿真的核心步骤是先画好电路原理图把STM32F103C8T6放到画布上接好电源、晶振、复位电路然后添加你需要的虚拟外设比如虚拟终端Virtual Terminal用来模拟串口、LED、按键等最后在Keil里编译生成hex文件双击芯片加载hex文件点击运行。这里有几个注意事项。第一Proteus默认的STM32模型可能需要设置晶振频率你要把它设成跟实际工程一致不然串口波特率会算不对。第二Proteus仿真速度比较慢尤其是跑DHT11这类对时序敏感的传感器时仿真器对延时函数的模拟可能和实物有偏差软件自带的延时函数在Proteus里可能需要微调。第三Proteus对ADC和UART的支持相对成熟但对定时器输入捕获这类外设的模拟精度参差不齐需要实测确认。4.2 在线仿真平台快速跑逻辑的轻量方案如果你不想安装Proteus这种重量级软件Wokwi这类在线仿真平台是个很好的替代方案。它直接在浏览器里写代码、画电路、看波形对Arduino、ESP32等平台支持得最好STM32的支持也在逐步完善。以我的使用感受来说在线仿真平台最大的优势是零配置。注册账号、新建项目、粘贴代码、选好芯片型号几十秒就能跑起来。对于验证某个具体的逻辑比如串口报文格式对不对、按键消抖状态机是否正常在线仿真完全够用。它的短板也很明显外设模型有限DHT11这种传感器没有现成模型你可能要用滑动变阻器模拟模拟量或者用一个按钮手动触发高低电平来模拟时序。另外对中断、DMA、定时器这类硬件外设的行为模拟也比较粗糙。所以我的建议是在线仿真用来快速验证核心逻辑Proteus用来跑完整的软硬件配合实物永远是最准的。4.3 串口与传感器的仿真实操体会这个项目里有串口日志功能在Proteus里我用虚拟终端仿真过一版。流程是在Proteus里放一个VIRTUAL TERMINAL把它的RXD接STM32的TX引脚PA9把TXD接STM32的RX引脚PA10注意交叉连接然后设置波特率115200数据位8无校验停止位1。跑起来之后虚拟终端里确实能看到项目上报的温湿度数据和状态信息。这一步验证的价值在于协议格式对不对、数据帧是否完整、有没有乱码都能在电脑上直观看到不需要接真实的串口线。关于串口时序还可以提一个思路如果将来要写更复杂的串口接收逻辑可以参考FPGA的UART_RX接收仿真方法——把波特率时钟生成、起始位检测、数据位采样、停止位校验都做细。虽然STM32用中断接收比较多但理解了底层时序调试串口问题时会更从容。4.4 仿真和实物到底差在哪仿真能帮你验证逻辑但仿真通过不代表实物就能跑。最大的差异来自电气特性仿真里的电压是理想的不存在纹波、噪声、串扰仿真里的器件是理想模型不存在DHT11上拉电阻手抖焊歪的情况仿真里的时钟是精确的不存在晶振起振慢或者频率偏差。我还遇到过一种情况同样的代码在Proteus仿真里能正常显示OLED但实物上屏就是花屏或者不亮。排查半天发现是I2C总线上拉电阻没有焊或者上拉电阻用的是10k而不是4.7k导致I2C时序在实物上不稳定。这种问题在仿真里根本不会出现因为Proteus的I2C模型太理想了。所以我的建议是仿真负责验逻辑实物负责调电气。两者配合把能提前暴露的问题在阶段就解决掉剩下真正需要示波器、万用表的活再拿到实物上做效率最高。5. 完整复现过程与高频问题排查实录最后这部分是我自己克隆这个项目时踩过的坑每个问题都花过一些时间整理出来供大家参考。很多问题看起来五花八门本质上都是环境、接线、时序三个方面的问题。5.1 Keil5同时兼容C51和STM32的安装细节很多人的电脑不只是玩STM32还要兼顾学校里的51单片机实验那就涉及到一个Keil下同时装C51和MDK的问题。实际上Keil的C51和MDK-ARM是两个独立的产品可以装在同一台电脑上但要注意几点。最省事的顺序是先装C51再装MDK-ARM。两者默认安装路径相同的话后装的MDK会覆盖部分公共文件但各自的编译器是独立的。装完之后桌面上只有一个Keil uVision5的图标新建工程时如果你的工程基于8051芯片它会自动调用C51的编译器如果是ARM内核芯片会调用ARMCC或者AC6编译器。容易踩的坑是License问题。C51和MDK的License是分开的如果你只有MDK的License编译51工程时会提示No License反之亦然。解决方法是把两个License都添加进去在Keil的License Management界面里License ID Code填一个添加完再填另一个两个都会显示为有效。STM32芯片包安装也在这里面。装完MDK之后还需要在Pack Installer里安装STM32F1系列的Device Family Pack也就是Keil.STM32F1xx_DFP。如果在线安装速度慢可以去Keil官网下载对应的.pack文件然后通过Pack Installer的File → Import菜单离线导入。5.2 ST-Link连接与烧录问题ST-Link无法识别USB设备是我被问过最多的问题之一。如果你把ST-Link插上电脑设备管理器里看不到任何STM32相关的设备或者看到一个带着黄色感叹号的未知设备大概率是驱动问题。先去ST官网下载最新版的ST-Link USB Driver装上一般能解决。驱动没问题但还是识别不了就要查硬件了。第一USB线是不是只有供电没有数据传输线这个坑我踩过不止一次看上去一模一样的两根安卓线功能完全不同。第二ST-Link和目标板之间的接线SWDIO、SWCLK、GND、3.3V四根线要一一对应千万别接反。第三目标板供电是否正常有些ST-Link虽然能对外输出3.3V但电流很小带不动整个板子这时候要用外部电源给板子供电。如果连上之后能识别但下载失败可以试试ST-Link Utility这个工具。它除了能烧录程序还能查看芯片的Flash、Option Bytes、读写保护状态。很多时候下载失败是因为芯片被设置了读保护用ST-Link Utility把读保护解除再下载就好了。5.3 硬件上电后的常见故障程序烧进去之后板子没反应是另一个高频问题。这时候先从电源和时钟查起用万用表量3.3V电压是否正常如果电压偏低查AMS1117输出端的电容有没有焊反钽电容接反会短路甚至炸用示波器或者逻辑分析仪看8MHz晶振是否起振如果晶振引脚上没有正弦波检查负载电容和晶振本身。OLED花屏的排查思路先确认I2C地址对不对SSD1306常见的地址是0x3C或者0x3D软件里设置的地址要和硬件地址一致可以通过改变SA0引脚的电平来切换。再查I2C总线的上拉电阻F103的I2C在硬件上需要外接上拉一般用4.7k如果没接或者阻值太大通信时序会不稳定。最后把I2C时钟频率降下来试试有些OLED模块对400kHz的快速模式兼容性不好降到100kHz就能正常显示了。DHT11读取失败要么全0要么全255优先查数据线的上拉电阻DHT11单总线要求数据线上有上拉电阻阻值范围4.7k到10k都可以没有上拉电阻的话数据线处于浮空状态读取结果必然是错的。然后查延时函数是否准确一些移植过来的延时函数跟主频不匹配本来应该延时40us的地方变成了400us时序肯定对不上。5.4 高频问题排查速查表问题现象可能原因解决方法ST-Link电脑不识别驱动缺失、USB线是充电线安装ST-Link USB Driver换数据线能识别但下载失败芯片读保护、SWD接线错误用ST-Link Utility解除读保护核对接线程序烧进去板子没反应电源异常、晶振未起振、BOOT0配置错误量3.3V电压示波器查晶振检查BOOT0电平OLED花屏或黑屏I2C地址不对、上拉电阻缺失、时钟太快核对0x3C/0x3D地址补4.7k上拉降I2C时钟DHT11读不到数据上拉电阻缺失、延时不准、线太长补4.7k上拉校准微秒延时缩短杜邦线继电器不停抖动基极未加下拉、MCU上电瞬间误触发基极到地加10k下拉电阻GPIO初始化先拉低串口输出乱码波特率不匹配、晶振频率设置错误核对代码和上位机的波特率检查HSE_VALUE最后说几句我的评价和心得如果非要给这个开源项目打一个总分我会给到8分以上。代码结构清晰可读原理图能看出来是认真画过的仿真部分覆盖了核心逻辑验证作为嵌入式入门和课设改造的素材含金量是够的。它的扣分项主要在DHT11这个传感器本身精度和稳定性都很一般如果要做真正意义上的监测系统建议换成SHT30这类数字温湿度传感器I2C接口精度高一个数量级。我自己在实践中最深的体会是拿到开源项目不要急着跑起来就结束一定要把代码、原理图、仿真这三者对着看一遍。代码里每操作一个寄存器去原理图里找对应的电路再在仿真里复现一遍行为这个过程走完你对项目才算真正懂了。很多人学了很久嵌入式遇到新项目还是手足无措就是因为平时只在代码层面打转没有建立这种三重对应的直觉。最后分享一个小技巧如果你也想做类似的三件套开源项目记住仿真不一定要完整复刻整个系统只仿真你最有把握出错的部分就行。我通常会把串口通信、按键逻辑和传感器时序单独拿出来仿真验证这三块恰恰是最容易藏着隐藏BUG的地方。验证通过之后再回到实物上去调电气这样整个开发周期能明显缩短。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。