基于单片机的多路热电偶温度监测与报警器

  1. 基于单片机的多路热电偶温度监测与报警器
    点击链接下载protues仿真设计资料:https://download.csdn.net/download/m0_51061483/92081542

  1. 系统概述

2.1 设计背景与应用场景

在工业生产、实验室环境、食品加工、医疗恒温设备、环境监测等应用中,温度不仅需要实时采集,还需要在温度异常时迅速发出报警提示,以避免设备损坏、材料变质或实验失败。传统的单点温度检测无法满足多测点分布式监控需求,而多路温度监测系统可以同时对多个关键位置进行监控,提高可靠性与安全性。

本系统以单片机为核心控制器,采用 4 路 N 型热电偶作为温度传感器,结合热电偶专用转换模块,实现 0~100℃ 温度范围内的实时监测,并支持为每一路独立设置上下限报警阈值。当任意一路温度超出设定范围时,系统将触发蜂鸣器与 LED 进行声光报警,并在显示屏上提示异常通道与报警类型(高温/低温)。

2.2 系统总体目标

系统实现以下主要目标:

1)完成 4 路 N 型热电偶温度采集并实时显示;

2)支持按键设置每路温度上下限报警值,并可保存;

3)当温度越界时蜂鸣器与 LED 声光报警;

4)在 0~100℃ 范围内保证较高测量稳定性与精度,低温区精度更高;

5)系统运行稳定,具备抗干扰能力与良好的人机交互体验。


  1. 系统功能设计

3.1 四路温度采集与实时显示

系统通过热电偶转换模块将 N 型热电偶的毫伏级热电势转换为数字温度值。主控单片机周期性读取四路温度数据,并对采集结果进行滤波、校准和单位转换,最终显示在屏幕上。显示内容包括:

  • CH1~CH4 温度实时值(单位 ℃)
  • 每路的报警状态(正常/高报警/低报警)
  • 当前设置模式提示(若进入阈值设置)

由于热电偶信号非常微弱且易受噪声影响,本系统在采样与软件处理上采用了多种抗干扰方法,例如移动平均滤波、异常值抑制、采样延时与屏蔽设计等,以提高显示稳定性。

3.2 按键设置上下限报警值

系统提供按键进行参数设置,支持为四路通道分别设定:

  • 上限报警值 HighLimit[i]
  • 下限报警值 LowLimit[i]

设置流程一般为:

  • 按"设置"键进入设置模式
  • 按"通道"键选择 CH1~CH4
  • 按"项目"键切换上下限
  • 按"加/减"键调整数值
  • 按"确认"键保存并退出

每一路通道的阈值独立存储,断电后可通过 EEPROM/Flash 读取恢复。

3.3 越限声光报警

当任意一路温度满足以下条件:

  • T[i] > HighLimit[i]:高温报警
  • T[i] < LowLimit[i]:低温报警

系统立即触发:

  • 蜂鸣器鸣叫(可采用间歇或连续鸣叫策略)
  • 对应 LED 点亮或闪烁
  • 显示屏给出报警通道与报警类型提示

为了避免温度临界点抖动频繁报警,系统可设计报警回差(Hysteresis),例如:

  • 高温报警触发点 HighLimit
  • 高温恢复点 HighLimit - Hys
  • 低温报警触发点 LowLimit
  • 低温恢复点 LowLimit + Hys

这样可以减少误触发,提升报警可靠性。

3.4 测温特性说明(0~100℃)

N 型热电偶在低温区(特别是 0~50℃)线性较好,配合冷端补偿与数字化转换模块可获得较高精度。随着温度升高,热电偶输出电压的变化率与非线性特性会导致误差增大,此外放大器漂移、冷端补偿误差和环境噪声对高温区影响更明显,因此系统在高温区误差相对增大属于合理特性。

本系统重点优化低温段精度,适用于 0~100℃ 温控/监测应用。


  1. 系统电路设计

4.1 电路设计总体结构

系统硬件电路可划分为以下模块:

1)单片机主控模块

2)4 路 N 型热电偶传感器与接口模块

3)热电偶信号调理/转换模块(带冷端补偿)

4)显示模块

5)按键输入模块

6)声光报警模块(蜂鸣器 + LED)

7)存储模块(EEPROM/内部 Flash)

8)电源模块与稳压/滤波

9)抗干扰与保护设计模块

各模块通过标准数字通信(SPI/I2C/GPIO)与主控相连,形成稳定可靠的多路测温与报警系统。


