找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3|回复: 0
打印 上一主题 下一主题
收起左侧

基于单片机的多功能智能台灯系统设计 附程序

[复制链接]
跳转到指定楼层
楼主
主要内容:传统台灯仅具备基础照明功能,无法兼顾用眼健康、智能管控与多样化使用需求本设计以单片机为核心主控单元,融合传感器检测、按键控制、显示与声光报警技术开发一款集人体检测、距离监测、环境光自适应调光、多模式切换于一体的多功能智台灯系统。系统可实现有人检测、近距离护眼报警、多档位亮度调节、本地按键控制功能,兼顾实用性、智能化与护眼特性,同时完成硬件电路搭建、软件程序编写、实调试与整体功能验证,打造低成本、易实现、稳定性强的嵌入式智能照明设备。。基本要求:1·搭载红外传感器识别人体存在,配合超声波传感器实时检测人与台灯距离,距离过时蜂鸣器触发报警,实现护眼提醒。。2.设置多档位工作模式,通过实体按键完成智能模式、按键模式两种模式自由切换。3.智能模式下,结合光敏电阻采集环境光照强度,自动划分低、中、高三档亮度并自应调光;红外检测无人时,台灯自动熄灭。4,按键模式下,通过独立按键手动切换灯光亮度档位。5·配备显示屏,实时展示系统工作模式、灯光亮度、检测距离等运行状态数据。

  1. #include <reg52.h>
  2. #include <intrins.h>


  3. // ===================== 引脚定义(保持与你的原理图一致)=====================
  4. sbit echo = P2^3;   // 超声波 Echo
  5. sbit trig = P2^4;   // 超声波 Trig
  6. sbit led1 = P1^4;   // 自动模式指示灯
  7. sbit led2 = P1^6;   // 手动模式指示灯
  8. sbit LED_1 = P2^0;  // 远光灯
  9. sbit LED_2 = P2^1;  // 近光灯


  10. sbit key1 = P3^2;   // 设置
  11. sbit key2 = P3^3;   // 增加
  12. sbit key3 = P3^4;   // 减小
  13. sbit key4 = P3^5;   // 手动/自动
  14. sbit key5 = P3^6;   // 手动远光/近光切换
  15. sbit key6 = P3^7;   // 手动关灯


  16. // ===================== LCD1602 驱动(直接写在文件中,避免外部头文件)=====================
  17. #define LCD_DATA P0
  18. sbit LCD_RS = P2^5;
  19. sbit LCD_RW = P2^6;
  20. sbit LCD_EN = P2^7;


  21. void LCD1602_WriteCmd(unsigned char cmd) {
  22.     LCD_RS = 0; LCD_RW = 0;
  23.     LCD_DATA = cmd;
  24.     LCD_EN = 1; _nop_(); _nop_(); LCD_EN = 0;
  25.     for(unsigned char i=0; i<5; i++);  // 短暂延时
  26. }
  27. void LCD1602_WriteData(unsigned char dat) {
  28.     LCD_RS = 1; LCD_RW = 0;
  29.     LCD_DATA = dat;
  30.     LCD_EN = 1; _nop_(); _nop_(); LCD_EN = 0;
  31.     for(unsigned char i=0; i<5; i++);
  32. }
  33. void LCD1602_Init(void) {
  34.     LCD1602_WriteCmd(0x38);
  35.     LCD1602_WriteCmd(0x0C);
  36.     LCD1602_WriteCmd(0x06);
  37.     LCD1602_WriteCmd(0x01);
  38.     for(unsigned int i=0; i<1000; i++); // 等待清屏完成
  39. }
  40. void LCD1602_ShowString(unsigned char x, unsigned char y, unsigned char *str) {
  41.     unsigned char addr = y ? (0xC0 + x) : (0x80 + x);
  42.     LCD1602_WriteCmd(addr);
  43.     while(*str) LCD1602_WriteData(*str++);
  44. }
  45. // 写一个字符到指定位置
  46. void LCD1602_WriteChar(unsigned char x, unsigned char y, unsigned char ch) {
  47.     unsigned char addr = y ? (0xC0 + x) : (0x80 + x);
  48.     LCD1602_WriteCmd(addr);
  49.     LCD1602_WriteData(ch);
  50. }


  51. // ===================== ADC0832 驱动(直接实现)=====================
  52. sbit ADC_CS  = P1^3;
  53. sbit ADC_CLK = P1^0;
  54. sbit ADC_DO  = P1^1;
  55. sbit ADC_DI  = P1^2;


  56. unsigned char ADC0832_Read(unsigned char channel) {
  57.     unsigned char i, dat = 0;
  58.     channel &= 0x01;
  59.     ADC_CS = 0;
  60.     // 起始位
  61.     ADC_CLK = 0; _nop_(); ADC_CLK = 1; _nop_();
  62.     ADC_DI = 1;
  63.     ADC_CLK = 0; _nop_(); ADC_CLK = 1; _nop_();
  64.     // 通道选择: 单端模式
  65.     ADC_DI = 1;   // 单端
  66.     ADC_CLK = 0; _nop_(); ADC_CLK = 1; _nop_();
  67.     ADC_DI = channel;
  68.     ADC_CLK = 0; _nop_(); ADC_CLK = 1; _nop_();
  69.     ADC_DI = 0;
  70.     // 读数据
  71.     for(i=0; i<8; i++) {
  72.         dat <<= 1;
  73.         ADC_CLK = 0; _nop_();
  74.         if(ADC_DO) dat |= 0x01;
  75.         ADC_CLK = 1; _nop_();
  76.     }
  77.     ADC_CS = 1;
  78.     return dat;
  79. }


  80. // ===================== 全局变量 ======================
  81. unsigned int time=0;
  82. int S=50;                 // 当前距离(cm),初始50cm,仿真时可手动改变
  83. unsigned int distance;    // 超声波时间中间量


  84. bit ir_ok = 0;            // 定时测量标志
  85. bit key1_flag=0, key2_flag=0, key3_flag=0, key4_flag=0, key5_flag=0, key6_flag=0;
  86. unsigned char sec1=0, sec2=0, ms=0;
  87. unsigned char light_set=50, S_set=30, state=0;  // 设置阈值
  88. bit s0;                   // 闪烁标志
  89. bit memory_flag=0;
  90. unsigned char light=0, ad_count=0;
  91. unsigned int ad_dat=0;
  92. unsigned char beam=0;     // 0关 1近光 2远光
  93. bit A_M=0;                // 0手动 1自动
  94. unsigned char count=0;


  95. // 仿真辅助:手动改变距离(按增加/减小键直接修改S)
  96. // 注意:只在非设置状态且自动模式下才允许手动修改当前距离(方便调试)
  97. bit sim_manual_distance = 1;   // 设为1表示允许手动改距离,设为0则使用真实超声波


  98. // 超声波超时退出用
  99. bit timeout_flag;


  100. // ===================== 函数声明 ======================
  101. void trigger(void);
  102. void measuring(void);
  103. void init_measuring(void);
  104. void interrupt_int(void);
  105. void display(void);
  106. void AD_dispose(void);
  107. void key_scan(void);
  108. void police(void);
  109. void delayt(unsigned int x);


  110. // ===================== 超声波相关函数 ======================
  111. void trigger(void) {
  112.     trig = 0;
  113.     _nop_();_nop_();_nop_();_nop_();_nop_();
  114.     _nop_();_nop_();_nop_();_nop_();_nop_();
  115.     _nop_();_nop_();_nop_();_nop_();_nop_();
  116.     _nop_();_nop_();_nop_();_nop_();_nop_();
  117.     trig = 1;
  118. }
  119. void init_measuring(void) {
  120.     trig = 1;
  121.     echo = 1;
  122.     count = 0;
  123. }
  124. void measuring(void) {
  125.     unsigned char l;
  126.     unsigned int h, y;
  127.     TR0 = 1;
  128.     // 等待echo变低,带超时
  129.     unsigned int to = 0;
  130.     while(echo == 1 && to < 60000) to++;
  131.     TR0 = 0;
  132.     if(to >= 60000) {  // 超时,无效测量
  133.         return;
  134.     }
  135.     l = TL0;
  136.     h = TH0;
  137.     y = (h << 8) + l;
  138.     y = y - 0xfc66;          // 补偿
  139.     distance = y + 1000 * count;
  140.     TL0 = 0x66;
  141.     TH0 = 0xfc;
  142.     delayt(30);
  143.     // 声速345m/s,计算距离cm
  144.     S = (unsigned long)3453 * distance / 200000;
  145.     if(S > 400) S = 400;
  146. }


  147. // ===================== 定时器初始化 ======================
  148. void interrupt_int(void) {
  149.     TMOD = 0x11;
  150.     TH0 = 0x00; TL0 = 0x00;
  151.     ET0 = 1;
  152.     TR0 = 0;
  153.     TH1 = 0x3c; TL1 = 0xb0;
  154.     ET1 = 1;
  155.     TR1 = 1;
  156.     EA = 1;
  157. }


  158. // ===================== LCD 显示 ======================
  159. void display(void) {
  160.     unsigned char str[17];
  161.     if(state == 0) {
  162.         LCD1602_ShowString(0, 0, "distance:      ");
  163.         // 显示距离数值(右对齐)
  164.         LCD1602_WriteChar(9, 0, '0' + S/100%10);
  165.         LCD1602_WriteChar(10,0, '0' + S/10%10);
  166.         LCD1602_WriteChar(11,0, '0' + S%10);
  167.         LCD1602_ShowString(12,0, "cm");
  168.         
  169.         LCD1602_ShowString(0, 1, "light:         ");
  170.         LCD1602_WriteChar(6, 1, '0' + light/100%10);
  171.         LCD1602_WriteChar(7, 1, '0' + light/10%10);
  172.         LCD1602_WriteChar(8, 1, '0' + light%10);
  173.         LCD1602_ShowString(9, 1, "%");
  174.     }
  175.     else if(state == 1) {
  176.         LCD1602_ShowString(0, 0, "dis_set:       ");
  177.         if(state==1 && s0) {
  178.             LCD1602_ShowString(8,0, "   ");
  179.         } else {
  180.             LCD1602_WriteChar(8,0, '0' + S_set/100%10);
  181.             LCD1602_WriteChar(9,0, '0' + S_set/10%10);
  182.             LCD1602_WriteChar(10,0,'0' + S_set%10);
  183.         }
  184.         LCD1602_ShowString(11,0, "cm");
  185.         LCD1602_ShowString(0,1, "lig_set:       ");
  186.         LCD1602_WriteChar(8,1, '0' + light_set/100%10);
  187.         LCD1602_WriteChar(9,1, '0' + light_set/10%10);
  188.         LCD1602_WriteChar(10,1,'0' + light_set%10);
  189.         LCD1602_ShowString(11,1, "%");
  190.     }
  191.     else if(state == 2) {
  192.         LCD1602_ShowString(0,0, "dis_set:       ");
  193.         LCD1602_WriteChar(8,0, '0' + S_set/100%10);
  194.         LCD1602_WriteChar(9,0, '0' + S_set/10%10);
  195.         LCD1602_WriteChar(10,0,'0' + S_set%10);
  196.         LCD1602_ShowString(11,0,"cm");
  197.         LCD1602_ShowString(0,1,"lig_set:       ");
  198.         if(state==2 && s0) {
  199.             LCD1602_ShowString(8,1, "   ");
  200.         } else {
  201.             LCD1602_WriteChar(8,1, '0' + light_set/100%10);
  202.             LCD1602_WriteChar(9,1, '0' + light_set/10%10);
  203.             LCD1602_WriteChar(10,1,'0' + light_set%10);
  204.         }
  205.         LCD1602_ShowString(11,1,"%");
  206.     }
  207. }


  208. // ===================== 光照采集 ======================
  209. void AD_dispose(void) {
  210.     if(ad_count < 10) {
  211.         ad_dat += ADC0832_Read(0);
  212.         ad_count++;
  213.     } else {
  214.         light = ad_dat / 10;
  215.         light = (unsigned long)light * 100 / 255;
  216.         ad_count = 0;
  217.         ad_dat = 0;
  218.     }
  219. }


  220. // ===================== 按键扫描 ======================
  221. void key_scan(void) {
  222.     // key1 设置
  223.     if(!key1) {
  224.         if(key1_flag) {
  225.             key1_flag = 0;
  226.             state = (state+1) % 3;
  227.         }
  228.     } else key1_flag = 1;
  229.    
  230.     // key2 增加
  231.     if(!key2) {
  232.         if(key2_flag) {
  233.             key2_flag = 0;
  234.             if(state == 1 && S_set < 400) S_set++;
  235.             else if(state == 2 && light_set < 100) light_set++;
  236.             // 在非设置状态且允许手动距离仿真时,按增加键增加当前距离S
  237.             else if(state == 0 && sim_manual_distance && S < 400) S++;
  238.         }
  239.         if(sec2 == 0) {
  240.             if(state == 1 && S_set < 400) S_set++;
  241.             else if(state == 2 && light_set < 100) light_set++;
  242.             else if(state == 0 && sim_manual_distance && S < 400) S++;
  243.         }
  244.         memory_flag = 1;
  245.     } else {
  246.         key2_flag = 1; sec2 = 2;
  247.     }
  248.    
  249.     // key3 减小
  250.     if(!key3) {
  251.         if(key3_flag) {
  252.             key3_flag = 0;
  253.             if(state == 1 && S_set > 0) S_set--;
  254.             else if(state == 2 && light_set > 0) light_set--;
  255.             else if(state == 0 && sim_manual_distance && S > 0) S--;
  256.         }
  257.         if(sec1 == 0) {
  258.             if(state == 1 && S_set > 0) S_set--;
  259.             else if(state == 2 && light_set > 0) light_set--;
  260.             else if(state == 0 && sim_manual_distance && S > 0) S--;
  261.         }
  262.         memory_flag = 1;
  263.     } else {
  264.         key3_flag = 1; sec1 = 2;
  265.     }
  266.    
  267.     // key4 手动/自动
  268.     if(!key4) {
  269.         if(key4_flag) {
  270.             key4_flag = 0;
  271.             A_M = !A_M;
  272.             if(A_M == 0) beam = 0;
  273.         }
  274.     } else key4_flag = 1;
  275.    
  276.     // key5 手动远光/近光
  277.     if(!key5) {
  278.         if(key5_flag) {
  279.             key5_flag = 0;
  280.             if(A_M == 0) {
  281.                 if(beam == 1) beam = 2;
  282.                 else beam = 1;
  283.             }
  284.         }
  285.     } else key5_flag = 1;
  286.    
  287.     // key6 手动关灯
  288.     if(!key6) {
  289.         if(key6_flag) {
  290.             key6_flag = 0;
  291.             if(A_M == 0) beam = 0;
  292.         }
  293.     } else key6_flag = 1;
  294. }


  295. // ===================== 自动模式逻辑 ======================
  296. void police(void) {
  297.     if(light < light_set) {        // 天黑
  298.         if(S > S_set) beam = 2;    // 远光
  299.         else beam = 1;             // 近光
  300.     } else beam = 0;
  301. }


  302. // ===================== 延时 ======================
  303. void delayt(unsigned int x) {
  304.     unsigned char j;
  305.     while(x--) for(j=0; j<125; j++);
  306. }


  307. // ===================== 主函数 ======================
  308. void main(void) {
  309.     interrupt_int();
  310.     LCD1602_Init();
  311.     // 简单显示欢迎界面
  312.     LCD1602_ShowString(0,0, "   Auto Light   ");
  313.     LCD1602_ShowString(0,1, "   V1.0 Ready   ");
  314.     delayt(500);
  315.    
  316.     init_measuring();
  317.    
  318.     while(1) {
  319.         display();
  320.         
  321.         if(ir_ok) {
  322.             ir_ok = 0;
  323.             if(!sim_manual_distance) {
  324.                 trigger();
  325.                 // 等待 echo 变高,带超时避免卡死
  326.                 unsigned int to = 0;
  327.                 while(echo == 0 && to < 60000) to++;
  328.                 if(to < 60000) {
  329.                     measuring();
  330.                 }
  331.                 init_measuring();
  332.             }
  333.             // 如果 sim_manual_distance==1,S 已经在按键中修改,不需要超声波
  334.         }
  335.         
  336.         if(memory_flag) {
  337.             memory_flag = 0;
  338.             // 模拟存储(实际项目中可写入EEPROM,这里空操作)
  339.         }
  340.         
  341.         if(A_M) {
  342.             led1 = 0; led2 = 1;
  343.             police();
  344.         } else {
  345.             led2 = 0; led1 = 1;
  346.         }
  347.         
  348.         AD_dispose();
  349.         
  350.         switch(beam) {
  351.             case 0: LED_1=1; LED_2=1; break;
  352.             case 1: LED_1=1; LED_2=0; break;
  353.             case 2: LED_1=0; LED_2=1; break;
  354.         }
  355.     }
  356. }


  357. // ===================== 定时器中断 ======================
  358. void timer0(void) interrupt 1 {
  359.     // 用于超声波测距,空
  360. }


  361. void timer1(void) interrupt 3 {
  362.     TH1 = 0x3c; TL1 = 0xb0;
  363.     ms++;
  364.     key_scan();
  365.     if(ms % 4 == 0) {
  366.         ir_ok = 1;
  367.         s0 = ~s0;
  368.     }
  369.     if(ms >= 20) {
  370.         ms = 0;
  371.         if(sec1 != 0) sec1--;
  372.         if(sec2 != 0) sec2--;
  373.     }
  374. }
复制代码

屏幕截图 2026-06-12 162024.png (129.57 KB, 下载次数: 0)

屏幕截图 2026-06-12 162024.png

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表