双51单片机智能照明控制器:光敏检测与定时两开两关设计
2026/9/19 12:17:18 网站建设 项目流程

简介:这是一份基于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 到 100mA,7805 小封装长时间运行建议加一个小散热片。晶振选 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.0;P1.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。单面板只有底层铜箔,跳线不可避免,但布局顺序对的话,跳线数量能压到很少。我一般这样排:

  1. 先放接口和电源:电源输入端子、7805、滤波电容在板边,强电区与弱电区要拉开距离。
  2. 再放两片单片机:AT89S52 和 AT89C2051 各自的最小系统尽量围绕芯片布置,晶振、复位、去耦电容就近放。
  3. 弱信号线优先:光敏电阻和电位器属于敏感节点,走线要短,要远离 220V 走线和可控硅,否则开关灯瞬间的干扰会把比较器输出打翻。
  4. 可控硅属于强电区,和弱电区之间至少留 3mm 间距,条件允许就开槽。
  5. 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 晶振下机器周期 1us,50ms 需要计数 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,方式1:16位定时器 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 芯片。主循环读取hourminsec时,最好先关中断拷贝一份,再恢复中断,避免读到中间状态。

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。步骤如下:

  1. 测量光敏电阻在暗环境和亮环境下的阻值,确认分压范围符合预期。
  2. 把系统调到傍晚照度,或者用遮光物挡住光敏电阻,观察 AT89C2051 的比较电平是否翻转。
  3. 调节 1RP,让比较电平在目标照度临界点附近刚好翻转。
  4. 翻转点定好后,再往回收一点,留出约 10% 的回差余量。
  5. 如果临界点附近抖动,在分压中点对地加 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 时钟时最先会查的地方。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询