4.2 单片机主控模块

4.2.1 主控芯片选择与作用

单片机作为系统核心,负责:

  • 采集四路温度数据
  • 扫描按键输入
  • 控制显示刷新
  • 判断报警条件并控制蜂鸣器与 LED
  • 保存与读取报警阈值参数
  • 执行滤波、校准等算法

常见选择包括:

  • 8051 系列(如 STC、Nuvoton)
  • AVR(如 ATmega328P)
  • STM32(Cortex-M0/M3/M4)

本系统不限定具体型号,但应满足:

  • 至少具备 SPI 或 I2C 接口(用于热电偶转换模块、显示模块)
  • 足够的 GPIO(按键、LED、蜂鸣器控制)
  • 稳定的定时器资源(周期采样、蜂鸣器节奏控制)
  • 具备 EEPROM 或可用 Flash 模拟 EEPROM(存储阈值)

4.2.2 时钟电路

为保证采样与显示刷新稳定,单片机可使用:

  • 外部晶振(如 8MHz/16MHz) + 两个匹配电容
  • 内部 RC 时钟(精度稍低,但足够)

若系统用于工业场景且需要更精准的采样周期,建议使用外部晶振。

4.2.3 复位电路

复位电路确保系统上电后进入确定状态。常用方式:

  • RC 上电复位(电阻+电容)
  • 复位按钮 + 上拉电阻
  • 监控芯片(若对可靠性要求高)

4.2.4 下载/调试接口

可预留 ISP/SWD/UART 接口,便于程序下载、参数校准与调试输出。

例如:

  • 8051:串口 ISP
  • STM32:SWD + 串口日志

4.3 四路 N 型热电偶传感器与接口模块

4.3.1 N 型热电偶简介

N 型热电偶属于镍铬硅/镍硅热电偶,具有:

  • 良好的抗氧化能力
  • 相对稳定的热电势输出
  • 适用于较宽温度范围
    本系统工作范围为 0~100℃,属于热电偶较低温应用段。

4.3.2 热电偶接线与接口保护

热电偶信号微弱,接线应注意:

  • 使用热电偶专用补偿导线,避免引入额外热电势
  • 接口处使用端子台或专用插座,保证可靠接触
  • 增加 ESD/浪涌保护(TVS 二极管或输入保护电路)
  • 采用屏蔽线并单点接地,降低工频与电磁干扰

4.3.3 通道隔离与布局建议

四路热电偶应尽量:

  • 走线短
  • 远离开关电源、蜂鸣器、电机等强干扰源
  • 模拟前端区域单独布线并铺地
  • 接口旁预留 RC 滤波或共模滤波器位置

这样可以显著减少热电偶测量抖动,提高低温段精度。


4.4 热电偶信号调理/转换模块(带冷端补偿)

4.4.1 为什么需要转换模块

热电偶输出为毫伏级电压,并且与温度呈非线性关系。如果直接用单片机 ADC 测量,需要高精度放大器、精密 ADC、冷端补偿温度传感器以及复杂的软件线性化计算,系统复杂且误差难控。

因此本系统采用热电偶专用转换模块(常见如 MAX31856、MAX31855、AD849x 等方案),它们集成了:

  • 高精度放大与 ADC
  • 冷端补偿
  • 热电偶类型选择
  • 数字输出接口(SPI/I2C)

这样可以大幅降低硬件设计难度并提升精度稳定性。

4.4.2 四路实现方式

实现四路热电偶采集通常有两种方案:

  • 方案 A:4 个独立转换芯片
    每路热电偶对应一个转换芯片,优点是通道独立、互不影响,软件逻辑清晰;缺点是成本略高。
  • 方案 B:多路复用 + 单个高精度转换
    通过模拟开关/多路复用器轮询热电偶,再由同一个转换模块处理。优点是成本低;缺点是设计复杂,对切换瞬态与补偿误差要求高。

本系统建议采用方案 A,能更好保证低温段精度与稳定性。

4.4.3 通信接口电路(SPI/I2C)

转换模块一般通过 SPI 或 I2C 与单片机通信,电路设计要点:

  • SCK/MOSI/MISO/CS(SPI)或 SCL/SDA(I2C)走线短且加上上拉/串联电阻(视需要)
  • 电平兼容:单片机与转换芯片电压一致(如 3.3V)
  • 若采用 5V 单片机,需要电平转换电路
  • 通道 CS 独立(SPI 多从机)

