主要内容:传统台灯仅具备基础照明功能,无法兼顾用眼健康、智能管控与多样化使用需求本设计以单片机为核心主控单元,融合传感器检测、按键控制、显示与声光报警技术开发一款集人体检测、距离监测、环境光自适应调光、多模式切换于一体的多功能智台灯系统。系统可实现有人检测、近距离护眼报警、多档位亮度调节、本地按键控制功能,兼顾实用性、智能化与护眼特性,同时完成硬件电路搭建、软件程序编写、实调试与整体功能验证,打造低成本、易实现、稳定性强的嵌入式智能照明设备。。基本要求:1·搭载红外传感器识别人体存在,配合超声波传感器实时检测人与台灯距离,距离过时蜂鸣器触发报警,实现护眼提醒。。2.设置多档位工作模式,通过实体按键完成智能模式、按键模式两种模式自由切换。3.智能模式下,结合光敏电阻采集环境光照强度,自动划分低、中、高三档亮度并自应调光;红外检测无人时,台灯自动熄灭。4,按键模式下,通过独立按键手动切换灯光亮度档位。5·配备显示屏,实时展示系统工作模式、灯光亮度、检测距离等运行状态数据。
- #include <reg52.h>
- #include <intrins.h>
- // ===================== 引脚定义(保持与你的原理图一致)=====================
- sbit echo = P2^3; // 超声波 Echo
- sbit trig = P2^4; // 超声波 Trig
- sbit led1 = P1^4; // 自动模式指示灯
- sbit led2 = P1^6; // 手动模式指示灯
- sbit LED_1 = P2^0; // 远光灯
- sbit LED_2 = P2^1; // 近光灯
- sbit key1 = P3^2; // 设置
- sbit key2 = P3^3; // 增加
- sbit key3 = P3^4; // 减小
- sbit key4 = P3^5; // 手动/自动
- sbit key5 = P3^6; // 手动远光/近光切换
- sbit key6 = P3^7; // 手动关灯
- // ===================== LCD1602 驱动(直接写在文件中,避免外部头文件)=====================
- #define LCD_DATA P0
- sbit LCD_RS = P2^5;
- sbit LCD_RW = P2^6;
- sbit LCD_EN = P2^7;
- void LCD1602_WriteCmd(unsigned char cmd) {
- LCD_RS = 0; LCD_RW = 0;
- LCD_DATA = cmd;
- LCD_EN = 1; _nop_(); _nop_(); LCD_EN = 0;
- for(unsigned char i=0; i<5; i++); // 短暂延时
- }
- void LCD1602_WriteData(unsigned char dat) {
- LCD_RS = 1; LCD_RW = 0;
- LCD_DATA = dat;
- LCD_EN = 1; _nop_(); _nop_(); LCD_EN = 0;
- for(unsigned char i=0; i<5; i++);
- }
- void LCD1602_Init(void) {
- LCD1602_WriteCmd(0x38);
- LCD1602_WriteCmd(0x0C);
- LCD1602_WriteCmd(0x06);
- LCD1602_WriteCmd(0x01);
- for(unsigned int i=0; i<1000; i++); // 等待清屏完成
- }
- void LCD1602_ShowString(unsigned char x, unsigned char y, unsigned char *str) {
- unsigned char addr = y ? (0xC0 + x) : (0x80 + x);
- LCD1602_WriteCmd(addr);
- while(*str) LCD1602_WriteData(*str++);
- }
- // 写一个字符到指定位置
- void LCD1602_WriteChar(unsigned char x, unsigned char y, unsigned char ch) {
- unsigned char addr = y ? (0xC0 + x) : (0x80 + x);
- LCD1602_WriteCmd(addr);
- LCD1602_WriteData(ch);
- }
- // ===================== ADC0832 驱动(直接实现)=====================
- sbit ADC_CS = P1^3;
- sbit ADC_CLK = P1^0;
- sbit ADC_DO = P1^1;
- sbit ADC_DI = P1^2;
- unsigned char ADC0832_Read(unsigned char channel) {
- unsigned char i, dat = 0;
- channel &= 0x01;
- ADC_CS = 0;
- // 起始位
- ADC_CLK = 0; _nop_(); ADC_CLK = 1; _nop_();
- ADC_DI = 1;
- ADC_CLK = 0; _nop_(); ADC_CLK = 1; _nop_();
- // 通道选择: 单端模式
- ADC_DI = 1; // 单端
- ADC_CLK = 0; _nop_(); ADC_CLK = 1; _nop_();
- ADC_DI = channel;
- ADC_CLK = 0; _nop_(); ADC_CLK = 1; _nop_();
- ADC_DI = 0;
- // 读数据
- for(i=0; i<8; i++) {
- dat <<= 1;
- ADC_CLK = 0; _nop_();
- if(ADC_DO) dat |= 0x01;
- ADC_CLK = 1; _nop_();
- }
- ADC_CS = 1;
- return dat;
- }
- // ===================== 全局变量 ======================
- unsigned int time=0;
- int S=50; // 当前距离(cm),初始50cm,仿真时可手动改变
- unsigned int distance; // 超声波时间中间量
- bit ir_ok = 0; // 定时测量标志
- bit key1_flag=0, key2_flag=0, key3_flag=0, key4_flag=0, key5_flag=0, key6_flag=0;
- unsigned char sec1=0, sec2=0, ms=0;
- unsigned char light_set=50, S_set=30, state=0; // 设置阈值
- bit s0; // 闪烁标志
- bit memory_flag=0;
- unsigned char light=0, ad_count=0;
- unsigned int ad_dat=0;
- unsigned char beam=0; // 0关 1近光 2远光
- bit A_M=0; // 0手动 1自动
- unsigned char count=0;
- // 仿真辅助:手动改变距离(按增加/减小键直接修改S)
- // 注意:只在非设置状态且自动模式下才允许手动修改当前距离(方便调试)
- bit sim_manual_distance = 1; // 设为1表示允许手动改距离,设为0则使用真实超声波
- // 超声波超时退出用
- bit timeout_flag;
- // ===================== 函数声明 ======================
- void trigger(void);
- void measuring(void);
- void init_measuring(void);
- void interrupt_int(void);
- void display(void);
- void AD_dispose(void);
- void key_scan(void);
- void police(void);
- void delayt(unsigned int x);
- // ===================== 超声波相关函数 ======================
- void trigger(void) {
- trig = 0;
- _nop_();_nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();_nop_();
- trig = 1;
- }
- void init_measuring(void) {
- trig = 1;
- echo = 1;
- count = 0;
- }
- void measuring(void) {
- unsigned char l;
- unsigned int h, y;
- TR0 = 1;
- // 等待echo变低,带超时
- unsigned int to = 0;
- while(echo == 1 && to < 60000) to++;
- TR0 = 0;
- if(to >= 60000) { // 超时,无效测量
- return;
- }
- l = TL0;
- h = TH0;
- y = (h << 8) + l;
- y = y - 0xfc66; // 补偿
- distance = y + 1000 * count;
- TL0 = 0x66;
- TH0 = 0xfc;
- delayt(30);
- // 声速345m/s,计算距离cm
- S = (unsigned long)3453 * distance / 200000;
- if(S > 400) S = 400;
- }
- // ===================== 定时器初始化 ======================
- void interrupt_int(void) {
- TMOD = 0x11;
- TH0 = 0x00; TL0 = 0x00;
- ET0 = 1;
- TR0 = 0;
- TH1 = 0x3c; TL1 = 0xb0;
- ET1 = 1;
- TR1 = 1;
- EA = 1;
- }
- // ===================== LCD 显示 ======================
- void display(void) {
- unsigned char str[17];
- if(state == 0) {
- LCD1602_ShowString(0, 0, "distance: ");
- // 显示距离数值(右对齐)
- LCD1602_WriteChar(9, 0, '0' + S/100%10);
- LCD1602_WriteChar(10,0, '0' + S/10%10);
- LCD1602_WriteChar(11,0, '0' + S%10);
- LCD1602_ShowString(12,0, "cm");
-
- LCD1602_ShowString(0, 1, "light: ");
- LCD1602_WriteChar(6, 1, '0' + light/100%10);
- LCD1602_WriteChar(7, 1, '0' + light/10%10);
- LCD1602_WriteChar(8, 1, '0' + light%10);
- LCD1602_ShowString(9, 1, "%");
- }
- else if(state == 1) {
- LCD1602_ShowString(0, 0, "dis_set: ");
- if(state==1 && s0) {
- LCD1602_ShowString(8,0, " ");
- } else {
- LCD1602_WriteChar(8,0, '0' + S_set/100%10);
- LCD1602_WriteChar(9,0, '0' + S_set/10%10);
- LCD1602_WriteChar(10,0,'0' + S_set%10);
- }
- LCD1602_ShowString(11,0, "cm");
- LCD1602_ShowString(0,1, "lig_set: ");
- LCD1602_WriteChar(8,1, '0' + light_set/100%10);
- LCD1602_WriteChar(9,1, '0' + light_set/10%10);
- LCD1602_WriteChar(10,1,'0' + light_set%10);
- LCD1602_ShowString(11,1, "%");
- }
- else if(state == 2) {
- LCD1602_ShowString(0,0, "dis_set: ");
- LCD1602_WriteChar(8,0, '0' + S_set/100%10);
- LCD1602_WriteChar(9,0, '0' + S_set/10%10);
- LCD1602_WriteChar(10,0,'0' + S_set%10);
- LCD1602_ShowString(11,0,"cm");
- LCD1602_ShowString(0,1,"lig_set: ");
- if(state==2 && s0) {
- LCD1602_ShowString(8,1, " ");
- } else {
- LCD1602_WriteChar(8,1, '0' + light_set/100%10);
- LCD1602_WriteChar(9,1, '0' + light_set/10%10);
- LCD1602_WriteChar(10,1,'0' + light_set%10);
- }
- LCD1602_ShowString(11,1,"%");
- }
- }
- // ===================== 光照采集 ======================
- void AD_dispose(void) {
- if(ad_count < 10) {
- ad_dat += ADC0832_Read(0);
- ad_count++;
- } else {
- light = ad_dat / 10;
- light = (unsigned long)light * 100 / 255;
- ad_count = 0;
- ad_dat = 0;
- }
- }
- // ===================== 按键扫描 ======================
- void key_scan(void) {
- // key1 设置
- if(!key1) {
- if(key1_flag) {
- key1_flag = 0;
- state = (state+1) % 3;
- }
- } else key1_flag = 1;
-
- // key2 增加
- if(!key2) {
- if(key2_flag) {
- key2_flag = 0;
- if(state == 1 && S_set < 400) S_set++;
- else if(state == 2 && light_set < 100) light_set++;
- // 在非设置状态且允许手动距离仿真时,按增加键增加当前距离S
- else if(state == 0 && sim_manual_distance && S < 400) S++;
- }
- if(sec2 == 0) {
- if(state == 1 && S_set < 400) S_set++;
- else if(state == 2 && light_set < 100) light_set++;
- else if(state == 0 && sim_manual_distance && S < 400) S++;
- }
- memory_flag = 1;
- } else {
- key2_flag = 1; sec2 = 2;
- }
-
- // key3 减小
- if(!key3) {
- if(key3_flag) {
- key3_flag = 0;
- if(state == 1 && S_set > 0) S_set--;
- else if(state == 2 && light_set > 0) light_set--;
- else if(state == 0 && sim_manual_distance && S > 0) S--;
- }
- if(sec1 == 0) {
- if(state == 1 && S_set > 0) S_set--;
- else if(state == 2 && light_set > 0) light_set--;
- else if(state == 0 && sim_manual_distance && S > 0) S--;
- }
- memory_flag = 1;
- } else {
- key3_flag = 1; sec1 = 2;
- }
-
- // key4 手动/自动
- if(!key4) {
- if(key4_flag) {
- key4_flag = 0;
- A_M = !A_M;
- if(A_M == 0) beam = 0;
- }
- } else key4_flag = 1;
-
- // key5 手动远光/近光
- if(!key5) {
- if(key5_flag) {
- key5_flag = 0;
- if(A_M == 0) {
- if(beam == 1) beam = 2;
- else beam = 1;
- }
- }
- } else key5_flag = 1;
-
- // key6 手动关灯
- if(!key6) {
- if(key6_flag) {
- key6_flag = 0;
- if(A_M == 0) beam = 0;
- }
- } else key6_flag = 1;
- }
- // ===================== 自动模式逻辑 ======================
- void police(void) {
- if(light < light_set) { // 天黑
- if(S > S_set) beam = 2; // 远光
- else beam = 1; // 近光
- } else beam = 0;
- }
- // ===================== 延时 ======================
- void delayt(unsigned int x) {
- unsigned char j;
- while(x--) for(j=0; j<125; j++);
- }
- // ===================== 主函数 ======================
- void main(void) {
- interrupt_int();
- LCD1602_Init();
- // 简单显示欢迎界面
- LCD1602_ShowString(0,0, " Auto Light ");
- LCD1602_ShowString(0,1, " V1.0 Ready ");
- delayt(500);
-
- init_measuring();
-
- while(1) {
- display();
-
- if(ir_ok) {
- ir_ok = 0;
- if(!sim_manual_distance) {
- trigger();
- // 等待 echo 变高,带超时避免卡死
- unsigned int to = 0;
- while(echo == 0 && to < 60000) to++;
- if(to < 60000) {
- measuring();
- }
- init_measuring();
- }
- // 如果 sim_manual_distance==1,S 已经在按键中修改,不需要超声波
- }
-
- if(memory_flag) {
- memory_flag = 0;
- // 模拟存储(实际项目中可写入EEPROM,这里空操作)
- }
-
- if(A_M) {
- led1 = 0; led2 = 1;
- police();
- } else {
- led2 = 0; led1 = 1;
- }
-
- AD_dispose();
-
- switch(beam) {
- case 0: LED_1=1; LED_2=1; break;
- case 1: LED_1=1; LED_2=0; break;
- case 2: LED_1=0; LED_2=1; break;
- }
- }
- }
- // ===================== 定时器中断 ======================
- void timer0(void) interrupt 1 {
- // 用于超声波测距,空
- }
- void timer1(void) interrupt 3 {
- TH1 = 0x3c; TL1 = 0xb0;
- ms++;
- key_scan();
- if(ms % 4 == 0) {
- ir_ok = 1;
- s0 = ~s0;
- }
- if(ms >= 20) {
- ms = 0;
- if(sec1 != 0) sec1--;
- if(sec2 != 0) sec2--;
- }
- }
复制代码
|