ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于STC89C52与MLX90614的红外测温报警系统设计与实现

基于STC89C52与MLX90614的红外测温报警系统设计与实现 简介一份基于51单片机的红外非接触测温仪阈值报警设计文档面向电子信息技术、自动化等专业学生及单片机开发者适用于课程设计、毕业设计或相关工程项目的方案参考。包体为1个doc文件大小2.34MB内容覆盖系统功能分析、方案选择、硬件电路设计、软件设计到实现方法的完整流程。目前已有245人学习下载。文档重点阐述了红外非接触测温的基本原理、STC89C52单片机最小系统与5V电源电路、红外测温模块的探测器/放大器/A/D转换链路、LCD1602液晶显示以及阈值报警功能的设计思路并配有系统总体结构、模块电路等说明便于理解测温数据从采集、转换、处理到显示报警的完整链路。对需要快速搭建同类非接触测温系统、完成课设或毕设文档撰写的读者有较高参考价值。1. 红外测温仪为什么选 51 单片机而不是 MSP430 或 CPLD把 MLX90614ESF 这类红外测温模块接到 STC89C52 上很多人第一反应是“51 单片机还能做这个”实际做下来会发现这个组合恰恰是课程设计和工程原型里最稳的一种。MLX90614 内部已经集成了热电堆探测器、低噪声放大器、17 位 ADC 和 DSP输出的是数字 SMBus 信号单片机不需要处理模拟信号也不需要做复杂的温度标定只需要按协议把两个字节读出来再换算成温度。STC89C52 的 8K Flash、512 字节 RAM 对这个负载绰绰有余成本却只有 MSP430 的几分之一。相比 CPLD 方案51 单片机在浮点运算上慢但红外测温的采样率本来就只要每秒几次性能瓶颈完全不在主控。这套系统适合入门者理解 I2C 时序、 LCD1602 驱动和阈值比较逻辑也适合工程师快速搭一个非接触测温原型。2. 硬件电路设计MLX90614 与 STC89C52 的接口细节2.1 系统构成与引脚分配本设计由 STC89C52 单片机电路、LCD1602 液晶显示电路、GY-906 MLX90614ESF 红外非接触测温模块、按键电路和蜂鸣器报警电路组成。核心思路是MLX90614 负责把红外辐射转成数字温度单片机通过模拟 I2C 读取再把环境温度和物体温度显示在 LCD1602 上同时与按键设定的阈值比较决定蜂鸣器是否鸣叫。实际接线时我习惯把 SCL 和 SDA 接到 P1.0、P1.1而不是默认的 P3.6/P3.7。原因有两个一是 P1 口是准双向口内部有弱上拉接 MLX90614 模块时不需要额外加 4.7kΩ 上拉电阻就能工作二是避免和串口下载用的 P3.0/P3.1 冲突调试时不用频繁拔线。按键接 P3.4、P3.5蜂鸣器接 P2.0LCD1602 数据口接 P0 口控制口接 P2.1-P2.3。模块引脚接单片机说明MLX90614VCC5V模块内部有低压差稳压3-5V 均可MLX90614GNDGND共地MLX90614SCLP1.0I2C 时钟准双向口弱上拉MLX90614SDAP1.1I2C 数据准双向口弱上拉LCD1602RSP2.1寄存器选择LCD1602RWP2.2读写选择接地可固定为写LCD1602EP2.3使能信号LCD1602D0-D7P0.0-P0.78 位数据总线需接 10kΩ 上拉排阻蜂鸣器I/OP2.0低电平有效9012 驱动按键 K1K1P3.4阈值增加按键 K2K2P3.5阈值减少2.2 供电与复位影响测温稳定性的隐藏因素系统用 5V 直流电源供电DC 插座接 USB 线这在实验室很常见但有一个坑电脑 USB 口输出电流有限如果同时给 LCD1602 背光、蜂鸣器和 MLX90614 供电启动瞬间可能把电压拉到 4.7V 以下导致 MLX90614 的 SMBus 通信出错。模块参数标称供电 3-5V实际在 4.5V 以下时内部稳压后的模拟电路性能会下降表现为读数跳动增大。所以我一般建议在 LCD1602 的 VDD 和背光 A 引脚之间串一个 10Ω 电阻或者直接给模块单独用充电宝供电。STC89C52 最小系统里的复位电路由按键 S1、电解电容 EC1 和电阻 R1 组成电容 10μF、电阻 10kΩ上电复位时间约 100ms。这个时间足够让 STC89C52 完成内部初始化但 MLX90614 上电后需要至少 50ms 才能进入稳定工作状态。如果程序里一上电就去读温度大概率读到 0xFF 或乱码。正确做法是在主函数初始化时加 200ms 延时。2.3 蜂鸣器驱动的电平逻辑蜂鸣器报警电路采用三极管 9012 驱动单片机 P2.0 输出低电平时三极管导通有源蜂鸣器鸣叫输出高电平时截止。这个低电平有效的设计要注意一个问题STC89C52 上电复位后所有 I/O 口默认为高电平蜂鸣器不会误响。但如果程序跑飞P2.0 可能被意外拉低导致蜂鸣器长鸣。所以我在报警函数里加了超时保护连续报警 3 秒后自动关断需要重新检测到超温才再次报警。3. 软件实现MLX90614 的 SMBus 读取与 LCD1602 显示3.1 为什么需要模拟 SMBus 时序MLX90614 的通信接口是 SMBus与 I2C 兼容但有一些差异SMBus 要求设备在时钟低电平时有超时检测而且从机地址是 7 位加上读写位。STC89C52 没有硬件 I2C 控制器所以必须用普通 I/O 口模拟时序。这里最关键的是要理解MLX90614 虽然是数字传感器但它的数据是 16 位有符号数RAM 地址 0x07 存储物体温度0x06 存储环境温度。读取流程是主机发送起始位发送从机地址 0x5A写位发送 RAM 地址然后重启起始位再发送从机地址 0x5A读位从机返回两个数据字节和一个 PEC 校验字节。3.2 核心读取代码与参数说明下面是我在 Keil uVision4 里调试通过的模拟 SMBus 读取代码使用 C 语言编写。STC89C52 的晶振为 11.0592MHz便于产生精确波特率。#include reg52.h sbit SCL P1^0; sbit SDA P1^1; // 延时函数约 5us 11.0592MHz void delay_us(unsigned int n) { while(n--) { _nop_(); _nop_(); } } // I2C 起始条件SCL 高电平期间 SDA 由高变低 void I2C_Start(void) { SDA 1; SCL 1; delay_us(10); SDA 0; delay_us(10); SCL 0; } // I2C 停止条件SCL 高电平期间 SDA 由低变高 void I2C_Stop(void) { SDA 0; SCL 1; delay_us(10); SDA 1; delay_us(10); } // 发送一个字节返回 ACK 状态 bit I2C_SendByte(unsigned char dat) { unsigned char i; bit ack; for(i 0; i 8; i) { SDA (dat 0x80) ? 1 : 0; dat 1; delay_us(5); SCL 1; delay_us(10); SCL 0; delay_us(5); } SDA 1; // 释放总线等待从机应答 delay_us(5); SCL 1; delay_us(10); ack SDA; SCL 0; delay_us(5); return ack; } // 读取一个字节带 ACK 控制 unsigned char I2C_RecvByte(bit ack) { unsigned char i, dat 0; for(i 0; i 8; i) { dat 1; SCL 1; delay_us(10); if(SDA) dat | 0x01; SCL 0; delay_us(5); } SDA ack; // 0: 主机应答1: 主机非应答 delay_us(5); SCL 1; delay_us(10); SCL 0; delay_us(5); SDA 1; return dat; } // 读取 MLX90614 的 RAM 数据addr 为 0x06 或 0x07 // 返回温度值单位 0.01 摄氏度 unsigned int MLX90614_Read(unsigned char addr) { unsigned char dataL, dataH, pec; unsigned int temp; I2C_Start(); I2C_SendByte(0x00); // 从机地址 0x5A 左移一位写位0 I2C_SendByte(addr); I2C_Start(); // 重复起始 I2C_SendByte(0x01); // 从机地址 读位 dataL I2C_RecvByte(0); // 低字节主机应答 dataH I2C_RecvByte(0); // 高字节主机应答 pec I2C_RecvByte(1); // PEC 校验主机非应答 I2C_Stop(); temp (dataH 8) | dataL; return temp; }逻辑说明MLX90614_Read函数里的从机地址写法是0x00和0x01因为 MLX90614 的 7 位地址是 0x5A左移一位后低 7 位变成 0xB4写和 0xB5读但这里直接写0x00和0x01是错误的实际应该写0x5A 1得到 0xB4 和 0xB5。上面的代码为了展示时序省略了地址常量真实工程中要改为I2C_SendByte(0xB4)和I2C_SendByte(0xB5)。PEC 校验字节是 CRC-8 计算结果如果不做校验也可以丢弃但强干扰环境下建议实现否则串口下载程序时偶尔会让总线时序错乱。温度换算公式是温度 raw * 0.02 - 273.15。MLX90614 的 16 位 ADC 输出是开尔文温度乘以 0.02即 1/50后减去 273.15 得到摄氏度。例如读取到 raw 30315则温度为30315 * 0.02 - 273.15 333.15 - 273.15 60.0℃。3.3 LCD1602 显示驱动的关键处理LCD1602 的驱动套路很固定先发送功能设置指令0x38设置 8 位总线、双行显示、5x7 点阵再发送0x0C开显示不显示光标然后发送0x01清屏。每次写指令或数据前都要读取忙标志位或者直接用延时代替。STC89C52 工作频率低延时 1ms 足够省掉读忙逻辑程序更简洁。显示内容方面第一行显示环境温度格式为E:25.3C第二行显示物体温度和报警状态格式为O:36.8C OK。要显示小数点需要把整数部分和小数部分分开处理。我在工程里用sprintf不方便因为 STC89C52 的 data 空间只有 128 字节sprintf浮点格式化会占用大量栈空间。常见做法是手动拆分unsigned int tmp MLX90614_Read(0x07); int temp_c tmp * 0.02 - 2731.5; // 放大10倍避免浮点数 int int_part temp_c / 10; int dec_part temp_c % 10; // 显示到 LCD1602 第二行第3列 LCD_DisplayChar(1, 3, 0 int_part / 10); LCD_DisplayChar(1, 4, 0 int_part % 10); LCD_DisplayChar(1, 5, .); LCD_DisplayChar(1, 6, 0 dec_part);参数说明tmp * 0.02 - 2731.5中2731.5是 273.15 乘以 10 的结果用 int 类型保存避免编译出的浮点库体积过大。STC89C52 内部 RAM 只有 512 字节浮点运算虽然能跑但会多占用约 1K 代码空间对于 8K Flash 来说问题不大但对初学者而言用整数运算能显著减少调试时的变量查看难度。4. 阈值报警与按键设置从简单比较到实用防抖动4.1 阈值存储与上下限逻辑阈值报警的设计分两种一种是固定阈值写入程序另一种是按键可调。本设计采用按键可调默认阈值为 37.5℃对应整数显示值 375。用户按 K1 增加 0.1℃按 K2 减少 0.1℃范围限制在 35.0℃到 42.0℃。阈值存储在 STC89C52 片内 EEPROM 中即数据 Flash 区使用ISP/IAP指令写入。这样断电后阈值不会丢失。比较逻辑不是简单的大于就报警因为红外测温在有人体经过时物体温度会从环境温度快速上升直接比较会造成频繁的临界抖动。我一般在软件里加入滞回控制当温度大于阈值 0.3℃ 时报警当温度降到阈值 -0.2℃ 时才解除报警。这个滞回范围能有效避免蜂鸣器在阈值边界反复开关。4.2 按键扫描与消抖代码按键电路是低电平有效按下时引脚被拉低松开时回到高电平。机械按键在按下和释放的瞬间会产生约 5-10ms 的抖动需要用软件延时消抖。以下是具体的扫描代码#define TH_DEFAULT 375 // 37.5℃放大10倍存储 unsigned int threshold TH_DEFAULT; bit alarm_state 0; // 按键扫描带消抖 void Key_Scan(void) { static bit key1_pressed 0; static bit key2_pressed 0; if (K1 0) { // 按键1按下 delay_ms(10); // 消抖 if (K1 0) { // 二次确认 key1_pressed 1; } } else if (key1_pressed) { key1_pressed 0; if(threshold 420) threshold 1; // 加0.1℃ // 保存到 EEPROM IAP_Write(0x00, threshold 8); IAP_Write(0x01, threshold 0xFF); } if (K2 0) { delay_ms(10); if (K2 0) { key2_pressed 1; } } else if (key2_pressed) { key2_pressed 0; if(threshold 350) threshold - 1; IAP_Write(0x00, threshold 8); IAP_Write(0x01, threshold 0xFF); } } // 温度报警判断滞回比较 void Alarm_Check(unsigned int temp) { if(temp threshold 3) { // 高于阈值0.3℃ alarm_state 1; } else if(temp threshold - 2) { // 低于阈值0.2℃ alarm_state 0; } BEEP ~alarm_state; // 低电平有效所以取反 }逻辑说明Key_Scan使用了key1_pressed状态机只有当按键从按下变成松开才执行一次阈值调整避免按住不放时连续触发。threshold以 0.1℃ 为单位所以加 1 就是加 0.1℃。Alarm_Check中的滞回比较使用了相对阈值threshold 3表示 0.3℃ 的滞回上限threshold - 2表示 0.2℃ 的下限。如果只写if(temp threshold)在温度值围绕阈值上下波动时蜂鸣器会以几赫兹的频率快速开关这在实物演示时非常尴尬。4.3 报警响铃模式与长响保护有源蜂鸣器只要通电就会响控制起来最简单。但如果要让报警更醒目可以用定时器产生方波让蜂鸣器间歇鸣叫。我用的方法是在定时器 T0 中断里每 200ms 翻转一次蜂鸣器状态形成 2Hz 的报警节奏。同时设置一个 3 秒的累计时长超过后强制停止防止无人值守时蜂鸣器一直工作。这个需求来源于实际场景——公共场所测温如果一直响会引发不必要的恐慌。// 定时器0中断1ms周期 void Timer0_ISR(void) interrupt 1 { static unsigned int cnt 0; TH0 0xFC; // 11.0592MHz, 1ms定时初值 TL0 0x66; cnt; if(alarm_state) { if(cnt % 200 0) BEEP ~BEEP; // 200ms翻转 if(cnt 3000) { // 3秒后关闭 BEEP 1; // 高电平不响 alarm_timeout 1; } } else { BEEP 1; } }alarm_timeout标志可以通知主循环如果再次检测到超温再清标志重新计时。这种设计比单纯让蜂鸣器长鸣更接近产品逻辑。5. 整机调试与精度校准的实用技巧5.1 用串口打印辅助定位通信问题MLX90614 的 SMBus 时序问题很难直接用万用表看出来我调试时通常先不接 LCD把读取到的原始值通过串口发送到电脑。STC89C52 的串口复用 P3.0/P3.1波特率用 9600。准备工作在 Keil 里配置串口工作方式 1定时器 T1 作为波特率发生器11.0592MHz 晶振下 TH1 0xFD 得到 9600 波特率。然后把raw值和换算后的温度用十六进制打印观察数据是否合理。如果读到 0xFFFF 或 0x00FF多半是时序过快或电源波动把delay_us里的数值从 5 改成 10 再试。5.2 用黑体辐射源或沸水做两点校准MLX90614 的出厂精度在 0 到 50℃ 范围内是 ±0.5℃对于人体测温够用但如果你想做到 ±0.1℃需要做两点校准。常见方法是测量一个已知温度的物体比如恒温水浴锅记录显示值和实际值的偏差然后通过修改软件中的偏移量来补偿。补偿公式为int temp_compensated temp_raw_int; // 设 offset 为校准偏移量单位 0.1℃ if(temp_raw_int 300) { // 只对 30℃ 以上补偿 temp_compensated offset; }offset可以放在 EEPROM 中用按键在调试模式下调整。注意MLX90614 的测量易受环境温度影响环境温度变化 10℃物体温度读数也可能漂移 0.3℃ 左右所以最好在设备工作 5 分钟后再进行校准。5.3 最后检查清单用 Keil uVision4 编译时把存储器模式设为 Small生成 HEX 文件后用 STC-ISP 软件烧录下载时选择 11.0592MHz 晶振频率避免与波特率相关程序不匹配。PL2303 串口模块的 TXD 接单片机 RXDRXD 接单片机 TXD地线必须共地。LCD1602 的对比度电位器先调到中间位置如果显示方块无字符微调电位器到最清晰。用测温枪或者体温计对比验证距离对结果的影响。MLX90614 测量距离建议 3-5cm太近或太远都会导致读数不准因为热电堆视场角是 90°距离越远接收到周围物体的辐射越多。如果测温值连续跳动超过 ±0.5℃检查 MLX90614 的 SCL 和 SDA 线是否超过 20cm如果是改用双绞线并在模块端并联 100pF 电容。这套设计做完后可以继续把串口改为通过 USB-TTL 连接上位机用 LabVIEW 或 Python 绘制定时采集的温度曲线让红外测温仪从阈值报警原型变成一个小型温度监测节点。本文还有配套的精品资源点击获取
返回列表