4.4.4 冷端补偿说明

热电偶测量的是"测量端与冷端的温差",必须知道冷端温度才能计算实际温度。转换模块内部集成冷端温度传感器,并自动完成补偿。

注意:冷端补偿的准确性与芯片周围温度一致性有关,因此 PCB 布局应保证:

  • 转换芯片远离发热源
  • 采用良好接地与铜皮散热,使芯片温度更接近接线端温度
  • 避免大电流走线经过芯片附近

4.5 显示模块

4.5.1 显示器类型选择

常见显示模块包括:

  • 1602/2004 字符 LCD
  • OLED(0.96/1.3 英寸,I2C/SPI)
  • TFT 彩屏(SPI/并口)

本系统显示内容主要为温度数值与报警状态,使用 1602/2004 LCD 或 OLED 即可。

4.5.2 显示内容组织建议

为了实现直观显示,可采用多页显示:

  • 页面 1:CH1、CH2 温度 + 状态
  • 页面 2:CH3、CH4 温度 + 状态
    或使用大屏 OLED 一页显示 4 路:
  • CH1: xx.x℃
  • CH2: xx.x℃
  • CH3: xx.x℃
  • CH4: xx.x℃
    并在异常时在对应行增加 "HI/LO/!" 标记。

4.5.3 接口电路与注意事项

  • I2C OLED:需要 SCL/SDA 上拉电阻(如 4.7k)
  • LCD 并口:需要更多 GPIO,并注意电源去耦
  • 背光电流较大时注意供电能力与噪声

4.6 按键输入模块

4.6.1 按键类型与数量规划

本系统常用 4~5 个按键:

  • SET:进入/退出设置
  • CH:通道选择
  • ITEM:上下限选择
  • UP:数值增加
  • DOWN:数值减少
    (可选 OK/保存键,也可用 SET 长按保存)

4.6.2 硬件消抖与软件消抖

按键抖动会导致误触发,硬件上可加入 RC 滤波,但更常见的是软件消抖:

  • 周期扫描按键(如 10ms)
  • 连续检测稳定状态达到阈值才认为有效
  • 支持短按与长按(长按加速调节)

4.6.3 按键连接方式

  • 上拉输入:GPIO 上拉电阻,按键按下接地
  • 下拉输入:GPIO 下拉电阻,按键按下接 VCC
    建议使用上拉输入方式,抗干扰更好且节省电阻(可用内部上拉)。

4.7 声光报警模块(蜂鸣器 + LED)

4.7.1 蜂鸣器驱动电路

蜂鸣器分为有源与无源:

  • 有源蜂鸣器:输入高电平即可鸣叫,驱动简单
  • 无源蜂鸣器:需要 PWM 或方波驱动,可控制音调

为了实现报警提示,本系统建议使用有源蜂鸣器,并通过 NPN 三极管或 MOSFET 进行驱动,避免单片机 IO 直接带载:

  • IO 输出控制三极管导通
  • 蜂鸣器接 VCC
  • 三极管发射极接地
  • 若为电感性负载,需并联续流二极管(部分蜂鸣器可省略,但加上更稳妥)

4.7.2 LED 指示电路

LED 可分为:

  • 系统运行指示(心跳灯)
  • 报警指示(红灯闪烁)

LED 需要串联限流电阻(如 330Ω~1kΩ)。报警时可让 LED 闪烁,以提高提醒效果。

若需要对应每路独立 LED,也可设置 4 个通道报警 LED,更直观定位异常通道。

4.7.3 报警策略设计

建议的报警策略:

  • 有一路越界:蜂鸣器间歇鸣叫(例如 200ms 响、800ms 停)
  • 多路越界:蜂鸣器快速间歇鸣叫,LED 快闪
  • 报警解除:蜂鸣器停止,LED 恢复正常状态

4.8 存储模块(EEPROM/内部 Flash)

4.8.1 存储内容

需保存的参数主要包括:

  • CH1~CH4 上限阈值 HighLimit
  • CH1~CH4 下限阈值 LowLimit
  • 报警回差 Hys(可选)
  • 显示模式与单位设置(可选)

4.8.2 存储器选择

  • 外置 I2C EEPROM(如 24C02/24C08)
  • 单片机内部 EEPROM(部分 MCU 自带)
  • Flash 模拟 EEPROM(STM32 常用)

