主要內(nèi)容:傳統(tǒng)臺燈僅具備基礎(chǔ)照明功能,無法兼顧用眼健康、智能管控與多樣化使用需求本設(shè)計以單片機為核心主控單元,融合傳感器檢測、按鍵控制、顯示與聲光報警技術(shù)開發(fā)一款集人體檢測、距離監(jiān)測、環(huán)境光自適應(yīng)調(diào)光、多模式切換于一體的多功能智臺燈系統(tǒng)。系統(tǒng)可實現(xiàn)有人檢測、近距離護眼報警、多檔位亮度調(diào)節(jié)、本地按鍵控制功能,兼顧實用性、智能化與護眼特性,同時完成硬件電路搭建、軟件程序編寫、實調(diào)試與整體功能驗證,打造低成本、易實現(xiàn)、穩(wěn)定性強的嵌入式智能照明設(shè)備。。基本要求:1·搭載紅外傳感器識別人體存在,配合超聲波傳感器實時檢測人與臺燈距離,距離過時蜂鳴器觸發(fā)報警,實現(xiàn)護眼提醒。。2.設(shè)置多檔位工作模式,通過實體按鍵完成智能模式、按鍵模式兩種模式自由切換。3.智能模式下,結(jié)合光敏電阻采集環(huán)境光照強度,自動劃分低、中、高三檔亮度并自應(yīng)調(diào)光;紅外檢測無人時,臺燈自動熄滅。4,按鍵模式下,通過獨立按鍵手動切換燈光亮度檔位。5·配備顯示屏,實時展示系統(tǒng)工作模式、燈光亮度、檢測距離等運行狀態(tài)數(shù)據(jù)。
- #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; // 設(shè)置
- sbit key2 = P3^3; // 增加
- sbit key3 = P3^4; // 減小
- sbit key4 = P3^5; // 手動/自動
- sbit key5 = P3^6; // 手動遠光/近光切換
- sbit key6 = P3^7; // 手動關(guān)燈
- // ===================== LCD1602 驅(qū)動(直接寫在文件中,避免外部頭文件)=====================
- #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 驅(qū)動(直接實現(xiàn))=====================
- 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;
- // 讀數(shù)據(jù)
- 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; // 設(shè)置閾值
- bit s0; // 閃爍標志
- bit memory_flag=0;
- unsigned char light=0, ad_count=0;
- unsigned int ad_dat=0;
- unsigned char beam=0; // 0關(guān) 1近光 2遠光
- bit A_M=0; // 0手動 1自動
- unsigned char count=0;
- // 仿真輔助:手動改變距離(按增加/減小鍵直接修改S)
- // 注意:只在非設(shè)置狀態(tài)且自動模式下才允許手動修改當前距離(方便調(diào)試)
- bit sim_manual_distance = 1; // 設(shè)為1表示允許手動改距離,設(shè)為0則使用真實超聲波
- // 超聲波超時退出用
- bit timeout_flag;
- // ===================== 函數(shù)聲明 ======================
- 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);
- // ===================== 超聲波相關(guān)函數(shù) ======================
- 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: ");
- // 顯示距離數(shù)值(右對齊)
- 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 設(shè)置
- 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++;
- // 在非設(shè)置狀態(tài)且允許手動距離仿真時,按增加鍵增加當前距離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 手動關(guān)燈
- 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++);
- }
- // ===================== 主函數(shù) ======================
- 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 已經(jīng)在按鍵中修改,不需要超聲波
- }
-
- 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--;
- }
- }
復(fù)制代碼
|