做这个STM32温度电压电流检测报警器OLED显示仿真设计的时候,我心里其实只有一个很朴素的目标:把温度、电压、电流三路信号采进单片机,换算成真实物理量,在OLED上清清楚楚显示出来,一旦超限就报警。这个题目在实训课、电子竞赛和个人练手项目里出现频率相当高,本质上是把STM32的GPIO、ADC、定时器、I2C、外中断这些外设全部串起来做一次综合性训练。说难不难,说简单也不简单——真正动手做一遍,你会发现最花时间的地方往往不是传感器本身,而是“数据从采集到显示再到报警”这条链路里各种意想不到的小坑。这篇就按我自己实操的思路完整拆一遍,从选型、电路、代码到Proteus仿真联调,该给的参数给参数,该贴的代码贴代码,希望能帮正在做类似项目的朋友省点时间。
1. 项目需求拆解与技术选型
1.1 功能需求拆解
这个项目看起来是五个名词的堆叠,但拆开看其实是一条清晰的数据流:传感器采集信号 → STM32处理换算 → OLED屏显示 → 阈值判断 → 报警输出。每一个环节都有对应外设,也都有纠结点。
温度这一路,讲究的是传感器接口协议;电压和电流这两路,讲究的是信号调理,因为STM32片内ADC只能读0到参考电压之间的模拟量,超出量程必须经过分压、放大等手段“翻译”成ADC能接受的范围;OLED显示走I2C总线,只需要两根线,但驱动时序和初始化配置如果不对,屏幕就是不亮;报警输出比较简单,一个GPIO加一个驱动管推蜂鸣器就行,难点在于判断逻辑怎么设计才不误报。
更实际一点说,这个题目的核心考察点并不是让某个传感器工作,而是你能不能把五个模块可靠地捏合在一起。很多初学者把每个模块单独调试都正常,一合起来就翻车,原因就是没提前规划好引脚、时钟和中断资源。
1.2 芯片和传感器的选型思路
主控我选了STM32F103C8T6,也就是大家常说的“C8T6”蓝板。这颗芯片的资源是64KB Flash、20KB RAM,内置两路12位ADC、多路定时器,I2C、USART、SPI一应俱全,做这种三路采集加显示报警的项目绰绰有余。选它而不是更便宜的STM32F030,主要原因是资料量巨大,遇到问题搜方案容易得多;而且Proteus仿真库里对F103系列支持最成熟,后面烧仿真固件时不用折腾模型兼容性。
温度传感器选型基本没悬念,DS18B20。单总线协议,一根线既供电又传数据,量程-55℃到+125℃,12位分辨率下精度0.0625,完全够用。Proteus里自带这个器件模型,改一个参数就能模拟环境温度变化,比拿打火机去烫真传感器安全多了。
电压和电流这两路,核心都离不开ADC。STM32F103的ADC是12位,也就是说参考电压3.3V时,最小分辨率是3.3V÷4096,约等于0.8mV。这听上去很美好,但被测电压如果直接怼到引脚上,超过3.3V就会烧芯片,所以电压必须分压处理;电流则相反,串一个采样电阻出来的压降太小,往往只有几十到几百毫伏,必须先放大再送ADC。因此电流采样我用的是“采样电阻+运放同相放大”方案,没有选ACS712霍尔模块,一是仿真库里不是每个版本都有ACS712模型,二是运放方案能让你把信号调理的原理吃得更透。
显示部分用0.96寸I2C接口的OLED,驱动芯片SSD1306,128×64分辨率。选I2C接口而不是SPI,虽然刷新速度慢一些,但只占两个引脚,接线简单,而且SSD1306的驱动代码特别成熟,属于闭眼复制都能跑的东西。需要注意的是Proteus里OLED模型不是每个版本都有,这个在第4章我会专门说替代方案。
2. 硬件电路设计
2.1 温度采集:DS18B20单总线电路
DS18B20的接线只有三个脚:VCC接3.3V,GND接地,DQ数据线接单片机引脚。数据线上必须接一个4.7kΩ上拉电阻到3.3V,这个电阻不是可加可不加的摆设。单总线协议是开漏输出,靠外部上拉电阻把电平拉高,器件拉低代表有效信号,没有上拉,整个时序就会乱套。
我习惯把DQ接在PA0口。因为后面的ADC采集我规划了PA1和PA2两个通道,PA0是最靠近的位置,布局舒服一些,也不容易和I2C冲突。
再说供电方式。DS18B20支持寄生供电,也就是只接两根线,从数据线上“偷电”,但寄生供电对时序要求苛刻,而且在仿真里容易出奇怪问题。我的原则是能稳妥绝不冒险,直接接3.3V独立供电。仿真时要特别注意VCC别接成5V,DS18B20虽然数据手册说3.0V到5.5V都可以,但STM32的GPIO电平是3.3V,你给它5V供电,数据线拉高到5V,回读会有端口损坏风险。
温度采集时序是典型的单总线三步走:复位脉冲、写ROM指令、读数据。具体代码我在第3.2节展开,这里先提一个硬件上的坑:如果Proteus里仿真DS18B20一直返回“85℃”这个标志值,不要急着怀疑代码,先看看上拉电阻值对不对。有些版本的Proteus模型对阻值敏感,4.7kΩ没问题,但如果你图省事拖了个1kΩ进去,时序计算就可能偏差。
2.2 电压采集:分压电阻与ADC接口
电压检测的量程需要根据应用场景确定。我这次做了0~12V范围内的电压监测,这样既覆盖了常见的蓄电池电压,也可以用来测稳压电源输出。STM32的ADC参考电压是3.3V,被测电压最高12V不能直接接,所以用两个电阻串联分压,把12V按比例缩到3.3V以内。
分压电路的经典参数是R1=30kΩ、R2=10kΩ,串联后接到12V正极,从R2两端取输出电压到ADC引脚。分压比是R2÷(R1+R2)=10kΩ÷40kΩ=0.25,也就是说12V输入时ADC引脚只有3V,留了0.3V的安全余量。为什么选30k和10k而不是3k和1k,因为功耗。电阻越小分压电路自身的消耗越大,30k和10k组合在12V下总电流只有12V÷40kΩ=0.3mA,几乎可以忽略。
换算关系可以用一个公式说清:实际电压 = ADC读数 ÷ 4096 × 3.3 ÷ 0.25。比如ADC读到3000,那实际电压就是3000÷4096×3.3×4≈9.67V。注意一定是先算出ADC引脚的实际电压,再乘分压比的倒数,顺序别搞反。
如果不是测12V而是测5V系统,分压电阻要重新算。让满量程时ADC引脚电压在2.5V到3.0V之间最合理,既能用满ADC分辨率又不超限。我做过一次5V量程的方案,用的是10kΩ串联5.1kΩ,分压比约0.338,换算公式同步调整即可。
ADC引脚前面要不要加保护?如果分压电阻上端被误接高压,电阻能起到限流作用,但真正妥善的做法是在ADC引脚对地并联一个5.1V稳压管或者两个方向相反的二极管做钳位。这是我给实际硬件留的余量,仿真阶段可以不做,但做PCB时强烈建议加上。
2.3 电流采集:采样电阻加运放放大
电流检测比电压麻烦,因为单片机只能测电压。通用的办法是让被测电流经过一个已知阻值的小电阻,测它两端的压降,再用欧姆定律反算电流。这个已知电阻叫采样电阻。
采样电阻阻值怎么定?原则是压降不能太大,免得影响负载工作;压降也不能太小,否则ADC的分辨率不够用。我选0.1Ω采样电阻,如果被测电流最大2A,那满量程压降是0.1Ω×2A=0.2V。0.2V直接给ADC也能读,但你会浪费大部分量程:12位ADC在0.2V时只能用到0.2÷3.3×4096≈248个码值,分辨率太差。所以需要运放把这0.2V放大到接近3.3V的区间。
这里用LM358来做同相放大。同相放大倍数是1+Rf/R1,取R1=10kΩ、Rf=90kΩ,放大倍数就是1+90kΩ÷10kΩ=10倍,也就是0.2V放大到2V,完美适配ADC量程。换算关系是:实际电流 = ADC读数 ÷ 4096 × 3.3 ÷ 放大倍数 ÷ 采样电阻阻值。代入参数就是:实际电流 = ADC读数 ÷ 4096 × 3.3 ÷ 10 ÷ 0.1 = ADC读数 ÷ 4096 × 3.3。
有个工程细节需要提醒:LM358不是轨到轨运放,输出不可能真的到5V,接近正电源时它会饱和。好在我们的最大输出是2V,离5V还远,所以没问题。如果想把量程扩到5A或者10A,就要相应减小采样电阻并调整放大倍数,仍然遵循“满量程输出不超过ADC量程”的原则。
运放供电在仿真里直接给5V即可,但要注意运放的地和STM32的地必须共地,否则ADC读到的相对电压完全不正确。共地这个点很多人在仿真里忽略,到了实际项目接错真会炸板。
2.4 报警与OLED显示电路
报警部分选有源蜂鸣器,有源的意思内部自带震荡源,给电就响,不需要单片机输出PWM方波,软件上简单很多。但STM32的GPIO带不动蜂鸣器,直接推不仅声音小,还可能把IO口烧了。我用2N2222三极管做开关,GPIO接基极,蜂鸣器接集电极,发射极接地,GPIO输出高电平三极管导通、蜂鸣器得电发声。基极串联一个1kΩ限流电阻,保护GPIO。
OLED模块这边,SDA接PB7,SCL接PB6,这就是STM32F103的I2C1引脚。模块上一般自带I2C上拉电阻,不需要额外再接。I2C地址要注意,SSD1306在0x78和0x7A之间二选一,由模块的地址电阻决定,代码里初始化的从机地址必须和硬件一致,否则屏幕死活点不亮。仿真里如果找不到OLED模型,可以先不接屏幕,用I2C逻辑分析探针看数据波形,我在第4章会讲这个替代方案。
以上硬件方案全部确定之后,实际项目里可以直接照着搭,或者用面包板/立创EDA画板子再焊接。仿真阶段则直接在Proteus里连线配置,注意运放、采样电阻、分压电阻的标号别和实际板子的封装混淆。
3. 软件驱动与实现逻辑
3.1 工程结构和初始化顺序
软件部分我用标准库开发,虽然现在HAL库很流行,但这类纯外设控制的项目标准库代码更直观,结构也更好理解。工程框架无非就是初始化→主循环两大块,但初始化顺序有讲究:先时钟,再GPIO,再ADC和DMA,再I2C、OLED,再DS18B20,最后SysTick定时器。定时器放最后是因为它的回调一旦触发就开始跑,这时候其他外设必须已经就绪。
初始化顺序的底层逻辑是“先基础后应用”:时钟是所有外设的父资源,GPIO复用配置决定了引脚功能,ADC需要DMA搬运数据,I2C又是OLED的通信基础。DS18B20放在屏幕初始化之后,是因为调试时如果屏幕没亮,你就什么都看不见,白瞎。我的习惯是先把OLED点亮、显示一行测试字符,再读传感器,有问题能立刻定位是屏幕的问题还是传感器的问题。
主循环里不要写死循环轮询传感器。比较好的做法是用SysTick产生1秒中断,在中断里置一个采样标志位,主循环检测到标志位后做采集、换算、显示、报警判断。这样I2C、ADC这些操作不会被打断,也不会出现显示刷新一半被温度读取干扰的问题。主循环和中断各干各的,数据流非常清爽。
3.2 DS18B20读取代码与时序细节
单总线时序是微秒级别的事,所以代码里会出现很多delay_us()。我在延时上吃过亏:标准库里的Delay函数如果没开SysTick,延时数值根本不准确,所以务必先把SysTick的1us延时调好。读温度的整个流程分为两步:
第一步发启动转换命令:主机发复位脉冲(拉低480us,释放等待60us,引脚被DS18B20拉低表示存在应答),随后写0xCC跳过ROM,再写0x44启动温度转换。DS18B20开始转换后会自己忙一阵,12位精度下最多750ms,所以必须延时至少750ms。
第二步读数据:同样先发复位脉冲,再写0xCC,再写0xBE读暂存器,然后连续读两个字节的LSB和MSB。读到的16位原始数据,如果高5位全是1说明是负温度,实际温度等于原码按补码取反加一再乘0.0625。
核心代码结构大概是这样:
uint16_t DS18B20_ReadTemp(void) { uint8_t lsb, msb; int16_t raw; float temp; DS18B20_Reset(); DS18B20_WriteByte(0xCC); // 跳过ROM DS18B20_WriteByte(0x44); // 启动转换 Delay_us(1000); // 实际项目里这句会被750ms延时替代,这里简写 DS18B20_Reset(); DS18B20_WriteByte(0xCC); DS18B20_WriteByte(0xBE); // 读暂存器 lsb = DS18B20_ReadByte(); msb = DS18B20_ReadByte(); raw = (msb << 8) | lsb; temp = raw * 0.0625; // 12位分辨率下1LSB=0.0625℃ return (uint16_t)(temp * 10); // 返回实际温度×10,保留一位小数 }这里有个非常容易踩的坑:启动转换后的延时不是随便写个几百微秒就行,12位精度下最大转换时间750ms,你只等1ms就读数据,读回来的多半是上次的旧值,而且不是0x85就是0xFFFF。我自己最开始把延时写在主循环外面只调了一次,结果屏幕上温度一直不变,排查好久才发现是转换没完成就读取了。正确做法是启动转换后延时1秒再读,或者用状态机每秒钟查询一次“忙”状态。
3.3 ADC多通道采集、滤波与物理量换算
ADC配置我选了ADC1的通道1接电压(PA1)、通道2接电流(PA2),采用DMA循环传输模式。为什么用DMA,是因为ADC如果靠CPU逐次读取,CPU就得耗在等待转换完成上,主循环会被拖慢。DMA能把转换结果自动搬运到内存数组,CPU只管事后取值,效率完全不在一个量级。
初始化ADC时有几个关键参数:12位分辨率、右对齐、扫描模式打开、连续转换模式打开、DMA循环模式打开。DMA配置时外设基址填ADC1的数据寄存器,内存基址填一个长度为2的u16数组,方向是外设到内存,模式是循环。这样ADC每次转换完两个通道,数据自动进数组,主循环随时读到最新值。
换算代码很简单:
float Real_Voltage = (float)adc_buf[0] / 4096.0f * 3.3f / 0.25f; float Real_Current = (float)adc_buf[1] / 4096.0f * 3.3f / 10.0f / 0.1f;但裸读数直接换算的话,数值会像心电图一样上下跳,因为即使是仿真,ADC也有一点量化噪声,到了实际板子上电源纹波、电磁干扰会更夸张。因此我在主循环里对每个通道采集20次,去掉一个最大值和一个最小值再求平均,做一阶滑动滤波,这是成本最低、效果最好用的数字滤波方案。实测下来,电压显示能稳定在±0.05V以内,电流稳定在±0.02A以内,完全满足需求。
滤波后的数据就干净多了,显示到OLED上不会闪烁抖动,阈值判断也稳定。
3.4 OLED显示布局与刷新策略
SSD1306驱动起来不算复杂,初始化序列是固定的那一长串命令,照抄就能用。显示方式上,我用了全屏刷新,每秒钟更新一次,因为三行纯文本信息信息量不大,128×64的缓冲全刷一遍耗时也就几十毫秒,不影响整体性能。
显示布局我分成四块区域:第一行显示温度,比如“Temp: 25.3C”;第二行显示电压,比如“Volt: 12.04V”;第三行显示电流,比如“Curr: 1.25A”;第四行显示报警状态,正常时显示“Normal”,报警时显示“ALARM!”。
OLED驱动里有一个小技巧:显示浮点数时不要用sprintf库函数,标准库的printf会占用大量Flash和堆空间,C8T6虽然64KB Flash但还是能省则省。更稳妥的办法是把浮点数拆成整数和小数部分,用自己写的整数转字符函数拼到缓冲区。比如温度25.35,拆成整数25和小数35,再用自定义函数转成字符串填充。
显示刷新周期不用太频繁,1秒一次足够。太快反而会因为I2C总线被频繁占用,影响其他外设通信。OLED屏本身刷新率也就二三十赫兹,你给它一秒钟刷一百次,眼睛也看不出来差别,还给CPU徒增压力。
3.5 阈值报警逻辑与防抖设计
报警逻辑是整个项目最考验思路的部分。最直观的做法是某个值超过阈值就报警,低于阈值就复位,但这样做在实际系统中会出现临界点反复抖动:温度在50℃附近来回波动时,蜂鸣器一会儿响一会儿停,听着就烦人。
所以引入迟滞比较的思路:三个报警阈值分别设上限和复位下限,二者之间留一个回差区间。比如温度阈值50℃,上限到50℃时报警,复位下限设为46℃,也就是说温度必须低于46℃报警才解除。这样即使温度在50℃附近抖动,报警状态只有两个稳定的翻转点,不会出现快速切换现象。
报警判断代码用一个状态机比较好,每个通道有NORMAL和ALARM两个状态,状态转换只发生在“超过上限”或“低于复位下限”时。报警触发后,蜂鸣器由GPIO拉高持续发声,同时OLED第四行显示对应的报警内容。如果三个通道同时超限,优先显示最先超限的那个,其他报警信息滚动提示。
还要处理一个实际问题:报警要不要自锁?意思是超限报警后即使参数恢复正常,蜂鸣器仍然保持长鸣直到手动复位。在很多安全报警设备里自锁是必须的,因为操作员不能漏掉任何一次危险。我这个项目属于学习性质,做成自动复位的形式更直观,能在仿真里反复演示。如果你做的是安全监控类实际项目,建议加上按键自锁复位逻辑。
4. 仿真搭建与联调全流程
4.1 元件清单与Proteus环境准备
Proteus版本我建议用8.13以上,因为高版本里I2C OLED模型更友好。需要准备的元件清单用表格列出比较清楚。
| 元件 | Proteus关键字 | 数量 |
|---|---|---|
| STM32主控 | STM32F103C8 | 1 |
| 温度传感器 | DS18B20 | 1 |
| 上拉电阻 | RES 4.7kΩ | 若干 |
| 分压电阻 | RES 30kΩ、10kΩ | 各1 |
| 采样电阻 | RES 0.1Ω | 1 |
| 运放 | LM358 | 1 |
| 反馈/输入电阻 | RES 90kΩ、10kΩ | 各1 |
| 三极管 | 2N2222 | 1 |
| 蜂鸣器 | BUZZER | 1 |
| OLED(可选) | OLED 128x64 SSD1306(I2C) | 1 |
| 直流电源 | VSOURCE或VSRC | 按需 |
| 电位器 | POT-HG | 若干 |
仿真图上电阻标称值一定要和原理图一致,特别是0.1Ω采样电阻,Proteus里如果默认显示“RES”参数没改,仿真出来的电流值会完全不对。我犯过这个错,半天找不到问题,最后发现是采样电阻忘记从默认的1k改成0.1了。
4.2 完整接线与关键参数配置
按第2章的电路方案在Proteus里连线,这里有三个容易配错的参数:
第一是DS18B20的温度值参数。默认值可能是27℃,双击元件在属性面板里找“Temperature”或类似字段,改成模拟环境温度变化,比如从20℃改到60℃,屏幕上的温度读数会跟着变,方便你验证报警。仿真和真实模块不同,真实模块摸一下温度就变化,但仿真必须手动改参数。
第二是电压分压上端的电压源,我用一个可调电源VSRC,双击它可以改电压值,因为要模拟0~12V变化的场景,也可以串一个POT-HG电位器接稳压源,用鼠标拖动改变分压。
第三是电流电路里负载的位置。我一般用电位器做负载电阻,这样可以连续调节回路电流,观察电流显示值变化。负载必须和采样电阻串联,采样电阻放在负载和地之间,运放差分两端分别接采样电阻两端,共地点不能错。
STM32芯片上电后并不自动运行,需要先编译工程生成hex文件,再双击仿真图中的MCU加载hex路径,然后启动仿真。别忘了晶振频率,仿真里STM32默认时钟配置如果不对,延时函数会全部错乱,具体是在MCU属性里把外部晶振频率设置为8MHz,然后程序里配置PLL倍频到72MHz,和实际开发板保持一致。
4.3 分级联调步骤
联调是整件事里最值得耐心的环节。我自己的习惯是分级调试,一次只验证一个功能模块,不一口气把所有模块接上然后期待它们自动协奏。
第一步,先只接OLED显示模块,烧个初始化代码,屏上能显示固定字符代表I2C通信没问题;第二步,接DS18B20,读温度并显示到屏幕,改温度参数确认读数跟随变化;第三步,接ADC电压电路,用电压源改造输入,读数应该随电压成正比变化;第四步,接电流采样电路,改负载电阻,电流读数跟着变;第五步,把所有模块同时接入并设定阈值,验证报警与复位;最后一步,把所有内容整合在主循环里,确定刷新间隔、报警逻辑没有冲突。
每完成一级就停一下,确认现象符合预期再进入下一级。如果在某一级发现数据不对,直接在那一个小范围里排查,而不是面对一整块电路无从下手。这套“增量联调”的方法在仿真和真实硬件开发中都通用,做复杂项目能帮你把出错范围缩到最小。
4.4 仿真与硬件的差异说明
Proteus仿真再真实也是理想环境,最终目的是验证原理和代码,不是替代硬件调试。仿真里LM358是理想模型,不会出现实际芯片的输出饱和、失调电压、偏置电流问题;仿真里电源也没有纹波,不会产生真实板子上的毛刺干扰;仿真里ADC的参考电压就是绝对精准的3.3V,而实际板子用AMS1117输出的3.3V多少有点误差。这些差异意味着你仿真跑得通,不代表实物焊出来一次成功。
所以我的建议是:仿真验证的核心放“逻辑正确、参数计算正确、接线概念正确”上,而不是把显示数值绝对精确当成目标。换到实际硬件后,第一件事用万用表测各点电压,第二件事注意共地和电源滤波,第三件事给ADC输入脚加一个100nF去耦电容。做到这三点,仿真到实物的迁移成功率非常高。
5. 调试常见问题与解决思路
5.1 温度数据读不到或者固定偏差
现象是屏幕显示85℃或者FFFF。85℃是DS18B20复位失败后暂存器里的典型值,出现这个值说明器件没有正确应答。优先检查数据线上拉电阻是否忘记接、阻值是否正常,其次检查时序函数里几个延时是否准确,尤其是复位脉冲和读时隙的微秒延时。Proteus里仿真速度如果调得太快,也会导致微秒延时整体偏短,把仿真运行速度调回实时模式通常能缓解。
还有一个坑是GPIO模式没配好。DS18B20的数据引脚需要开漏输出模式,如果配置成推挽输出,读输入时序时读不到正确的低电平信号。我见过有人在代码里反复调延时,最后发现只是GPIO_Mode_Out_OD没设置。
5.2 ADC数值异常与显示偏差
ADC读数全为4095或者全为0,一般不是程序问题,而是电路问题。读数全为4095说明输入超量程,你给ADC引脚电压高于3.3V了,检查分压比;读数全为0,基本是引脚没接对,或者GPIO没有配置成模拟输入模式。STM32的ADC引脚初始化必须设成ADC_Mode的模拟输入,不是普通GPIO输入。
换算偏差比较隐晦,经常出现实际电压和表显电压差固定的倍数。比如万用表测12V系统,OLED显示3V左右,那不是换算公式错误,而是你忘记了分压比的倒乘。解决办法是重新对照标定的物理量:先只测2V、6V、10V三个点,记录ADC读数和显示值,三点连成直线检查斜率与截距。
5.3 报警不响应或临界误触发
报警不响应一般不是GPIO问题,而是判断逻辑的变量类型问题。我在做的时候把物理量定义成float同时用等号比较,结果因为浮点精度问题导致边界值永远碰不到。后来把所有阈值比较改为带小数位的宽容比较,比如大于等于阈值减0.05,问题就消失了。
临界误触发是迟滞设计没做好导致的。如果阈值上下限之间回差太小,甚至没有回差,那么任何数值微小抖动都会反复翻转报警。仿真里做起来其实非常明显:你把输入电压调到阈值附近,鼠标稍微动一下电位器,蜂鸣器就“嘀嘀嘀”连环响。解决办法就是第3.5节里的迟滞区间,每个通道都给一个合理回差,比如电压阈值11.0V,复位下限10.5V;电流阈值1.5A,复位下限1.3A。
5.4 OLED显示异常
最常见的OLED不亮,几乎都是I2C地址问题。扫描一遍仿真里OLED元件的地址,是0x78还是0x7A,同时检查代码里的初始化命令序列是否完整。SSD1306初始化的命令序列将近10条,漏掉一条就会白屏或花屏。
还有一个容易忽略的细节是OLED供电电压。SSD1306有3.3V和5V版本,仿真里如果选成了5V模块但用3.3V供电,屏幕亮度会很低或者完全没反应。你可以在Proteus库属性里检查模块的额定电压。实际项目中,这个坑我会顺手写在PCB的标号注释里以提醒自己。
我把这个项目完整做完之后,最大的一个感受就是:这类综合题目的难点根本不在某个具体传感器怎么读,而在于你有没有能力把整条数据流理顺。温度、电压、电流三条路虽然物理信号不同,但到了软件层全部收敛成“ADC/单总线读数→滤波→标度变换→显示→判断”这个统一模式。建议你自己动手时,先画一张信号流向图,把每个环节的输入输出、计算公式、阈值设定写清楚,再开始写代码和接线。仿真通过只是第一关,换到真实板子上的时候,多留一分耐心给供电和地线,你会少踩很多坑。如果后续有时间,这项目还可以扩展成带按键阈值设定、串口把数据上传电脑、甚至通过WiFi模块做远程监控的版本,硬件基础都是一样的,主要工作量在通信协议的扩展上。