4.8.3 写入策略与寿命保护

EEPROM 有写入寿命限制,因此建议:

  • 仅在用户按确认键后写入
  • 写入前检测参数变化,若无变化不写入
  • 可加入校验字节,防止掉电导致数据损坏

4.9 电源模块与稳压/滤波

4.9.1 供电方案

系统可由:

  • 5V USB 供电
  • 12V/24V 外部适配器 + 降压模块
  • 电池供电(若需要便携)

若热电偶转换芯片与 OLED 使用 3.3V,则需要稳压输出 3.3V。可采用 LDO 或 DC-DC。

4.9.2 滤波与去耦

为了保证热电偶低电平测量稳定,必须重视电源品质:

  • 每个芯片电源引脚附近放置 0.1uF 去耦电容
  • 电源入口放置 10uF~100uF 电解/钽电容
  • 模拟/数字地合理分区,单点汇接
  • 蜂鸣器等大电流负载建议单独走线并加滤波

4.10 抗干扰与安全保护设计

4.10.1 信号屏蔽与接地

热电偶线优先使用屏蔽线,并将屏蔽层单端接地,减少地环路干扰。PCB 采用完整地平面可降低噪声。

4.10.2 ESD 与浪涌保护

热电偶接口与按键接口可能被人体触碰,应加入:

  • TVS 二极管
  • 串联电阻/磁珠
  • RC 滤波

4.10.3 软件抗干扰措施

  • 温度数据滤波与异常值丢弃
  • 看门狗复位防死机
  • 参数存储校验防止错误读写
  • 报警回差避免临界抖动

  1. 程序设计

5.1 软件总体架构

5.1.1 程序结构划分

系统软件可划分为以下模块:

1)系统初始化模块

2)温度采集模块(4 路)

3)数据滤波与校准模块

4)显示管理模块

5)按键扫描与人机交互模块

6)报警判断与执行模块

7)参数存储管理模块

8)定时调度与主循环模块

整体运行方式推荐采用"主循环 + 定时任务"结构:

  • 定时器中断提供 1ms/10ms 节拍
  • 主循环根据标志位执行采样、显示刷新、按键处理等任务
  • 避免在中断中执行耗时操作,提升系统实时性和稳定性

5.1.2 任务周期建议

  • 按键扫描:10ms
  • 温度采样:200ms~500ms(根据需要调整)
  • 显示刷新:200ms(OLED 可更快,LCD 可更慢)
  • 报警判断:每次采样后立即判断
  • 蜂鸣器节奏:由 10ms 节拍控制

5.2 系统初始化模块

5.2.1 硬件初始化内容

  • GPIO 初始化(按键输入、蜂鸣器、LED 输出)
  • SPI/I2C 初始化(温度模块、显示模块)
  • 定时器初始化(周期节拍)
  • 看门狗初始化(可选)
  • 读取存储参数(阈值、回差)
  • 初始化显示界面并提示系统启动

5.2.2 默认阈值策略

若检测到 EEPROM 参数无效(校验失败),系统应加载默认值:

  • LowLimit:0℃
  • HighLimit:100℃
    或更安全的默认范围,例如 10℃~80℃,避免误报警。

5.3 温度采集模块

5.3.1 采集流程

对每路通道执行以下步骤:

1)选择对应的转换芯片(SPI CS 拉低)

2)读取温度寄存器或数据帧

3)解析温度值(可能包含符号位、小数位)

4)转换为摄氏温度浮点或定点格式

5)存入温度数组 Temp[i]

5.3.2 采样数据格式设计

为了降低单片机资源消耗,推荐使用"定点数"表示温度:

  • 例如以 0.1℃ 为单位存储:253 表示 25.3℃
    这样可以避免频繁浮点运算,提高速度。

5.3.3 异常检测

热电偶可能出现开路、短路或反接,转换芯片通常会提供故障标志位。软件应检测:

  • 传感器断线:显示 "OPEN" 并报警或提示
  • 读数异常:忽略并保留上次有效值
  • 通道故障:允许用户确认后关闭该通道报警(可选扩展)

5.4 数据滤波与校准模块

5.4.1 滤波必要性

热电偶测量受噪声影响,尤其在低温段,显示波动会影响用户判断,因此必须进行滤波。

5.4.2 移动平均滤波

对每一路维护一个长度 N 的采样队列,例如 N=5:

  • 新值入队
  • 计算平均值作为显示值
    移动平均能有效抑制随机噪声,适用于温度缓慢变化场景。

