双51单片机智能照明控制器:光敏检测与定时两开两关设计

📅 发布时间:2026/9/19 12:17:26
双51单片机智能照明控制器:光敏检测与定时两开两关设计
简介这是一份基于AT89S52单片机的照明灯智能控制器毕业设计文档面向电子、自动化及嵌入式相关专业学生和单片机爱好者。内容从课题背景、芯片选型到系统硬/软件设计层层展开重点讲解AT89S52、AT89C2051与LCD1602的引脚功能及连接方式并给出夜用照明系统、光敏接收电路、按键调光、报警电路、复位晶振电路等模块的实现方法软件部分采用C语言结合KEIL C51编写附完整程序清单可作为课程设计或毕业论文的参考模板。资源为1个doc文件压缩包大小676KB内容完整目前已有276人学习下载。文档末尾还介绍了PROTEL 99SE绘制原理图与PCB的流程以及软硬件调试思路能帮助读者快速掌握单片机智能照明控制系统的整体设计框架是一份实用性与参考价值兼备的资料。1. 深夜关灯这件事为什么值得用两颗 51 去做过道灯、草坪灯、广告箱灯这类公共照明凌晨没人时整夜亮着浪费的不只是电费还有灯具寿命。这个项目用 AT89S52 维护 LCD1602 显示的标准时钟AT89C2051 用内部模拟比较器读光敏电阻两个芯片通过 P3.7 联动最终用双向可控硅控制灯具通断。它实现的“两开两关”是天黑后自动开灯4 小时后关灯天亮前 1 小时再开灯天亮后自动关。对做 51 课程设计、智能照明控制器原型或想把手边的灯改造成按时段和照度协同工作的装置这套方案的选型逻辑、可控硅触发和中断时序都值得拆开看一遍。2. 芯片选型与分工AT89S52、AT89C2051 与 LCD1602 的引脚级连接一个照明控制器而已为什么用两颗单片机这是拆这个项目时最先要回答的问题。AT89S52 没有片内 ADC也没集成模拟比较器直接拿它读光敏电阻只能靠外接 LM393 之类的比较器AT89C2051 虽然有 2K Flash、128 字节 RAM但驱动 1602、按键、可控硅和电铃就吃力了。所以文档给出的方案是让 AT89C2051 专门做照度阈值判断AT89S52 专门做时钟维护和控制输出。如果换用带 ADC 的 STC 单片机确实一颗就能搞定但通过这个双片结构能更清楚看到“感知”和“控制”在嵌入式系统里是如何拆解的。2.1 为什么是 AT89S52 加 AT89C2051一个做时间一个做照度AT89S52 的核心资源是 8K 字节 Flash、256 字节 RAM、32 根 I/O 线、3 个 16 位定时器/计数器、全双工串口还带 ISP 下载接口P1.5/MOSI、P1.6/MISO、P1.7/SCK 三个引脚可以实现在系统编程。做标准时钟、LCD1602 显示、按键扫描、可控硅控制都够用。AT89C2051 是 20 脚封装的精简版 51只有 15 根 I/O 线但它内部带一个精密模拟比较器同相输入端是 P1.0/AIN0反相输入端是 P1.1/AIN1正好用来做光敏电阻的阈值比较不需要额外接 ADC 芯片。两个芯片之间不需要串口协议一根线就把“天黑/天亮”事件传过去AT89C2051 检测照度变化后由程序把比较结果反映到 P3.7 引脚AT89S52 的 P3.7 作为输入读取。这里有个容易被忽略的点AT89C2051 的比较器输出在芯片内部并不直接对应某个外露引脚必须先读比较器状态位再通过普通 I/O 输出。如果照着手册以为 P3.6 会自动跟着比较器翻转程序就会读不到正确电平。2.2 引脚级连接LCD1602 模拟口线、光敏输入与可控硅控制整体引脚分配可以整理成表画原理图之前先把这张表定下来后面画 PCB 能少走很多弯路。功能模块AT89S52 引脚AT89C2051 引脚说明LCD1602 DB0--DB7P0.0--P0.7经 74HC573 锁存无P0 口是开漏输出需要 10k 上拉排阻LCD1602 RS/RW/EP2.3 / P2.4 / P2.5无模拟口线方式读写时序靠软件翻转光敏分压输入无P1.0(AIN0) / P1.1(AIN1)内部模拟比较器的同相/反相输入阈值调整无1RP 电位器调节光敏分压点联动信号P3.7 输入P3.7 输出只传“暗/亮”电平事件照明驱动P1.7 输出无经 Q1 三极管触发双向可控硅电铃驱动P3.5 输出无经 Q2 三极管驱动 BELL独立按键P1.0--P1.3无按键另一端接 GND内部上拉晶振/复位XTAL1/XTAL2、RSTXTAL1(Pin4)/XTAL2(Pin5)、RST(Pin1)12MHz 晶振RC 复位LCD1602 的数据端接到 74HC573 时很多人会忘记 P0 口需要上拉。P0 作为输出时可以驱动 8 个 TTL 输入但它是漏极开路结构高电平必须靠外部上拉电阻提供。10k 排阻是常见选择如果上拉阻值太大LCD1602 的数据线上升沿会变缓高速读写时容易出现乱码用 4.7k 会更稳但功耗略高。RS、RW、E 不用经过锁存器直接用 P2 口控制这样的“模拟口线”方式好处是省引脚、接线直观代价是读写时序全靠延时函数把握。2.3 最小系统的边界参数7805、晶振和复位电源部分用 7805 稳压输入建议用 9V 到 12V 直流。7805 输入输出压差至少 2V低于这个值输出会掉出 5V。整个系统电流主要是 LCD1602 背光加两片单片机大约 50 到 100mA7805 小封装长时间运行建议加一个小散热片。晶振选 12MHz 时51 的机器周期是 1us定时器最长定时 65.536ms所以常见的做法是定时器设 50ms再软件计数 20 次得到 1 秒。复位电路用 10uF 电容加 10k 电阻即可上电瞬间 RST 拉高之后电容充电使 RST 回到低电平12MHz 下只要高电平维持 2us 就能复位RC 时间常数做到 100ms 已经留足余量。3. 光敏检测、可控硅触发与 PCB 实现的硬件细节硬件部分真正决定“能不能稳定工作”的不是单片机最小系统而是光敏检测电路、可控硅驱动链和 PCB 布局。原文档把这几个模块拆得很清楚这里按复现顺序逐个说。3.1 光敏接收电路分压阈值与比较器读法光敏电阻的阻值随照度变化光照强时阻值降到几 kΩ暗态时能到几百 kΩ 甚至 1MΩ 以上。AT89C2051 的 P1.0 和 P1.1 是内部比较器的两个模拟输入端只需要把光敏电阻和一个电位器组成分压网络比较器的翻转点就会随光照变化。常见接法是光敏电阻 R7 接 VCC电位器 1RP 接 GND中点进 P1.0P1.1 接一个固定分压作为参考。电位器阻值一般选 47k 或 100k调它就是在调“天暗到什么程度算黑夜”。由于比较器没有迟滞光敏信号在临界点附近会抖动软件里要做消抖比如连续读两次状态一致才更新结果硬件上也可以在分压中点对地并联一个 0.1uF 电容滤掉工频干扰。环境状态光敏电阻阻值典型范围P1.0 电位变化判断结果白天强光照1k--10k接近 VCC天亮傍晚弱光10k--100k随照度下降临界区夜间100k--1M接近 GND天黑这里要特别注意AT89C2051 的 P1.0 和 P1.1 作为模拟输入时不要使能内部上拉否则等于给比较器输入端并联了一个电阻会直接改变翻转阈值。原文档中提到的 1RP 就是用来标定这个临界点的。3.2 可控硅照明与电铃报警一条低电平触发的驱动链照明部分不是用继电器而是用双向可控硅 SD 做主回路。控制逻辑是AT89S52 的 P1.7 输出低电平时NPN 三极管 Q1 饱和导通给可控硅触发极提供触发电流可控硅导通灯泡 LAMP 点亮P1.7 输出高电平时 Q1 截止可控硅在交流电流过零后自然关断。文档里画的是一颗三极管直接驱动双向可控硅这种接法在实验室验证没问题但控制板的地和 220V 主回路之间会有耦合调试时有触电风险。实际做产品我一般会在单片机和可控硅之间加一个 MOC3021 光耦配合 330Ω 左右的限流电阻做隔离如果负载是灯这类阻性负载还需在可控硅两端并联 RC 吸收电路防止关断瞬间的电压尖峰触发误导通。三极管基极电阻用 1k 到 4.7k阻值太大触发电流会不足可控硅会在每个半周边缘抖动灯看起来就是闪烁的。电铃部分由 P3.5 控制 Q2 和 BELL同样是低电平导通。文档没有把电铃的触发条件写死一个常见用途是在天黑开灯时让电铃短响一声作为事件联动的提示。如果用的是直流蜂鸣器必须并联续流二极管如果直接驱动交流电铃也要经过可控硅不能让单片机的 I/O 直接碰高电压。3.3 独立按键、复位与晶振的接线按键调时部分用的是独立式按键P1.0 到 P1.3 各接一个按键另一端接 GND。51 的 P1 口内部有上拉按下时读到 0松开时读到 1软件在检测到下降沿后延时 20ms 再确认一次消抖即可。按键不要放在 P1.5 到 P1.7 上因为这三个脚是 ISP 下载用的 MOSI、MISO、SCK被按键电路占用后在线下载会出问题。复位和晶振是两片单片机都需要的。AT89S52 的 XTAL1/XTAL2 是 18/19 脚AT89C2051 的 OSC1/OSC2 是 4/5 脚画 PCB 时特别容易按 40 脚封装的习惯想当然。晶振的两个负载电容要用 20 到 30pF并且尽量靠近单片机引脚放置走线不要太长。RST 引脚典型接法都是 10uF 电容到 VCC、10k 电阻到 GND按这个参数来基本不用改。3.4 Protel 99SE 下单面板绘制要留意的几个坑原文档用 Protel 99SE 画原理图和单面板 PCB。单面板只有底层铜箔跳线不可避免但布局顺序对的话跳线数量能压到很少。我一般这样排先放接口和电源电源输入端子、7805、滤波电容在板边强电区与弱电区要拉开距离。再放两片单片机AT89S52 和 AT89C2051 各自的最小系统尽量围绕芯片布置晶振、复位、去耦电容就近放。弱信号线优先光敏电阻和电位器属于敏感节点走线要短要远离 220V 走线和可控硅否则开关灯瞬间的干扰会把比较器输出打翻。可控硅属于强电区和弱电区之间至少留 3mm 间距条件允许就开槽。LCD1602 是 16 针排针不是双列直插封装生成 PCB 前确认封装引脚间距是 2.54mm。Protel 99SE 的封装库比较老AT89C2051 的 DIP20、AT89S52 的 DIP40、74HC573 的 DIP20 一般都有但 LCD1602 常常需要自己画。封装引脚和实际器件不一致是焊接调试时最难查的问题之一画完一定要用 DRC 检查网络和间距。4. Keil C51 下的定时器中断、LCD1602 驱动与两开两关状态机软件部分的核心不是循环里一堆 if而是先把“标准时钟”跑准再让灯的状态跟着时间和照度事件走。文档附页的源程序没有公开下面给出按原项目逻辑整理的可编译骨架在 Keil C51 里可以直接建工程验证。4.1 定时器中断做标准时钟50ms 累积 20 次为 1 秒AT89S52 的定时器 0 用方式 1也就是 16 位定时器。12MHz 晶振下机器周期 1us50ms 需要计数 50000初值是 65536 减 50000 等于 15536十六进制就是 0x3CB0。中断函数里每次重装初值并累积计数到 20 次就把秒变量加 1。#include REG52.H #define T0_MS 50 unsigned int t_count 0; unsigned char sec 0, min 0, hour 0; void timer0_init(void) { TMOD 0xF0; // 只改定时器0保留定时器1的配置 TMOD | 0x01; // 定时器0方式116位定时器 TH0 0x3C; // 50ms初值高8位 TL0 0xB0; // 50ms初值低8位 ET0 1; // 允许定时器0中断 EA 1; // 打开总中断 TR0 1; // 启动定时器0 } void timer0_isr(void) interrupt 1 { TH0 0x3C; // 中断里重新装入初值 TL0 0xB0; if (t_count 20) { // 20次 * 50ms 1秒 t_count 0; if (sec 60) { sec 0; if (min 60) { min 0; if (hour 24) hour 0; } } } }这段代码里TMOD 0xF0是为了不动定时器 1 的高四位配置TMOD | 0x01把定时器 0 设成方式 1。中断函数中重装初值会带来几微秒的误差一天累计大约快半秒对电子钟显示可以接受如果要求更高精度可以把定时器 2 配成自动重载模式或改用外部 RTC 芯片。主循环读取hour、min、sec时最好先关中断拷贝一份再恢复中断避免读到中间状态。4.2 LCD1602 模拟口线驱动初始化序列和 E 脉冲LCD1602 的数据线接在 P0 并经 74HC573 锁存RS、RW、E 直接由 P2.3、P2.4、P2.5 控制。写数据的顺序是先设置 RS/RW再往 P0 送数据最后给出一个 E 高脉冲数据在 E 下降沿被锁存进去。sbit LCD_RS P2^3; sbit LCD_RW P2^4; sbit LCD_E P2^5; void lcd_write_cmd(unsigned char cmd) { LCD_RS 0; // 命令模式 LCD_RW 0; // 写操作 P0 cmd; // 数据送P0经74HC573锁存到LCD LCD_E 1; LCD_E 0; // 产生E下降沿 delay_ms(2); // 命令执行时间约2ms } void lcd_init(void) { delay_ms(15); // 上电等待 lcd_write_cmd(0x38); delay_ms(5); lcd_write_cmd(0x38); delay_ms(5); lcd_write_cmd(0x38); delay_ms(5); lcd_write_cmd(0x08); // 显示关闭 lcd_write_cmd(0x01); // 清屏 lcd_write_cmd(0x06); // 写入后地址加1 lcd_write_cmd(0x0C); // 开显示不显示光标 }初始化时连续写三次 0x38是为了确保 HD44780 在上电后进入 8 位数据模式。0x38 的含义是 16x2 显示、5x7 点阵、8 位数据接口。清屏指令 0x01 执行时间最长数据手册上写约 1.64ms实际用延时 5ms 更保险。如果不做忙检测命令和命令之间至少要留 2ms清屏和回车这类指令留 5ms。4.3 两开两关状态机用光敏事件修正定时起点“两开两关”不能简单写死 19 点开、23 点关、5 点开、6 点关因为天黑和天亮时间随季节变化。原文档的意图是让光敏电阻参与判断用实际检测到的天黑事件去修正定时起点。AT89S52 通过 P3.7 读到 AT89C2051 发来的暗亮电平然后驱动状态机。sbit LAMP P1^7; // 低电平点亮 sbit DARK P3^7; // 约定1天黑 enum { S_DAY, S_NIGHT_ON, S_NIGHT_OFF, S_DAWN_ON } state S_DAY; unsigned char night_hour 19; // 默认天黑时刻光敏事件会更新 void lamp_task(void) { bit dark_now; dark_now DARK; switch (state) { case S_DAY: // 白天等待天黑 if (dark_now) { night_hour hour; // 记录实际天黑时刻 LAMP 0; // 天黑开灯 state S_NIGHT_ON; } break; case S_NIGHT_ON: // 天黑后照明 if ((hour * 60 min) (night_hour * 60 240)) { LAMP 1; // 4小时后关灯 state S_NIGHT_OFF; } break; case S_NIGHT_OFF: // 深夜熄灭等待天亮前1小时 if (hour 5 hour 6) { // 默认5点到6点可调 LAMP 0; // 天亮前1小时开灯 state S_DAWN_ON; } break; case S_DAWN_ON: // 天亮前照明 if (!dark_now) { // 光敏转亮判断天亮 LAMP 1; // 天亮关灯 state S_DAY; } break; } }这个状态机的重点是天黑开灯的基准时间来自光敏事件而非固定常量所以季节变化时night_hour会被自动更新后面的 4 小时关灯也随之推移。天亮前 1 小时的窗口用hour 5 hour 6只是默认值实际应该做成可配置项由按键调整或者根据前一天夜晚时长推算出天亮时间。P3.7 的信号是 AT89C2051 比较器判断后的结果判断本身已经在另一颗芯片里完成AT89S52 这边只需要做防抖连续两次读到相同值再认可状态变化。5. 联调时最容易翻车的三个环节阈值标定、触发沿与总线时序硬件和软件都完成后再合在一起调问题往往集中在三个点上光敏阈值没标定、可控硅触发电流不够、LCD1602 时序不对。逐个处理完这个系统基本就能稳定跑了。5.1 光敏阈值的标定步骤标定前先准备万用表和一把小螺丝刀最好再有一块能测照度的手机 App。步骤如下测量光敏电阻在暗环境和亮环境下的阻值确认分压范围符合预期。把系统调到傍晚照度或者用遮光物挡住光敏电阻观察 AT89C2051 的比较电平是否翻转。调节 1RP让比较电平在目标照度临界点附近刚好翻转。翻转点定好后再往回收一点留出约 10% 的回差余量。如果临界点附近抖动在分压中点对地加 0.1uF 电容或者软件连续采样三次一致才更新状态。如果白天实测光敏电阻只有几 kΩ而暗态有几百 kΩ电位器选 47k 到 100k 比较合适。电位器阻值选得太小光敏电阻的动态范围会被压缩很难找到一个稳定的临界点。5.2 用示波器确认可控硅触发沿灯具控制的问题不容易用万用表直接看出来最好用示波器探头测可控硅触发极观察灯点亮时 G 极是否有稳定的电平或脉冲。常见的坑有三个三极管基极电阻取值太大导致触发电流不足可控硅没有 RC 吸收电路感性负载关断时误触发P1.7 上电瞬间是默认高电平灯不会误亮但 P3.5 控制的电铃可能在上电瞬间动作一下必要时在 Q2 基极加一个 10k 下拉电阻。调试 220V 侧时一定注意隔离示波器要用隔离探头或者只测控制板低压部分高压主回路用万用表确认通断。5.3 Keil 仿真与实物差异Keil C51 的 dScope 可以验证定时器逻辑把断点设在if (t_count 20)这一行运行后观察sec是否按预期加 1。但仿真环境里没有真实的光敏电阻和可控硅这两部分必须靠实物调。LCD1602 上电后如果第一行全是黑块、第二行正常优先检查 VLCD 对比度电压把对比度电位器调到 1V 左右通常能解决。如果屏幕完全无显示先量 RST 在复位结束后是否回到低电平再查 P0 口上拉排阻公共端是否接 VCC以及 74HC573 的 OE 是否接地。上电后 LCD 第一行一直白块、第二行正常这是我复现这类 1602 时钟时最先会查的地方。本文还有配套的精品资源点击获取