
简介面向嵌入式课程设计场景这套资料以STM32F401微控制器和DS18B20数字温度传感器为核心提供完整的温度报警系统方案包含Keil5工程源码、Proteus仿真电路图和配套设计报告适合高校相关专业学生作为课程设计、课设答辩或毕业设计参考。系统支持实时温度采集、液晶显示、手动设置上下限预警参数、超限LED指示灯报警并可在LCD上显示题目、姓名、学号等定制信息同时预警范围覆盖-100至100摄氏度满足常规环境监测要求。压缩包内共190个文件整体约9.27MB以C/H源码、Proteus仿真文件、编译生成的hex/axf文件以及Word文档设计报告为主类型区分明确便于查看逻辑、运行仿真和继续修改。目前已有12656人学习使用说明这套方案在同类嵌入式课程设计中具有较高人气与参考价值。通过源码阅读和仿真复现能够快速掌握STM32外设配置、DS18B20单总线驱动时序、按键交互和显示逻辑适合在此基础上扩展风扇控制、声光报警或其他物联网功能。 “基于STM32的温度报警设计”是我见过被最多学生拿来当年终课设或者毕业设计的题目之一。说它简单是因为功能很清晰读个温度、设个阈值、超了就叫。说它不简单是因为实际调试中总会在传感器时序、报警抖动、下载失败这些地方翻车。这篇文章我打算把整个方案从头到尾拆一遍从硬件选型到软件状态机再到那些网上教程不会明说的坑尽量让第一次做毕设的人也能照着落地。在开始看代码之前正好用一句话点出核心这个项目的本质不是做一个温度计而是做一个稳定的事件响应系统。1. 项目整体思路与方案选型1.1 功能拆解别急着写代码先画状态机很多人拿到题目就直接打开STM32CubeMX配置引脚但这样很容易漏需求。温度报警看着只涉及“读取温度”和“超过阈值报警”实际上系统至少有这几个状态正常态、报警态、恢复态还可以再加上错误态。什么条件触发报警温度大于等于阈值。什么条件取消报警注意不是“回落到阈值以下”就立刻取消否则蜂鸣器或继电器会在临界点来回跳。我建议加滞回区间比如报警阈值是60摄氏度那么等温度回落到57摄氏度再解除报警这3摄氏度的差值就是回差。为什么需要回差因为温度本身有波动传感器读数也有噪声如果没有滞回系统会不停地在报警和正常之间切换。还有一个容易被忽略的点当传感器故障、读不到数据时系统不能当作正常温度处理。如果这是一台温控柜传感器断线但报警不响可能造成设备烧毁。所以错误状态也要触发报警至少要有明显的异常指示。状态机先想清楚后面写代码就是水到渠成的事。1.2 为什么选STM32控制器的取舍做这个项目很多初学者会问用51单片机不香吗确实能实现尤其只接一个DS18B2051绰绰有余。但我还是建议用STM32来做理由有三点。第一STM32主频高、外设丰富后续要扩展OLED显示、ESP8266联网、上位机串口监控不需要换平台。第二HAL库配合STM32CubeMX能快速生成工程把精力放在业务逻辑上这也是目前企业里常见的工作方式。第三从毕业设计或者项目答辩角度看用STM32可展示的东西更多DMA、定时器输入捕获、FreeRTOS都是现成的扩展方向。如果只是追求最低成本、最简单51完全可以但如果想学到东西STM32的知识复利明显更高。具体型号我推荐STM32F103C8T6淘宝十几块钱的小系统板资料多教程多遇到问题几乎都能搜到答案。1.3 温度传感器选型DS18B20、NTC、LM75怎么挑温度传感器常见的有三种各有优劣传感器通信方式典型精度成本优点缺点DS18B20单总线±0.5℃-10~85℃低接线少、数字输出、可直接读温度时序要求严格单总线容易受干扰NTC热敏电阻模拟电压取决于校准很低电路简单成本极低需要ADC、查表温漂明显LM75I2C±3℃中低总线稳定可并联多个精度一般需要I2C协议调试我做这个项目一般推荐DS18B20原因很现实只有一根数据线代码例程多调试相对容易。但要注意它必须外接一个4.7kΩ左右的上拉电阻到VCC否则数据线没法正常工作。而且“单总线”意味着所有通信都挤在一根线上时序要求苛刻后面软件部分我会专门讲。2. 硬件电路设计与搭建2.1 最小系统与引脚规划这里以最常见的STM32F103C8T6核心板为例整板不用自己画最小系统只需要考虑外设连接。我的引脚规划如下DS18B20数据引脚接PA0配置成开漏输出模式蜂鸣器控制引脚接PB1状态指示LED接PC13PA9和PA10作为串口1的TX、RX用来打印调试信息。重点强调一下GPIO模式DS18B20的GPIO不要用推挽输出更不要用普通输入模式。单总线协议要求主机在读取时释放总线让外部上拉电阻把电平拉高你用开漏输出模式最省心。如果配成推挽输出操作不当很容易导致引脚和传感器输出打架轻则读不到数据重则损坏端口。CubeMX里把PA0选成GPIO_Output然后设置为Output Open Drain再开启内部上拉或者外部加4.7kΩ上拉这样读和写都能搞定。2.2 报警执行电路蜂鸣器、继电器、LED报警执行机构可以根据场景选蜂鸣器、LED或者继电器。先说蜂鸣器很多人直接把IO口接蜂鸣器正极结果发现声音很小或者IO口烧了。原因很简单无源蜂鸣器工作电流往往超过30mASTM32的GPIO输出能力有限而且蜂鸣器是感性元件关断瞬间会产生反向电动势。正确做法是用一片NPN三极管做开关。GPIO经过1kΩ电阻接到三极管基极发射极接地集电极接蜂鸣器负极蜂鸣器正极接VCC。IO输出高电平三极管导通蜂鸣器响IO输出低电平蜂鸣器停。如果控制的是继电器继电器线圈两端必须并联一个反向续流二极管比如1N4148否则线圈断电瞬间的感应电压很容易击穿三极管或单片机的引脚。LED就简单了串一个330Ω或1kΩ电阻到地。2.3 电源与去耦小细节影响大稳定整个系统可以用USB的5V供电核心板上的AMS1117稳压到3.3V。DS18B20的工作电压范围是3.0V到5.5V建议直接使用和单片机一致的3.3V避免电平不匹配。这里有一个容易被忽略的点DS18B20的数据线在3.3V供电时上拉电阻也可以接3.3V不要一股脑接5V。另外去耦电容特别重要。我会在MCU的VCC引脚旁边放一个100nF陶瓷电容电源入口放一个10μF电解电容并联100nF。别小看这几毛钱的电容驱动继电器或蜂鸣器这种开关负载时电源瞬间跌落会导致DS18B20时序错乱温度数据飘忽不定。加上去耦电容之后很多莫名其妙的故障会直接消失。3. 软件设计与核心代码实现3.1 开发环境配置HAL库还是标准库现在STM32开发主流方案有三种标准外设库、HAL库配合STM32CubeMX、LL库。对于这个项目我最推荐STM32CubeMX生成工程加HAL库理由是图形化配置时钟和外设代码自动生成以后加串口、I2C都方便。CubeMX配置大致是选择芯片STM32F103C8TxRCC设为HSE外部晶振SYS的Debug设为Serial Wire。这一步非常重要如果Debug不选Serial Wire代码下载一次之后第二次就可能报找不到目标设备。然后配置USART1的TX是PA9、RX是PA10PA0设为开漏输出接DS18B20PB1设为推挽输出接蜂鸣器PC13设为输出接LED。时钟树直接选72MHz。生成MDK-ARM工程用Keil打开。如果你习惯VSCode加EIDE插件或者PlatformIO也不是不行但新手用Keil更稳至少报错定位更直接。工程生成之后第一件事是编译一次确认环境没问题再开始写业务代码。3.2 DS18B20驱动核心时序和代码DS18B20通信过程就是一个主机对从机的严格时序控制任何一个延时不对都可能读回0或者85。关键步骤我记成四步复位主机拉低总线480μs以上然后释放等待从机拉低60到240μs如果检测到存在脉冲说明传感器在线。跳过ROM发送0xCC。总线上只有一个设备时不需要匹配64位序列号。启动温度转换发送0x44。转换时间最长750ms如果设置为12位分辨率。再复位、跳过ROM、发送0xBE读暂存器连续读9个字节前两个字节是温度低字节和高字节。关键的复位和读写时序代码看起来是这样static uint8_t DS18B20_Reset(void) { uint8_t presence; DQ_LOW(); delay_us(500); DQ_HIGH(); delay_us(60); presence DQ_READ(); delay_us(420); return presence; } static void DS18B20_WriteByte(uint8_t data) { for (int i 0; i 8; i) { DQ_LOW(); delay_us(2); if (data 0x01) DQ_HIGH(); else DQ_LOW(); delay_us(60); DQ_HIGH(); data 1; } } static uint8_t DS18B20_ReadByte(void) { uint8_t data 0; for (int i 0; i 8; i) { data 1; DQ_LOW(); delay_us(2); DQ_HIGH(); delay_us(5); if (DQ_READ()) data | 0x80; delay_us(60); } return data; }这段代码里的delay_us是软件延时不能用HAL_Delay因为HAL_Delay最小单位是1ms而单总线时序要求的是微秒级。我习惯用SysTick写一个delay_us或者直接用一个基本定时器做微秒延时。软件延时会受编译器优化等级影响如果读数据不对先检查这段延时是否校准。3.3 报警状态机不要用if堆业务很多教程里的写法是if (temp 60) buzzer_on(); else buzzer_off();这样做在阈值附近大概率会产生继电器弹跳一样的“哒哒声”。用状态机会清晰很多扩展错误处理也方便typedef enum { STATE_NORMAL, STATE_ALARM, STATE_ERROR } SysState_t; SysState_t state STATE_NORMAL; float temp 0; while (1) { if (DS18B20_ReadTemp(temp) ! DS18B20_OK) { state STATE_ERROR; } else { switch (state) { case STATE_NORMAL: if (temp ALARM_TEMP) state STATE_ALARM; break; case STATE_ALARM: if (temp RELEASE_TEMP) state STATE_NORMAL; break; case STATE_ERROR: if (temp ALARM_TEMP) state STATE_NORMAL; break; default: break; } } UpdateOutput(state, temp); HAL_Delay(500); }这里ALARM_TEMP设成60.0fRELEASE_TEMP设成57.0f。因为主循环间隔500ms采样一次相当于软件消抖蜂鸣器不会再乱响。在错误状态下我一般让蜂鸣器以1秒间隔间歇报警和持续报警的高温状态区分开。3.4 串口打印与调试调试时串口的功劳最大。我会重定向printf到串口1每隔500毫秒打印一次温度值和当前状态这样不用猜代码走到哪了。int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 0xFFFF); return ch; }然后插上USB转TTL模块打开串口助手波特率115200就能看到实时温度。如果手头有OLED加一个I2C显示屏把温度显示出来整个项目就更有“产品”的感觉。但要注意OLED的I2C总线和DS18B20的单总线在代码里不要混用延时否则容易互相卡顿。4. 调试常见问题与排查技巧4.1 温度永远读到85℃或-55℃这是DS18B20项目里出镜率最高的两个故障值。85℃是DS18B20上电复位后暂存器的默认值说明复位和ROM命令基本正常但读取的温度是旧值-55℃则通常是读出了0xFFFF也就是时序错乱导致读不到有效数据。排查顺序我建议是这样第一检查原理图或面包板数据线上有没有4.7kΩ上拉电阻第二确认GPIO配置的是开漏输出外部上拉正常第三用逻辑分析仪看时序或者先跑一个官方开发板例程。最容易犯的错误是上来就改代码其实是硬件接触不良。我自己的习惯是把串口打印加在复位和读取之间看到底是哪一步返回异常这样能快速缩小范围。4.2 蜂鸣器在阈值附近反复报警这个现象我在项目评审现场见过好多次温度在59.9到60.1之间来回跳蜂鸣器跟着一会儿响一会儿停非常掉价。原因就是两个没有滞回采样值本身有噪声。解决办法第一位是软件加上滞回区间就是前面提到的60℃报警、57℃解除。第二位是对温度连续采样多次比如5次去掉最大值和最小值再取平均或中值。这种滑动滤波对控温场景足够不需要上卡尔曼滤波。这里还要注意一个细节报警输出之后尽量不要在ISR或者延时函数里直接翻转引脚。用一个标志位主循环根据状态机统一更新输出看起来更规整也避免中断嵌套把单总线时序搞乱。4.3 ST-Link下载失败no stm32 target found搜索热度非常高的一个问题报错大概是“Error: no STM32 target found! If your product embeds Debug Authentication...”。绝大多数情况不是芯片锁死而是连接或配置问题。我遇到过的常见原因有SWDIO、SWCLK、GND三根线没接对或者杜邦线接触不良。核心板没有独立供电只靠ST-Link的3.3V输出供电电流不够导致芯片没正常工作。BOOT0没有拉低芯片进入了系统存储器模式。上一次程序占用了SWD引脚比如把PA13、PA14配置成普通GPIO也没有在CubeMX里把SYS Debug选成Serial Wire。ST-Link和目标板连线太长环境干扰严重可以尝试降低SWD频率。一个很实用的土办法按住目标板的复位键不放点击下载的同时松开复位键。很多“死活连不上”的情况这样就能刷进去。如果还是不行用STM32 ST-LINK Utility连接一下看能不能识别到芯片能识别说明硬件基本没问题。4.4 程序卡死在HAL_Delay或延时函数如果之前在中断回调里写了HAL_Delay而且中断优先级和SysTick相同甚至更高程序很容易卡在延时函数里出不来。正确做法是中断服务函数里只置标志位主循环处理实际业务。DS18B20的微秒延时也不要用HAL_Delay它最小单位1ms满足不了时序要求。我自己的延时方案是用DWT计数器实现delay_us。DWT是内核调试单元不需要占用定时器精度也很稳。如果你不想折腾用TIM4做一个1MHz的计数也行但注意不要让定时器中断和DS18B20死等同时发生。5. 扩展方向与个人经验5.1 能往哪些方向继续扩展这个项目想拿高分完全可以在稳定跑通之后扩展用ESP8266通过MQTT把温度上报到手机加一块OLED显示实时曲线把继电器换成SSR控制加热器就变成闭环温控系统再复杂一点用FreeRTOS把传感器采集、显示、报警拆成独立任务。但我不建议一开始就堆模块先把核心的温度采集和报警逻辑做到稳如老狗再加扩展不然出了问题都不知道该查哪一块。5.2 踩坑之后说几句实话最后分享一点个人经验。早期我也照着网上的代码抄DS18B20结果怎么调都读到85℃后来借了一台逻辑分析仪才发现是延时不准确换了编译器优化等级就好了。从那以后我养成一个习惯任何传感器调试先通过串口打印原始数据再谈业务逻辑。温度报警看似是一个入门项目但能把复位时序、状态机、硬件驱动、故障处理都讲清楚才算是真正理解嵌入式开发。希望这篇记录能让你少走一点弯路也祝你的项目一次点亮。本文还有配套的精品资源点击获取