5.4.3 中值滤波与异常值抑制

当系统可能受到突发干扰导致瞬间跳变,可加入:

  • 若当前值与上一次差值大于阈值(如 20℃),判为异常并丢弃
  • 或采用 3 点中值滤波,抵抗尖峰噪声

5.4.4 校准方式

可提供软件校准系数:

  • TempCal[i] = TempRaw[i] + Offset[i]
    Offset[i] 可在出厂时测量并写入 EEPROM,使 4 路一致性更好。
    由于系统强调低温段精度,校准可在 25℃ 与 80℃ 两点标定,或仅在常用温区做偏移校准即可。

5.5 显示管理模块

5.5.1 显示刷新机制

显示模块不应每毫秒刷新,否则占用总线资源并影响采样。建议:

  • 每 200ms 刷新一次屏幕
  • 当进入设置模式时可提升刷新频率,以便用户操作更流畅

5.5.2 界面状态机设计

界面可分为:

  • 正常显示界面
  • 设置界面(选择通道)
  • 设置界面(选择上下限)
  • 设置界面(数值调整)
  • 保存提示界面

使用状态机能使界面逻辑清晰,避免大量 if-else 混乱。

5.5.3 报警提示显示

在发生报警时,界面建议突出显示:

  • 报警通道闪烁
  • 显示 "HI" 或 "LO" 标识
  • 若多路报警,循环显示或同时显示标记

5.6 按键扫描与交互模块

5.6.1 按键扫描实现思路

每 10ms 扫描一次所有按键,记录:

  • 当前电平
  • 上一次电平
  • 稳定计数器
    当计数器达到阈值(如连续 3 次相同)则确认按下/释放事件。

5.6.2 短按、长按与加速调节

在阈值设置时,UP/DOWN 可以支持:

  • 短按:+0.1℃ 或 +1℃
  • 长按:连续快速增加/减少(例如每 100ms 变化一次)
    这样用户设置更方便。

5.6.3 参数限制与合理范围

为防止设置错误,建议限制:

  • LowLimit 最小值:0℃
  • HighLimit 最大值:100℃
  • LowLimit < HighLimit
    若用户设置冲突,系统可自动纠正或提示"ERR"。

5.7 报警判断与执行模块

5.7.1 报警判断逻辑

每次获得滤波后的温度值后,执行:

  • 若 Temp[i] > HighLimit[i] → AlarmHigh[i]=1
  • 若 Temp[i] < LowLimit[i] → AlarmLow[i]=1
    并结合回差判断解除条件。

5.7.2 报警输出控制

系统维护一个全局报警标志:

  • AnyAlarm = AlarmHigh 或 AlarmLow 任意为真

若 AnyAlarm=1:

  • 蜂鸣器进入报警节奏
  • LED 闪烁
    否则:
  • 蜂鸣器关闭
  • LED 恢复正常(如心跳灯)

5.7.3 报警保持与静音设计(可选)

为了提高用户体验,可设计:

  • 报警保持:报警发生后保持提示一段时间
  • 静音键:用户按下后蜂鸣器静音,但 LED 仍提示
  • 若温度恢复正常则自动退出报警
    这些属于可扩展功能,但结构上可以预留。

5.8 参数存储管理模块

5.8.1 数据结构设计

建议使用结构体管理参数:

  • uint16_t high[4]
  • uint16_t low[4]
  • uint16_t hys
  • uint8_t checksum

5.8.2 校验机制

可采用简单校验:

  • 所有字节求和取低 8 位
    或 CRC8/CRC16
    读取时校验失败则加载默认参数并提示用户。

5.8.3 写入时机

只在以下情况写入:

  • 用户确认保存
  • 参数发生改变
    这样能大幅延长 EEPROM 寿命。

5.9 定时调度与主循环模块

5.9.1 节拍与任务标志位

使用定时器产生 1ms 中断,在中断内:

  • 计数并产生 10ms 标志:key_task
  • 计数并产生 200ms 标志:temp_task、display_task
  • 控制蜂鸣器节奏:buzzer_task

主循环中根据标志位执行对应任务,形成良好的软实时系统。

5.9.2 看门狗设计

在主循环末尾喂狗,如果程序卡死则自动复位。对长期运行系统非常重要。


  1. 程序示例代码(模块化示例)
c 复制代码
#include <stdint.h>
#include <stdbool.h>

