ARTICLE DETAIL

资讯详情

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

单片机空调温度控制系统设计与实现:从选型到联调

单片机空调温度控制系统设计与实现:从选型到联调 简介这是一份基于8051单片机的空调温度控制系统课程设计报告面向电气工程、自动化、检测技术与仪器等专业学生可用于完成单片机课程设计或理解温度检测与闭环控制原理。资源为doc格式共1个文件压缩包大小613KB内容完整包含设计任务书、硬件电路设计、程序流程与代码思路等部分。系统以8051单片机为核心结合电位器模拟温度变化、A/D转换器采集模拟信号、8255扩展I/O口驱动LED数码管并通过键盘或开关设定恒温温度当外界温度超过设定值1℃时可驱动发光二极管或直流电机模拟加热/制冷动作。报告详细给出了系统总体模块、各模块介绍、硬件连接、程序流程图以及汇编/C语言程序设计框架还包含设计目的、过程、总结与参考文献便于读者掌握单片机接口技术、A/D转换应用和恒温控制系统的完整开发流程。已有75人学习该资源尤其适合作为课程设计报告撰写和单片机综合实训的参考模板。1. 单片机课程设计——空调温度控制到底在做什么如果你搜过「单片机课程设计报告 空调温度控制」大概率已经见过不下十份能跑通的参考方案一个 51 单片机、一只温度传感器、几颗按键、一个继电器再加一块 LCD1602 或者数码管就把空调控制面板干到能用的程度。但凡是自己从头搭过一遍的人都会发现课程设计真正卡人的不是「读温度」——DHT11 或者 DS18B20 的单总线时序翻来覆去就那几个微秒的事——而是「把温度控制做成一个不会乱跳的系统」。压缩机什么时候开、什么时候停、温度落在设定值附近时会不会频繁启停、掉电后再上电是回到默认 26℃ 还是记住上次设定这些才是报告里值得写、答辩时值得讲的部分。这篇就按从选型到联调的顺序把一条完整可复现的路径铺开。适合正在做课程设计或毕业设计、手里有一块 STC89C52RC 或者 STM32 但不确定「报告该写多深」的人也适合想从代码里看出温度回差和按键去抖这些工程细节的熟手。2. 系统架构与器件选型空调温度控制的最小闭环长什么样2.1 闭环拆解传感、执行、设定、显示四件事空调温度控制本质上是一个位式闭环系统传感器读回环境温度单片机把读到的温度跟用户设定的目标温度做比较用比较结果去驱动执行机构。跟 PID 控温不同的是空调温控对精度要求低对「别频繁启停」要求高所以多数课程设计都用带滞回区间的位式控制而不是连续调节。整个系统的信号流可以拆成四段温度检测传感器把温度转换成电信号单片机读出来。设定输入按键把目标温度和回差量写进 RAM 或 EEPROM。控制决策比较当前温度与设定值决定压缩机、风扇继电器吸合还是断开。显示与反馈LCD 或数码管把当前温度、设定温度、工作模式显示出来。这四段里「控制决策」这个环节看起来代码量最少却是逻辑最容易出错的。常见的不成熟写法是当温度高于设定值就开压缩机低于设定值就关结果就是传感器读数在临界点抖动时继电器跟着咔咔响。2.1.1 为什么优先选 STC89C52RC 而不是 STM32课程设计的评分逻辑里「完整跑通」的权重远大于「性能冗余」。用 STC89C52RC 这类 51 内核单片机的理由是Proteus 里现成的仿真模型最多烧录用 CH340 转串口就能搞定代码示例在网上能覆盖到每一个报错点。STC89C52RC 的工作电压 5VI/O 口直接能驱动轻负载继电器驱动芯片不用像 STM32F103 那样还得考虑 3.3V 和 5V 电平转换问题。如果你手里已经有一只 STC32G12K128 或者 STM32 最小系统板当然不必刻意换成 51程序结构完全一致差别只在外设库函数和时钟配置。下面代码以 51 为主移植到 STM32 时把延时和引脚映射改掉就行。2.2 温度传感器选型DS18B20 与 DHT11 的取舍空调温控这个场景里DS18B20 几乎是课程设计的事实标准。原因有三点单总线接口只占一个 I/O 口Proteus 仿真的时序模型做得很成熟。12 位分辨率下精度 ±0.5℃读数直接是 0.0625℃ 步进不用自己做 ADC 标定。每一片 DS18B20 都有 64 位序列号以后想做成双传感器控温直接在总线上轮询即可。DHT11 的优势是湿度温度二合一但它的温度分辨率只有 1℃在报告里写「控温精度 ±1℃」没问题想把温度变化过程画成曲线就会露馅。选 DHT11 时要注意它和 DS18B20 的时序完全不同DHT11 是主机先拉低 18ms 再释放然后等待从机拉低响应你不能用 DS18B20 的读取代码直接去读 DHT11。下面是 DS18B20 的初始化时序这段是单总线通信里最容易在 Proteus 仿真时卡住的部分// DS18B20 总线复位 unsigned char ds18b20_reset(void) { unsigned char presence; DQ 0; // 主机拉低总线 delay_us(480); // 至少 480us让从机检测到复位脉冲 DQ 1; // 释放总线进入接收模式 delay_us(60); presence DQ; // 读取从机是否拉低总线 delay_us(420); // 剩下的复位时间 return presence; // 0 表示检测到从机 }时序的核心是「谁拉低、拉低多久、然后释放后多久采样」。DS18B20 的复位脉冲要求主机拉低 480us 以上释放后从机会在 60~240us 内把总线拉低作为存在脉冲。上面代码里在释放后延时 60us 再读DQ是卡在从机响应窗口的中间位置Proteus 仿真如果不同步最常见的错误就是这个 60us 被调太短读到的是高电平。2.2.1 把温度读数换算成十进制的方法DS18B20 返回的是 16 位温度寄存器值在 12 位模式下低 4 位是小数部分。课程设计报告里通常会贴这样的代码// 将 DS18B20 原始数据换算为带小数点温度值 int ds18b20_get_temp(void) { unsigned char low, high; unsigned int raw; int temp_100; // 温度乘以 100保留两位小数 if (ds18b20_reset() ! 0) return ERROR_TEMP; ds18b20_write_byte(0xCC); // 跳过 ROM 匹配单设备场景 ds18b20_write_byte(0x44); // 启动温度转换 // 转换 12 位数据需要 750ms 最坏情况这里做简单等待 while (!DQ); // 等待转换完成也可用固定延时替代 if (ds18b20_reset() ! 0) return ERROR_TEMP; ds18b20_write_byte(0xCC); ds18b20_write_byte(0xBE); // 读取暂存器 low ds18b20_read_byte(); high ds18b20_read_byte(); raw (high 8) | low; if (raw 0x8000) { // 负温处理 raw ~raw 1; temp_100 - (int)(raw * 625 / 100); } else { temp_100 (int)(raw * 625 / 100); } return temp_100; // 实际温度为 temp_100 / 100 }这里把转换结果乘以 100 再参与比较计算是为了避免浮点数。51 单片机用 Keil C51 编译时float 运算是软件模拟的慢且占 ROM用整数运算后面做滞回控制时也不会牺牲精度。625这个常量的来历是 0.0625℃ 乘以 10000再除以 100 得到 625正好把 16 进制的原始值换算成「温度 × 100」适合需要在 LCD 上显示小数点后两位的场景。2.3 执行机构继电器与可控硅两种方案对比执行部分有两个方向继电器驱动或者可控硅过零触发。课程设计里继电器是绝对主流因为驱动逻辑直观Proteus 里用ULN2003加一个RELAY模型就能仿真不用考虑过零检测。实际做法是用单片机的 P2.0 输出到 ULN2003 的输入端输出端接继电器线圈线圈两端反并一个 1N4007 续流二极管触点端才接 220V 的负载回路。可控硅方案比如 BT136 或 BTA16适合报告里讲「过零触发防止干扰」的进阶话题但它在 Proteus 仿真中常需要额外的光耦模型调试成本偏高。推荐课程设计阶段先用继电器把主逻辑验证通了再在「改进方向」里写可控硅方案。2.3.1 继电器驱动电路的关键参数器件参数说明ULN2003输入高电平 2.5V 以上51 单片机 5V 推挽输出可直接驱动继电器线圈电压 5V DC触点 10A 250V AC模拟空调压缩机时选 10A 触点更稳续流二极管1N4007继电器线圈断电时吸收反向电动势三极管方案S8050 基极电阻 4.7kΩ不用 ULN2003 时的替代电路很多初学者会把 ULN2003 当三极管用认为导通后输出端直接是低电平然后把继电器一端接 5V 一端接 ULN2003 输出线路接对但忘了芯片内每路输出都带了一个续流二极管到 COM 脚所以必须把 COM 引脚接到 5V 正极否则继电器断电瞬间会产生很高的反压。这是 Proteus 仿真里看不出来、实物上一上电就烧芯片的典型坑。3. 代码实现空调温度控制的核心逻辑与最小可运行程序3.1 主循环框架扫描按键、读取温度、刷新显示、控制输出课程设计而非工程产品的主程序可以写成一个大循环。空调温度控制的实时性要求不高DS18B20 转换要 750msLCD 刷一次要几毫秒因此一个几十毫秒周期的大循环完全够用。void main(void) { int cur_temp 0; // 当前温度乘以100 int set_temp 2600; // 默认设定温度 26.00℃ int diff 20; // 回差 0.20℃防止继电器频繁翻转 lcd_init(); ds18b20_reset(); while (1) { scan_key(); // 读取按键修改 set_temp cur_temp ds18b20_get_temp(); // 读取一次当前温度 ctrl_ac(cur_temp, set_temp, diff); // 控制继电器输出 lcd_show(cur_temp, set_temp); // 显示当前值与设定值 delay_ms(50); // 简单限速循环 } }这个主循环体现了温度控制的典型时间框架温度读取在最坏情况下会阻塞 750ms等待 DS18B20 转换中间按键扫描和显示刷新被暂时打断。如果按键在等待期间按下最多等一个转换周期才能响应对空调这种控制对象完全可接受。ctrl_ac函数内部就是位式控制逻辑下一节展开。注意set_temp 2600这里用的单位是「摄氏度乘以 100」和传感器读数cur_temp保持一致避免混用整数与浮点。3.2 带滞回的控制函数避免压缩机频繁启停位式控温最大的弊病是临界点振荡。比如设定 26℃实际 25.9℃ 时关压缩机热起来到 26.1℃ 就开读数的噪声就会让继电器在几分钟内反复动作。解决办法是在目标温度上下设置一个回差区间// 空调温度控制核心滞回比较 void ctrl_ac(int cur, int set, int diff) { // cur 和 set 都放大了100倍diff 也是 if (cur set diff) { RELAY_ON(); // 温度高于上限开启压缩机 mode_cool 1; } else if (cur set - diff) { RELAY_OFF(); // 温度低于下限关闭压缩机 mode_cool 0; } // 在回差区间内维持上次状态不变 }这里的逻辑遵循了位式控制的经典写法只有跨越区间的边界才改变继电器状态。如果当前温度落在set - diff cur set diff中间什么都不做状态保持之前的值。diff 20表示回差为 0.20℃。这个值怎么选有讲究太小的回差比如 5即 0.05℃会让继电器在温度噪声中频繁动作。太大的回差比如 100即 1.0℃会让温度波动大体感不好。课程设计的默认值建议 20~50 之间也就是 0.2℃ 到 0.5℃。3.3 按键扫描与去抖设定温度怎么改才不漂移按键处理分三层机械去抖、边沿捕获、长按连加。课程设计通常只做前两层。每个按键按下时会产生约 5~10ms 的抖动不做去抖就会出现按一下加好几度的现象。程序里用 20ms 延时法去抖// 温度加按键检测带 20ms 去抖和防重复触发 void scan_key(void) { if (KEY_UP 0) { // 检测按键按下低电平有效 delay_ms(20); // 跳过机械抖动期 if (KEY_UP 0) { // 再次确认仍为低电平 if (!key_up_pressed) { set_temp 100; // 每按 1 次加 1.00℃ if (set_temp 3200) set_temp 3200; // 上限 32℃ key_up_pressed 1; // 记录按下状态防止按住时连续加 } } } else { key_up_pressed 0; // 按键释放复位标志 } }key_up_pressed这个标志位是关键。如果不加它按下按键期间主循环每跑一次就执行一次set_temp 100实际效果变成了「按一下直接加到上限」。加了这个标志后必须在一次按键周期内只响应一次只有释放后才能再次触发。这就是边沿触发和电平触发的区别报告里建议把这个词写进去答辩时有加分点。3.4 LCD1602 显示把当前温度与设定值排布好显示部分用 LCD1602 就够。第一行显示当前温度和设定温度第二行显示工作状态。初始化函数和显示函数片段如下// 在 LCD1602 上显示温度和状态 void lcd_show(int cur, int set) { unsigned char buf[16]; // 第一行当前温度 sprintf((char *)buf, Temp:%2d.%02dC , cur / 100, cur % 100); lcd_puts(0x00, buf); // 第二行设定温度 sprintf((char *)buf, Set :%2d.%02dC , set / 100, set % 100); lcd_puts(0x40, buf); }sprintf在 C51 下会比较占 ROM如果 Keil 编译时提示空间不够常见的做法是去掉浮点支持只保留整数格式化或者自己写一个整数转字符串的小函数。LCD 刷新不需要太快每 200ms 刷一次即可否则一方面sprintf执行时间长影响主循环另一方面 DS18B20 转换期间调用 LCD 也可能因为时序抢占导致显示水波纹。4. Proteus 仿真与实物联调把空调温度控制跑起来的完整步骤4.1 Proteus 电路连接要点与常见警告Proteus 仿真是课程设计报告里必须有的截图来源。常见连接方案AT89C51或 STC89C52 的替代模型 DS18B20 LCD1602 两个按键 ULN2003 继电器。需要注意的点DS18B20 的数据引脚要接一颗 4.7kΩ 上拉电阻到 5V单总线要求。LCD1602 的对比度引脚V0接一个 10kΩ 电位器到 GND否则仿真画面上可能出现「全黑块」或「无字」。继电器模型按RELAY选触点端接交流正弦源和负载电阻用来模拟压缩机。常见警告是DS18B20 的时序错误会导致仿真界面弹出Logic Analyzer信号违例。这种警报告诉你总线时序没满足手册要求不是芯片坏了。优先检查复位时序中的 480us 延时是否被 Keil 编译器优化掉。4.1.1 用逻辑分析仪验证温度采集时序Keil 和 Proteus 联调时可以在 DS18B20 的 DQ 引脚挂一个虚拟逻辑分析仪直接观察复位脉冲宽度。要求是低电平持续 480us 以上。C51 的delay_us(480)在 12MHz 晶振下用_nop_()实现时需要根据晶振频率修正循环计数值。12MHz 晶振下每条指令约 1us用两层循环写 480 没问题如果改用 11.0592MHz 晶振为了串口波特率同样的延时函数差 4%在 DS18B20 这里完全能容忍但在串口通信里就必须重新算波特率。4.2 实物联调的电源与接地坑如果做实物第一个坑通常不在程序里而在电源上。单片机最小系统板和继电器共用一个 5V 电源时继电器一吸合线圈电流会造成电源电压跌落轻则 LCD 闪屏重则单片机复位。解决方法继电器电源与单片机电源分别供电共地即可。继电器线圈回路加 100~470μF 电解电容稳定电压。用 ULN2003 的 COM 脚接 5V 时确保该 5V 能提供继电器吸合所需的 70mA 左右的电流。还有一个问题容易被忽略DS18B20 是三端器件VDD 和 GND 反接一次就可能永久损坏。实物调试前用万用表量一遍供电引脚比反复换芯片划算。4.3 代码烧录STC 单片机的一键下载技巧STC89C52RC 的烧录流程是先用 STC-ISP 软件选择芯片型号和串口号然后点「下载/编程」这时候软件会等待单片机重新上电所以要给板子设计一个电源开关或者一键下载电路。课程设计中如果嫌开关麻烦常见做法是冷启动下载先断开板子电源点下载后再上电。错误率最高的一步是 USB-TTL 模块的接线TXD 接单片机的 RXDRXD 接单片机的 TXD交叉连接。很多人接成直插结果软件能识别到端口但一直提示「握手失败」。5. 进阶技巧用回差、掉电保存与异常处理让报告更扛得住答辩再往下走报告和代码已经完成了「能用」。如果要让这份设计从及格变成优秀有三个方向值得写进报告温度采样滤波、掉电保存设定值、传感器断线异常处理。它们都属于「不增加多少代码量但体现工程意识」的改进项。5.1 多次采样取平均滤掉尖峰噪声DS18B20 的瞬时读数在空调压缩机启动的瞬间可能因为电源扰动出现跳变。工程做法不是直接信任单次读数而是连读 5 次去掉最大值和最小值后取平均。用前面的temp_100单位实现// 滑动滤波采集5次去掉极值后取平均 int get_stable_temp(void) { int vals[5]; int i, min_idx, max_idx, sum; for (i 0; i 5; i) { vals[i] ds18b20_get_temp(); delay_ms(100); // 两次读数之间间隔避免忙等 } min_idx 0; max_idx 0; for (i 1; i 5; i) { if (vals[i] vals[min_idx]) min_idx i; if (vals[i] vals[max_idx]) max_idx i; } sum 0; for (i 0; i 5; i) { if (i ! min_idx i ! max_idx) sum vals[i]; } return sum / 3; }这套算法的代价是每次控温循环要等 5 次转换约 4 秒对空调温控完全够用。报告里可以写一句「以时间换稳定」比刻意堆滑窗滤波复杂公式更切题。5.2 STC 单片机 EEPROM重启后记住上次设定温度课程设计的加分项之一是「掉电保存」。STC89C52RC 内部集成了 EEPROM严格说是 Data Flash地址从 0x2000 开始。通过 IAP 指令读写不需要外挂 AT24C02报告篇幅瞬间浓缩。保存与读取的代码结构#include STC89C5xRC.H // 保存设定温度到 Data Flash void save_set_temp(int set) { unsigned char addr 0x2000; unsigned char high (unsigned char)(set 8); unsigned char low (unsigned char)(set 0xFF); IAP_CONTR 0x80; // 使能 IAP 功能 IAP_CMD 0x02; // 字节编程命令 IAP_ADDRL low; IAP_ADDRH high; IAP_TRIG 0x5A; // 触发编程 IAP_TRIG 0xA5; _nop_(); }注意触发位置IAP_TRIG 前两条命令是固定动作0x5A、0xA5顺序不能反。而save_set_temp函数里的形参set是一个大端表示的整型拆分高、低字节时要先确定写入顺序与读取顺序一致。这个细节程序跑起来没毛病但报告里最好写一句。5.3 传感器断线识别别再显示 85.00℃ 的迷之读数DS18B20 断开或短路时不校验原始读数会把 16 位数据全部置 1换算结果是 85℃。空调系统若显示 85℃ 就会误开压缩机。处理方式是在读取函数里加一层信心检查。以上文ds18b20_get_temp为例当复位时拉低失败返回ERROR_TEMP主流程检测到这个信号后直接进入保护态——关闭压缩机输出LCD 显示Err。这是空调温度控制从「演示模型」迈入「准产品设计」的关键一步。到了这里你会发现整个课程设计最值的部分其实不在 DS18B20 的时序里而在「把温度控制当作一个有状态、有边界、有异常路径的小系统」来设计。把回差、滤波、掉电保存和断线保护这四件事讲清楚报告的文字部分自然就厚了。再往下要走的路只有一条把继电器换成可控硅过零触发加一个红外遥控接收头模拟遥控器按键然后配上 PT100 做高精度采样——那又是一个新课题了。本文还有配套的精品资源点击获取
返回列表