简介:面向计算机应用技术(嵌入式方向)专业的毕业设计文档,选题为基于51单片机的空气智能加湿器,适合需要完成嵌入式课程设计、毕业设计选题与论文写作的学生参考。方案以AT89C51单片机为核心,配合DS18B20温度传感器与1602LCD液晶显示屏,实现加湿器自动开启关闭、防干烧、声光报警及室内温湿度显示等功能,可作为软硬件联调与智能控制系统设计的实践蓝本。包内为1个doc文档,压缩包约339KB,篇幅集中、便于通读。文档按毕业设计规范组织,含摘要、任务来源与意义、总体设计方案、硬件设计(电路图、信号分析、功能描述、复位电路、液位定位与光电开关)以及软件设计等章节,能帮助读者快速搭建论文框架、理清模块划分与实现思路。目前已有538人学习下载。
1. 干湿球测湿 + AT89C51:一个能跑通的低成本方案
市售几十块的加湿器有个通病:插上电就一直雾化,水箱空了照样转,房间湿度都到 70% 了还在喷。干烧和过度加湿这两件事,恰好是低端机型最容易省掉的部分。这份毕业设计要做的,就是给加湿器装一个"脑子"——用 AT89C51 读两路 DS18B20 的干湿球温度,反推相对湿度,配上水位检测做防干烧,声光报警做提示,1602 液晶实时显示温湿度。
干湿球法几乎是单片机课程里成本最低的测湿方案:两只数字温度传感器加一片 51,BOM 不到二十块,不需要额外的湿度芯片和标定设备。它适合正在做嵌入式方向毕业设计的人,也适合想把 51 的 I/O 口操作、定时器、单总线微秒级时序一次性打通的人。下面从引脚分配开始,把单总线时序、干湿球公式的定点实现、水位互锁逻辑一路写到烧录联调,每一步都能直接抄进工程。
2. 51 单片机硬件设计:引脚先分配好再动手画图
2.1 为什么还在用 AT89C51
AT89C51 是 4KB Flash、128B RAM、32 根 I/O 的经典 8 位机,MCS-51 指令集,Keil C51 和汇编都能编。选它的理由很实际:Proteus 元件库里模型齐全,教学资料铺天盖地,出了问题好查。但有两个要提前想清楚。
一是容量。AT89C51 只有 4KB 程序空间,把 1602 驱动、两路 DS18B20 时序、显示转换和主逻辑全塞进去,很容易顶到 3KB 以上,改一点就超。稳妥做法是直接上 AT89C52(8KB)或 STC89C52RC,引脚完全兼容,程序不用改。现在市面上标 AT89C51 的片子翻新货不少,STC89C52RC 反而更好买、还支持串口下载。
二是执行速度。12MHz 晶振下机器周期 1μs,一条MOV级指令占 1~2μs。DS18B20 的读时隙要求主机拉低 1μs 后 15μs 内完成采样,靠的是 NOP 和短延时循环卡时间,编译器优化一开就可能把时序打乱。所以时序子程序必须单独放一个文件,关掉该文件的优化。
2.2 一张引脚分配表管住整块板子
硬件设计最怕画到一半改引脚,改一处牵动一片。先把分配表定死,写代码和画原理图都照它来。
| 功能 | 引脚 | 方向 | 说明 |
|---|---|---|---|
| 干球 DS18B20 | P1.2 | 双向 | 4.7kΩ 上拉到 +5V |
| 湿球 DS18B20 | P1.3 | 双向 | 独占一根 I/O,避免 ROM 匹配 |
| 1602 数据 D0~D7 | P0.0~P0.7 | 输出 | P0 为开漏,必须 10kΩ 排阻上拉 |
| 1602 RS / RW / E | P2.0 / P2.1 / P2.2 | 输出 | E 下降沿锁存 |
| 1602 背光 | P2.7 | 输出 | 经 S8050 驱动,可调亮度 |
| 加湿执行机构 | P1.0 | 输出 | 三极管驱动继电器,0 断 1 通 |
| 蜂鸣器 | P1.1 | 输出 | 无源型,定时器输出 2kHz 方波 |
| 运行指示灯 | P1.4 | 输出 | 加湿中点亮 |
| 水位 低 / 中 / 高 | P3.2 / P3.3 / P3.4 | 输入 | 低电平有效,按键或浮球开关 |
对应到代码就是一组sbit定义,别用宏定义数字引脚,51 的位操作靠sbit才写得动。
/* ---------- 引脚分配(与原理图严格一致) ---------- */ sbit DQ_DRY = P1^2; /* 干球 DS18B20 数据线,需 4.7k 上拉 */ sbit DQ_WET = P1^3; /* 湿球 DS18B20 数据线 */ sbit HUM_CTRL = P1^0; /* 加湿执行机构:1=通,0=断 */ sbit BEEP = P1^1; /* 无源蜂鸣器,由定时器 0 翻转输出方波 */ sbit LED_RUN = P1^4; /* 加湿进行中指示灯 */ sbit LCD_RS = P2^0; /* 0=指令,1=数据 */ sbit LCD_RW = P2^1; /* 0=写,1=读(忙检测时用) */ sbit LCD_EN = P2^2; /* 下降沿执行 */ sbit LCD_BLK = P2^7; /* 背光开关,1=亮 */ sbit LV_LOW = P3^2; /* 低水位:0 表示缺水 */ sbit LV_MID = P3^3; /* 中水位 */ sbit LV_HIGH = P3^4; /* 高水位 */sbit是 Keil C51 的位寻址关键字,只能用在可位寻址区(P0~P3、20H~2FH 位区)。P3.2~P3.4 是外部中断和定时器引脚,这里当普通输入用没问题,但要注意 P3 口内部有弱上拉,接按键时按下接地即可,不必外加上拉电阻。
2.3 复位、晶振、P0 上拉:三个最容易翻车的细节
复位电路用 10μF 电解电容加 10kΩ 电阻构成 RC,配上手动复位按键和一个 1N4148 反向泄放二极管。二极管的作用是掉电瞬间让电容快速放电,否则电源跌落再上电时电容还存着电,复位脉冲宽度不够,单片机会跑飞。RC 常数别贪大,10μF×10kΩ 已经给出几十毫秒的复位宽度,电容上到 47μF 反而会导致上电后复位脚缓慢爬升,出现"上电不启动、按一下复位才行"的经典故障。
晶振选 12MHz,配两只 30pF 瓷片电容,尽量贴着晶振引脚焊接,走线短而等长。如果后续打算接串口调试,换 11.0592MHz 能让波特率误差归零,代价是机器周期变成 1.085μs,所有基于 1μs 假设的延时循环要重算。
P0 口是开漏输出,驱动 1602 的数据线时如果不接上拉,写进去的1根本拉不高,屏幕会显示乱码或者干脆空白。加一只 10kΩ 排阻拉到 +5V,问题立刻消失。这是新手最常踩、也最容易被误判成"液晶坏了"的一个坑。
2.4 加湿器负载驱动:从 LED 原型到继电器
开发阶段用一只 LED 加限流电阻代替加湿器执行机构,这是很合理的做法——省了接强电的风险,仿真时也能直观看到 P1.0 的电平变化。但真机上板必须换成继电器或固态继电器。
51 单个 I/O 口的灌电流典型值 20mA 上下,继电器线圈 5V 要 70mA 左右,直连必然拉垮口线甚至烧片。标准接法是 P1.0 经 1kΩ 基极限流电阻驱动 S8050,继电器线圈并在一个 1N4148 续流二极管上,方向与线圈反接,吸收断电瞬间的反向电动势。想彻底隔离强电侧干扰,就用 PC817 光耦替代三极管做前级。
超声波雾化片本身工作频率在兆赫兹级,51 直接驱动不现实。工程上更可行的做法是把加湿器整机当成一个负载,用继电器控制它的市电通断,防干烧逻辑作用在继电器之前。
3. DS18B20 单总线时序与干湿球相对湿度计算
3.1 单总线为什么难写:微秒级窗口
DS18B20 用一根线同时传数据和供电(寄生电源模式),代价是所有时序都由主机严格把控。它没有时钟线,靠的是"拉低多久、什么时候采样、什么时候释放"来编码 0 和 1。51 在 12MHz 下指令周期 1μs,容错窗口本来就只有十几微秒,再叠上 C 编译器的优化,很容易出现"仿真能读、上板读 85℃"的现象——85℃ 是 DS18B20 上电默认值,意味着转换根本没完成或者时序没被识别。
| 时序类型 | 主机拉低 | 采样/释放时机 | 总时隙 | 备注 |
|---|---|---|---|---|
| 复位脉冲 | ≥480μs | 释放后 15~60μs 内等存在脉冲 | — | 存在脉冲由从机拉低 60~240μs |
| 写 1 | 1~15μs | 释放后保持高 | ≥60μs | 释放后 15~60μs 内采样 |
| 写 0 | 60~120μs | 全程拉低 | ≥60μs | 拉低时间要覆盖采样窗口 |
| 读时隙 | ≥1μs | 释放后 15μs 内采样 | ≥60μs | 从机在窗口内驱动总线 |
表里的"总时隙 ≥60μs"是硬约束,相邻两个时隙之间至少留 1μs 恢复时间,否则从机会丢掉后面几位。
3.1.1 复位与存在脉冲
复位脉冲的做法是主机拉低总线 480μs 以上再释放,然后等大约 60μs 读总线电平。如果读到低电平,说明从机响应了存在脉冲,器件在线;读不到就把存在标志位置位,跳过后续操作。
RESET: ; 复位 + 存在脉冲检测 SETB DQ_DRY NOP CLR DQ_DRY ; 主机拉低 MOV R3,#150 ; 150*4us = 600us > 480us CALL DELAY_BY_R3 SETB DQ_DRY ; 释放总线 MOV R3,#15 ; 约 60us 后开始检测 CALL DELAY_BY_R3 MOV R3,#60 ; 检测窗口约 240us CHK: JNB DQ_DRY,GET_ACK ; 读到低电平 -> 器件存在 DJNZ R3,CHK SETB 70H ; 70H.0 = 1,器件不存在 JMP RESET_END GET_ACK: CLR 70H ; 存在标志清零 MOV R3,#120 ; 等恢复时间 2*120us DJNZ R3,$ RESET_END: RETDELAY_BY_R3是按 R3 计数的空循环,基准是 4μs 一跳。这里把存在标志放在位寻址区 70H 的第 0 位,主程序直接JB 70H.0就能判断,不用额外传参。注意DJNZ R3,$这种原地循环写法在 Keil 汇编器里合法,在有些第三方汇编器上要展开成标号。
3.1.2 写时隙和读时隙
写一位的逻辑是:先拉低启动时隙,然后根据要写的位决定拉低多久——写 1 就很快释放,写 0 就拉够 60μs 以上。
WRITE: ; 写一个字节,A 为待写数据 MOV R2,#8 ; 一次写 8 位 CLR C W_LP: SETB DQ_DRY NOP CLR DQ_DRY ; 启动写时隙 MOV R3,#4 ; 约 16us:写 1 的拉低时长 CALL DELAY_BY_R3 RRC A ; 最低位先进 C MOV DQ_DRY,C ; 写 0 时这里把总线继续拉低 MOV R3,#12 ; 约 48us,凑满 60us 时隙 CALL DELAY_BY_R3 SETB DQ_DRY ; 释放,恢复 1us 以上 NOP DJNZ R2,W_LP RET读时隙正好相反:主机拉低 1μs 以上启动,然后立刻释放,在 15μs 内采样。关键在于采样必须发生在释放之后、从机还没来得及松手之前。
READ: ; 读一个字节,结果放在 A MOV R2,#8 R_LP: SETB DQ_DRY NOP CLR DQ_DRY ; 拉低 >1us 启动读时隙 NOP NOP SETB DQ_DRY ; 释放,让从机驱动总线 NOP NOP MOV C,DQ_DRY ; 15us 内采样 RRC A MOV R3,#6 ; 补齐到 60us 时隙 CALL DELAY_BY_R3 DJNZ R2,R_LP RETWRITE和READ都依赖准确的软件延时,因此这两个函数以及调用的DELAY_BY_R3建议放在单独的ds18b20.c里,用#pragma OPTIMIZE(5,SPEED)之类的指令固定优化等级,避免换编译器版本后时序漂移。
一次完整读温的流程是:复位 → 跳过 ROM(0xCC)→ 启动转换(0x44)→ 等转换完成 → 复位 → 跳过 ROM → 读暂存器(0xBE)→ 连读两个字节。跳过 ROM 只在一个总线挂一只器件时可用,挂两只就必须走0x55加 64 位序列号的匹配流程,毕业设计里更省事的做法是两个传感器各占一根 I/O,时序代码直接复用。
3.2 12 位原始值到 0.1℃:定点换算
DS18B20 默认 12 位分辨率,读回的 16 位数据里低 4 位是小数,每 LSB 等于 0.0625℃。温度寄存器最大正数是 +125℃,最高 5 位是符号位,负温用补码表示。
/* raw 为 DS18B20 读出的 16 位原始值,返回 0.1℃ 单位的温度 */ int ds18b20_to_tenth(unsigned int raw) { long v = (long)(int)raw; /* 转有符号,补码直接可用 */ return (int)(v * 10 / 16); /* 0.0625℃/LSB -> 0.1℃ */ }先转成有符号再运算,是为了让 -10℃ 这类负温也能自动处理。v * 10 / 16用整数除法截断,误差不超过 0.05℃,对相对湿度计算完全够用。整个工程里不要出现float——51 上引入浮点库会让代码体积暴涨两三 KB,4KB 的片子立刻装不下。
还有一个容易被忽略的点:12 位分辨率下单次转换需要 750ms。原文代码里的DELAY_600MS是不够的,读到的会是上一次的转换结果,表现为"温度变化总是慢半拍"。要么把延时加到 750ms 以上,要么在初始化时把分辨率配置成 11 位(375ms),用 0.125℃ 的精度换响应速度。
3.3 干湿球法:查表 + 线性插值算相对湿度
干湿球法的物理基础是:湿球表面水分蒸发会带走热量,空气越干燥蒸发越快,湿球温度相对干球温度就降得越多。两者温差和相对湿度成一一对应关系,核心公式是
e = Ew(Tw) − A·P·(T − Tw),RH = e / Ew(T) × 100%
其中Ew是饱和水汽压,用 Magnus 公式算:Ew(T) = 6.112 × exp(17.62T / (243.12 + T)),单位 hPa。A是干湿表系数,大约 0.00066×(1+0.00115Tw),乘以标准大气压 1013hPa 后约等于 0.67 hPa/℃。
51 上算不了exp,工程做法是把Ew做成 0~50℃、步长 5℃ 的查表,中间线性插值。
/* 0,5,10,...,50℃ 对应的饱和水汽压,单位 0.1hPa */ static const unsigned int ew_tab[11] = { 61, 87, 123, 170, 234, 317, 424, 562, 738, 958, 1234 }; /* t 为 0.1℃ 单位整数,返回 0.1hPa 单位的饱和水汽压 */ unsigned int ew_lookup(int t) { unsigned char i; if (t <= 0) return ew_tab[0]; if (t >= 500) return ew_tab[10]; i = (unsigned char)(t / 50); /* 定位到 5℃ 区间 */ return ew_tab[i] + (unsigned int)(((unsigned long)(ew_tab[i+1] - ew_tab[i]) * (t - i * 50)) / 50); /* 区间内线性插值 */ } /* td 干球、tw 湿球,单位 0.1℃,返回 0.1%RH(0~1000) */ unsigned int calc_rh(int td, int tw) { unsigned int es, e; unsigned long drop; if (td <= tw) return 1000; /* 湿球不低于干球,按饱和处理 */ es = ew_lookup(td); e = ew_lookup(tw); drop = (unsigned long)(td - tw) * 67 / 10; /* 0.669hPa/℃ -> 0.1hPa */ if (e <= drop) return 0; /* 低于露点,防止无符号下溢 */ return (unsigned int)((unsigned long)(e - drop) * 1000 / es); }ew_tab的数值是按 Magnus 公式算出来再放大 10 倍取整的,插值误差在 0.3%RH 以内,比 DS18B20 本身 ±0.5℃ 的精度贡献小得多,不构成瓶颈。drop用无符号长整型是因为(td - tw)最大可能到 200(20℃ 温差),乘 67 后会超出 16 位整数范围,这是 C51 里很典型的一处溢出陷阱。
湿度测量的实际误差主要来自湿球纱布的湿润程度和通风条件。真机上必须保证湿球探头包着脱脂纱布、纱布另一端浸在水槽里,而且要有微风掠过——静止空气里湿球温度会趋近室温,算出来的湿度永远偏高。
4. 主程序状态机:水位互锁、防干烧与声光报警
4.1 主循环不要写成一条直线
原文的流程图是"读干球 → 读湿球 → 算湿度 → 读水位 → 比较 → 控制"一条线跑到底,加上 750ms 的转换延时,一轮循环要将近两秒。这带来两个问题:按键调整报警阈值时响应迟钝;水位突变时不能立刻切断加湿输出。
更合理的结构是主循环只管状态判断和输出,温度转换放在后台。具体做法是用定时器 0 产生 1ms 中断做时基,主循环每 10ms 跑一次水位扫描和输出更新,每 1s 触发一次温度读取,两边互不阻塞。
4.2 阈值参数表与滞回区间
控制参数集中定义,比散在代码里到处写魔法数字好维护得多。
| 参数 | 符号 | 取值 | 说明 |
|---|---|---|---|
| 加湿开启阈值 | RH_ON | 40%RH | 低于此值启动加湿 |
| 加湿停止阈值 | RH_OFF | 55%RH | 高于此值停止,形成 15% 滞回 |
| 水位下限 | LV_MIN | 低水位有效 | 触发断加湿 + 报警 |
| 水位上限 | LV_MAX | 高水位有效 | 停止补水提示 |
| 温度报警上限 | T_HI | 可设,默认 35℃ | 超限声光报警 |
| 温度报警下限 | T_LO | 可设,默认 5℃ | 低于此值报警 |
滞回是这套设计里最值得加的一处改进。如果按 40% 单点判断,湿度在阈值附近抖动时继电器会一秒吸合好几次,机械触点寿命几天就报废,听感上也是"哒哒哒"停不下来。把开启和停止拆成两个阈值,实际湿度必须跨过 15% 的带宽才会改变输出状态。
4.3 水位输入去抖与互锁逻辑
开发阶段用三个按键代替水位传感器,按键的机械抖动在 5~20ms 之间,直接读会采到一串跳变。软件上做 20ms 延时确认,或者用定时器累计三次相同采样。
互锁逻辑的核心是:只要低水位有效,HUM_CTRL必须无条件置 0,且这个判断要放在湿度判断之前,不能被湿度分支短路。
#define RH_ON 400 /* 40.0%RH,0.1% 单位 */ #define RH_OFF 550 /* 55.0%RH */ #define DEBOUNCE 20 /* 去抖次数,2ms 一次 */ static unsigned char low_cnt = 0; /* 低水位连续计数 */ static bit water_ok = 0; /* 水位允许标志 */ void water_scan(void) /* 2ms 调用一次 */ { if (LV_LOW == 0) { /* 低电平有效,说明缺水 */ if (low_cnt < DEBOUNCE) low_cnt++; } else { if (low_cnt) low_cnt--; } water_ok = (low_cnt < DEBOUNCE) ? 1 : 0; /* 稳定缺水才置 0 */ } void control_task(unsigned int rh, unsigned char water_ok) { static bit humidifying = 0; if (!water_ok) { /* 第一优先级:防干烧 */ humidifying = 0; HUM_CTRL = 0; LED_RUN = 0; alarm_on(ALARM_WATER); /* 缺水声光报警 */ return; } if (!humidifying && rh < RH_ON) humidifying = 1; /* 低于下限才开 */ if ( humidifying && rh > RH_OFF) humidifying = 0; /* 高于上限才关 */ alarm_off(ALARM_WATER); HUM_CTRL = humidifying; LED_RUN = humidifying; }low_cnt用递增递减而不是直接赋值,是为了抗单次脉冲干扰——电源波动引起的一两个采样点跳变不会立刻改变water_ok。water_ok声明的bit类型是 Keil C51 特有的位变量,占位寻址区一个位,比用unsigned char省内存。
4.4 报警优先级与蜂鸣器驱动
系统里有缺水报警和温度越限报警两类,都走同一个蜂鸣器和同一只红色 LED,那就必须定优先级。工程上的排序是:缺水 > 温度越限 > 正常。缺水是安全相关,只要成立就一直响,直到水位恢复;温度越限可以做成断续响,响 200ms 停 800ms,避免长时间高分贝噪声。
无源蜂鸣器要方波驱动才有声音,直接用BEEP = 1只会得到一声轻微的"嗒"。用定时器 0 的 1ms 中断做一个 2kHz 方波发生器最省事:
/* 定时器 0 中断,1ms 一次,内部再分频出方波 */ void timer0_isr(void) interrupt 1 { TH0 = 0xFC; TL0 = 0x18; /* 12MHz 下 1ms 定时初值 */ if (alarm_flags & ALARM_MASK) { /* 有报警才输出 */ beep_div ^= 1; BEEP = beep_div; /* 每 1ms 翻转一次 = 500Hz 基频 */ } else { BEEP = 0; } /* 断续报警计时、按键扫描、水位采样分频都在这里排队 */ }1ms 翻转一次得到 500Hz,蜂鸣器响度尚可;想更刺耳就把翻转周期缩到 0.5ms。TH0/TL0的初值随晶振变化,12MHz 下 1ms 是0xFC18,换成 11.0592MHz 就要按 1.085μs 一个机器周期重算,这一处很容易被漏掉,换晶振后蜂鸣器音调会明显偏低。
5. 51 单片机烧录与 Proteus 仿真联调:HEX 灌进芯片前的三道验证
5.1 先在 Keil 里把算法单独跑一遍
时序和算法混在一起调,出了问题分不清是公式错了还是总线没通。有效做法是把calc_rh和ew_lookup拷到一个空的 PC 工程里,喂几组已知的干湿球数据验证。比如干球 25.0℃、湿球 19.2℃,查表算出来应该在 55%RH 附近,如果得到 90% 或者 20%,说明插值或者drop的缩放系数写错了。
Keil C51 的编译链路是三个独立工具,搞清楚参数含义比点 IDE 按钮有价值:
# 在 Keil 安装目录的 C51\BIN 下执行 C51.EXE main.c DEBUG OBJECTEXTEND # 编译:生成 .obj,带调试信息 BL51.EXE main.obj,ds18b20.obj TO humid # 链接:绝对定位输出 OH51.EXE humid # 转换:Intel HEX 格式OBJECTEXTEND打开扩展目标文件格式,能在 μVision 里做源码级单步;BL51的TO后面接输出名;OH51生成的.hex才是烧录器认的文件。如果链接报"DATA SPACE OVERFLOW",说明 128 字节 RAM 不够用了,把不必要的大数组挪到code段,或者把unsigned int降级成unsigned char。
5.2 在 Proteus 里核对时序
Proteus 里搭好电路后,加载 HEX 文件之前先把元件和接法核对一遍。常用的几个模型是 AT89C51、LM016L(1602 的仿真模型)、DS18B20。DS18B20 模型在仿真时不一定严格复现 750ms 转换时间和微秒级时序,所以它验证的是"逻辑通不通",不是"时序准不准"。仿真时看到湿度数字在变、水位按下后继电器释放、蜂鸣器响,主逻辑就对了。
仿真的真正价值在两处:一是抓 P1.2 波形,看复位脉冲有没有到 480μs、存在脉冲有没有出现;二是用单步执行配合变量观察窗,看calc_rh的中间值。如果仿真里 DS18B20 一直返回 85,先把READ里采样点的 NOP 数量加两个试试。
5.3 上板烧录与首次上电检查
烧录用 STC-ISP 走串口是最方便的,前提是芯片换成了 STC89C52RC;如果坚持用 AT89C51,就得靠编程器或者专用仿真器写入。烧录前把 HEX 路径、芯片型号、串口号三项核对一遍,尤其是串口号——插拔几次 USB 转串口线后 COM 号会变,选错会一直提示"正在检测单片机"。
首次上电按这个顺序看:液晶背光亮不亮(P2.7 和驱动管)→ 第一行有没有出现字符(P0 上拉和初始化延时)→ 温度值是不是接近室温 → 按下低水位按键时继电器是否立刻断开。这个顺序从电源到通信再到逻辑,出问题能快速缩小范围。
5.4 常见故障对照表
| 现象 | 最可能原因 | 排查动作 |
|---|---|---|
| 液晶全黑块或全空白 | 对比度电位器没调 / P0 排阻未接 | 调 10kΩ 电位器,量 P0.0 静态电平 |
| 显示乱码 | 初始化延时不足,未等 15ms | 在初始化开头补 15ms 以上延时 |
| 温度恒为 85℃ | 转换未完成或时序被优化打乱 | 延时加到 750ms,时序文件关优化 |
| 温度恒为 0℃ | 跳过 ROM 命令用错(多挂场合) | 改 0x55 + 匹配 ROM,或拆成两根 I/O |
| 继电器反复吸合 | 单点阈值判断,无滞回 | 开启/停止阈值拉开 10%RH 以上 |
| 上电不启动,按复位才行 | 复位电容过大,RC 爬升太慢 | 电容降到 10μF 以内,加泄放二极管 |
| 蜂鸣器只有"嗒"一声 | 无源蜂鸣器被当有源用 | 改用定时器输出方波,或换有源蜂鸣器 |
上电那一下拿示波器抓 P1.2 的复位脉冲,480μs 拉低加 60μs 存在脉冲这段波形对上了,剩下的基本都是应用层逻辑问题,调试会快很多。
本文还有配套的精品资源,点击获取