/* =========================
   参数与宏定义
   ========================= */
#define CH_NUM          4
#define TEMP_MIN_X10    0       // 0.0℃
#define TEMP_MAX_X10    1000    // 100.0℃
#define DEFAULT_LOW     0       // 0.0℃
#define DEFAULT_HIGH    1000    // 100.0℃
#define DEFAULT_HYS     5       // 0.5℃ 回差

/* =========================
   全局变量
   ========================= */
volatile uint32_t g_ms = 0;
volatile bool flag_10ms = false;
volatile bool flag_200ms = false;

int16_t temp_raw_x10[CH_NUM] = {0};
int16_t temp_filt_x10[CH_NUM] = {0};

uint16_t low_limit_x10[CH_NUM]  = {DEFAULT_LOW, DEFAULT_LOW, DEFAULT_LOW, DEFAULT_LOW};
uint16_t high_limit_x10[CH_NUM] = {DEFAULT_HIGH, DEFAULT_HIGH, DEFAULT_HIGH, DEFAULT_HIGH};
uint16_t hys_x10 = DEFAULT_HYS;

bool alarm_hi[CH_NUM] = {0};
bool alarm_lo[CH_NUM] = {0};
bool any_alarm = false;

/* =========================
   硬件抽象接口(需用户实现)
   ========================= */
// SPI/I2C 读取某一路热电偶转换芯片温度,返回 0.1℃单位
extern bool Thermo_ReadTempX10(uint8_t ch, int16_t *out_temp_x10);

// 显示接口
extern void Display_ShowNormal(int16_t t0, int16_t t1, int16_t t2, int16_t t3,
                               bool a0, bool a1, bool a2, bool a3);

// 按键扫描接口:返回按键事件(用户可用枚举表示)
typedef enum {
    KEY_NONE = 0,
    KEY_SET,
    KEY_CH,
    KEY_ITEM,
    KEY_UP,
    KEY_DOWN,
    KEY_OK
} key_event_t;

extern key_event_t Key_ScanEvent10ms(void);

// 蜂鸣器与 LED 控制
extern void Buzzer_On(void);
extern void Buzzer_Off(void);
extern void LED_AlarmOn(void);
extern void LED_AlarmOff(void);
extern void LED_HeartbeatToggle(void);

// EEPROM/Flash 参数读写接口
extern bool Param_Load(uint16_t low[CH_NUM], uint16_t high[CH_NUM], uint16_t *hys);
extern bool Param_Save(uint16_t low[CH_NUM], uint16_t high[CH_NUM], uint16_t hys);

/* =========================
   简单移动平均滤波(N=5)
   ========================= */
#define AVG_N 5
static int16_t avg_buf[CH_NUM][AVG_N] = {0};
static uint8_t avg_idx = 0;

static int16_t Filter_MovingAvg(uint8_t ch, int16_t new_x10)
{
    avg_buf[ch][avg_idx] = new_x10;
    int32_t sum = 0;
    for (uint8_t i = 0; i < AVG_N; i++) sum += avg_buf[ch][i];
    return (int16_t)(sum / AVG_N);
}

static void Filter_UpdateAll(void)
{
    for (uint8_t ch = 0; ch < CH_NUM; ch++) {
        temp_filt_x10[ch] = Filter_MovingAvg(ch, temp_raw_x10[ch]);
    }
    avg_idx++;
    if (avg_idx >= AVG_N) avg_idx = 0;
}

/* =========================
   报警判断(带回差)
   ========================= */
static void Alarm_CheckAll(void)
{
    any_alarm = false;

    for (uint8_t ch = 0; ch < CH_NUM; ch++) {
        int16_t t = temp_filt_x10[ch];

        // 高温报警
        if (!alarm_hi[ch]) {
            if (t > (int16_t)high_limit_x10[ch]) alarm_hi[ch] = true;
        } else {
            if (t < (int16_t)(high_limit_x10[ch] - hys_x10)) alarm_hi[ch] = false;
        }

        // 低温报警
        if (!alarm_lo[ch]) {
            if (t < (int16_t)low_limit_x10[ch]) alarm_lo[ch] = true;
        } else {
            if (t > (int16_t)(low_limit_x10[ch] + hys_x10)) alarm_lo[ch] = false;
        }

        if (alarm_hi[ch] || alarm_lo[ch]) any_alarm = true;
    }
}

/* =========================
   蜂鸣器节奏控制(间歇鸣叫)
   ========================= */
static void Alarm_OutputTask10ms(void)
{
    static uint16_t buz_cnt = 0;
    static bool buz_state = false;

    if (!any_alarm) {
        Buzzer_Off();
        LED_AlarmOff();
        buz_cnt = 0;
        buz_state = false;
        return;
    }

    LED_AlarmOn();

    // 200ms 响 + 800ms 停(周期 1000ms)
    buz_cnt += 10;
    if (buz_cnt <= 200) {
        if (!buz_state) { Buzzer_On(); buz_state = true; }
    } else if (buz_cnt <= 1000) {
        if (buz_state) { Buzzer_Off(); buz_state = false; }
    } else {
        buz_cnt = 0;
    }
}

/* =========================
   温度采样任务(200ms)
   ========================= */
static void Temp_SampleTask200ms(void)
{
    for (uint8_t ch = 0; ch < CH_NUM; ch++) {
        int16_t t;
        if (Thermo_ReadTempX10(ch, &t)) {
            // 异常值抑制:限制在 0~100℃
            if (t < TEMP_MIN_X10) t = TEMP_MIN_X10;
            if (t > TEMP_MAX_X10) t = TEMP_MAX_X10;
            temp_raw_x10[ch] = t;
        }
        // 若读取失败,可保留上次值或做断线处理扩展
    }

    Filter_UpdateAll();
    Alarm_CheckAll();
}

/* =========================
   显示任务(200ms)
   ========================= */
static void Display_Task200ms(void)
{
    bool a0 = alarm_hi[0] || alarm_lo[0];
    bool a1 = alarm_hi[1] || alarm_lo[1];
    bool a2 = alarm_hi[2] || alarm_lo[2];
    bool a3 = alarm_hi[3] || alarm_lo[3];

    Display_ShowNormal(temp_filt_x10[0], temp_filt_x10[1], temp_filt_x10[2], temp_filt_x10[3],
                       a0, a1, a2, a3);
}

/* =========================
   参数加载(启动时)
   ========================= */
static void Param_Init(void)
{
    uint16_t low[CH_NUM], high[CH_NUM], hys;
    if (Param_Load(low, high, &hys)) {
        for (uint8_t i = 0; i < CH_NUM; i++) {
            low_limit_x10[i]  = low[i];
            high_limit_x10[i] = high[i];
        }
        hys_x10 = hys;
    } else {
        // 加载失败,使用默认值
        for (uint8_t i = 0; i < CH_NUM; i++) {
            low_limit_x10[i]  = DEFAULT_LOW;
            high_limit_x10[i] = DEFAULT_HIGH;
        }
        hys_x10 = DEFAULT_HYS;
    }
}

/* =========================
   简化的设置逻辑(示例)
   ========================= */
static void UI_Task10ms(void)
{
    static bool in_setting = false;
    static uint8_t sel_ch = 0;
    static bool sel_high = true; // true=high, false=low

    key_event_t ev = Key_ScanEvent10ms();
    if (ev == KEY_NONE) return;

    if (!in_setting) {
        if (ev == KEY_SET) {
            in_setting = true;
            sel_ch = 0;
            sel_high = true;
        }
        return;
    }

    // 设置模式
    if (ev == KEY_SET) {
        // 退出不保存
        in_setting = false;
        return;
    }

    if (ev == KEY_CH) {
        sel_ch = (sel_ch + 1) % CH_NUM;
    } else if (ev == KEY_ITEM) {
        sel_high = !sel_high;
    } else if (ev == KEY_UP) {
        if (sel_high) {
            if (high_limit_x10[sel_ch] < TEMP_MAX_X10) high_limit_x10[sel_ch] += 1;
        } else {
            if (low_limit_x10[sel_ch] < TEMP_MAX_X10) low_limit_x10[sel_ch] += 1;
        }
    } else if (ev == KEY_DOWN) {
        if (sel_high) {
            if (high_limit_x10[sel_ch] > TEMP_MIN_X10) high_limit_x10[sel_ch] -= 1;
        } else {
            if (low_limit_x10[sel_ch] > TEMP_MIN_X10) low_limit_x10[sel_ch] -= 1;
        }
    } else if (ev == KEY_OK) {
        // 保存并退出
        Param_Save(low_limit_x10, high_limit_x10, hys_x10);
        in_setting = false;
    }

    // 约束逻辑:low < high
    if (low_limit_x10[sel_ch] >= high_limit_x10[sel_ch]) {
        if (sel_high) high_limit_x10[sel_ch] = low_limit_x10[sel_ch] + 1;
        else low_limit_x10[sel_ch] = high_limit_x10[sel_ch] - 1;
    }
}

/* =========================
   定时器中断(1ms)
   ========================= */
void SysTick_ISR_1ms(void)
{
    g_ms++;
    if (g_ms % 10 == 0)  flag_10ms = true;
    if (g_ms % 200 == 0) flag_200ms = true;
}

/* =========================
   主函数
   ========================= */
int main(void)
{
    // 用户需补充:硬件初始化(GPIO/SPI/I2C/Timer/Display)
    Param_Init();

    while (1) {
        if (flag_10ms) {
            flag_10ms = false;
            UI_Task10ms();
            Alarm_OutputTask10ms();
            LED_HeartbeatToggle();
        }

        if (flag_200ms) {
            flag_200ms = false;
            Temp_SampleTask200ms();
            Display_Task200ms();
        }

        // 可选:喂狗
    }
}

  1. 系统精度与误差分析

7.1 低温段精度较高的原因

在 0~50℃ 范围内,热电偶输出电压变化较为稳定,环境热梯度较小,冷端补偿误差相对可控,配合滤波与校准,系统可获得更高精度。此时测量噪声主要来自电源纹波和 EMI,通过良好硬件布局与软件滤波即可有效抑制。

7.2 高温段误差相对增大的原因

在 50~100℃ 范围内:

  • 热电偶非线性更明显
  • 热电偶线材与接线端温差更大,冷端补偿更敏感
  • 环境干扰与 PCB 温升可能导致转换芯片冷端温度读数偏差
  • 放大器/ADC 漂移对高温段影响更明显
    因此高温段误差相对增大是由多因素叠加导致的。通过加强冷端区域散热设计、提高供电稳定性、增加校准点、适当降低采样频率(减少噪声)等方式可进一步改善。

7.3 提升精度的工程措施建议

  • 采用高精度热电偶转换芯片并保证其参考温度稳定
  • 优化 PCB:模拟地与数字地规划、短走线、远离高电流区域
  • 热电偶接口使用屏蔽线与单点接地
  • 软件端采用滤波 + 异常值抑制 + 校准偏移
  • 为每路通道预留独立校准偏移参数,提高一致性

  1. 总结

本系统以单片机为核心,通过 4 路 N 型热电偶实现 0~100℃ 温度范围的实时监测与显示,并支持为每路设置上下限报警阈值。当温度越界时,系统通过蜂鸣器与 LED 实现声光报警提示,从而满足多点温度安全监控需求。硬件部分采用热电偶专用转换模块实现高精度采集与冷端补偿,并配合良好的电源滤波、接口保护和抗干扰布局保证测量稳定性;软件部分采用模块化结构,实现温度采样、滤波校准、显示管理、按键交互、报警控制以及参数存储等功能,使系统具备良好的可靠性、可维护性与扩展性。通过合理的报警回差策略与人机交互设计,系统能够在工业与实验场景中稳定运行,尤其在低温区具有更高精度表现,满足多路温度监测与报警的实际应用需求。

相关推荐
qq_455760852 小时前
redis - 事务
数据库·redis·缓存
大巨头2 小时前
SQL Server 完整锁类型详解
数据库
Archie_IT2 小时前
基于STM32F103C8T6标准库的OLED显示屏中文汉字显示实现_资料编号39
stm32·单片机·嵌入式硬件·mcu·硬件工程·信息与通信·信号处理
Damon小智2 小时前
NiFi实现数据存储到数据库
数据库·mysql·docker·postgresql·nifi
任子菲阳2 小时前
学JavaWeb第六天——JDBC & Mybatis
java·数据库·mybatis
一路往蓝-Anbo2 小时前
STM32单线串口通讯实战(三):协议层设计 —— 帧结构、多机寻址与硬件唤醒
c语言·开发语言·stm32·单片机·嵌入式硬件·物联网
资深web全栈开发2 小时前
Zanzibar vs MySQL Permission System - 实证性能对比研究
数据库·mysql·权限设计·zanzibar
Greyscarf2 小时前
人大金仓服务启动
数据库
张较瘦_2 小时前
MySQL | 文本数据类型(CHAR/VARCHAR/TEXT/BLOB):区别、场景与实战
数据库·mysql