本帖最后由 電子哎嗨 于 2021-1-8 23:52 編輯
原創作品,禁止轉載售賣,僅供學習參考!!!
功能說明:
1、上電之后LED燈點亮,代表當前燈是自動控制模式;
2、通過按鍵K5可以在自動和手動模式來回切換;
3、在手動模式下,按鍵K2,K3,K4分別對應一個燈光亮度;(k1按下時不可用)
4、在自動模式下,首先要檢測到有人,才進行亮度的自動控制,否則臺燈熄滅。可以擋住光敏電阻
的光線,或用手電筒來照射光敏電阻,模擬光照的變化,從而就可以看到臺燈的亮度會隨著環境中的
光照強度的改變而改變,效果是光照越弱,臺燈越亮。如果人體傳感器1分鐘檢測不到有人,臺燈就
會自動熄滅。(光敏電阻在USB燈后面);
5、無論是自動模式還是手動模式,都是把亮度分為10個等級的,并在LCD上顯示0-9;
6、設置日期時間:按下K1(設置)鍵,顯示年位置會有光標閃爍,表示此時可以調節年份,如需調節年份,
按K3(加),K4(減)即可對年份進行調節。然后按K2(移動)鍵,顯示月份位置會光標閃爍,同樣的方法可
以調節月,再按K2鍵分別可設置日,時,分,秒。
7、靠近超聲波時,蜂鳴器報警。
需要設計實物請私聊~
制作出來的實物圖如下:
48229EB52F5960EC7E533E9BE9CDD7A2.jpg (134.66 KB, 下載次數: 77)
下載附件
2021-1-8 23:11 上傳
具體位置參考實物圖
原理圖如下(proteus仿真工程文件可到本帖附件中下載)
ZM])D`6MO1$HI5(T381Y5OF.png (39.64 KB, 下載次數: 89)
下載附件
2020-12-21 13:33 上傳
單片機源程序如下:
- #include <reg52.h> //調用單片機頭文件
- #define uchar unsigned char //無符號字符型 宏定義 變量范圍0~255
- #define uint unsigned int //無符號整型 宏定義 變量范圍0~65535
- #include "eeprom52.h"
- #include "intrins.h"
- #include "ds1302.h"
- #include "lcd1602.h"
- #include "ultrasonic_wave.h"//超聲波頭函數
- bit flag_200ms ;
- bit flag_100ms ;
- bit flag_beep1_en;//定時模式開啟標志
- bit flag_beep2_en;
- bit flag_beep3_en;
- sbit k1=P1^4; //時間設置切換
- sbit k2=P1^5; //光標移動
- sbit k3=P1^6; //加
- sbit k4=P1^7; //減
- sbit k5=P2^7; //手動/自動
- sbit ADC_CS = P3^5; //ADC0832引腳定義
- sbit ADC_CLK = P3^6;
- sbit ADC_DAT = P3^7;
-
- sbit LED = P2^6; //自動模式指示燈
- sbit dq = P2^1; //18b20 IO口的定義
-
- sbit Module = P2^2; // 人體紅外感應引腳定義
- sbit Beep = P2^0; // 蜂鳴器引腳定義
-
- sbit Lamp = P1^3; // 照明燈定義
- uchar gCount=0; // 全局計數變量
- uchar gIndex; // 亮度變量,0是最暗,9是最亮,一共10檔
- uint gTime=0; // 計時變量,用于計時多久沒檢測到有人
- uint temperature ; //溫度變量
- uchar menu_1; //時間/定時模式切換
- uchar menu_2; //調整時間
- uchar ret; //AD采集結果
- uchar key_time,flag_value; //用做連加的中間變量
- bit key_500ms ;
- /******************把數據保存到單片機內部eeprom中******************/
- void write_eeprom()
- {
- SectorErase(0x2000);
- byte_write(0x2000, fen1);
- byte_write(0x2001, shi1);
- byte_write(0x2002, open1);
- byte_write(0x2058, a_a);
- }
- /******************把數據從單片機內部eeprom中讀出來*****************/
- void read_eeprom()
- {
- fen1 = byte_read(0x2000);
- shi1 = byte_read(0x2001);
- open1 = byte_read(0x2002);
- a_a = byte_read(0x2058);
- }
- /**************開機自檢eeprom初始化*****************/
- void init_eeprom()
- {
- read_eeprom(); //先讀
- if(a_a != 1) //新的單片機初始單片機內問eeprom
- {
- fen1 = 3;
- shi1 = 8;
- open1 = 1;
- a_a = 1;
- write_eeprom(); //保存數據
- }
- }
- /*********************************************************/
- // ADC0832的時鐘脈沖
- /*********************************************************/
- void WavePlus()
- {
- _nop_();
- ADC_CLK = 1;
- _nop_();
- ADC_CLK = 0;
- }
- /*********************************************************/
- // 獲取指定通道的A/D轉換結果
- /*********************************************************/
- uchar Get_ADC0832()
- {
- uchar i;
- uchar dat1=0;
- uchar dat2=0;
-
- ADC_CLK = 0; // 電平初始化
- ADC_DAT = 1;
- _nop_();
- ADC_CS = 0;
- WavePlus(); // 起始信號
- ADC_DAT = 1;
- WavePlus(); // 通道選擇的第一位
- ADC_DAT = 0;
- WavePlus(); // 通道選擇的第二位
- ADC_DAT = 1;
-
- for(i=0;i<8;i++) // 第一次讀取
- {
- dat1<<=1;
- WavePlus();
- if(ADC_DAT)
- dat1=dat1|0x01;
- else
- dat1=dat1|0x00;
- }
-
- for(i=0;i<8;i++) // 第二次讀取
- {
- dat2>>= 1;
- if(ADC_DAT)
- dat2=dat2|0x80;
- else
- dat2=dat2|0x00;
- WavePlus();
- }
-
- _nop_(); // 結束此次傳輸
- ADC_DAT = 1;
- ADC_CLK = 1;
- ADC_CS = 1;
- if(dat1==dat2) // 返回采集結果
- return dat1;
- else
- return 0;
- }
- /*********************************************************/
- // 自動控制
- /*********************************************************/
- void AutoControl(uchar num)
- {
- if(num<30) // 最亮
- gIndex=9;
- else if((num>35)&&(num<45))
- gIndex=8;
- else if((num>50)&&(num<60))
- gIndex=7;
- else if((num>65)&&(num<75))
- gIndex=6;
- else if((num>80)&&(num<90))
- gIndex=5;
- else if((num>95)&&(num<105))
- gIndex=4;
- else if((num>110)&&(num<120))
- gIndex=3;
- else if((num>125)&&(num<135))
- gIndex=2;
- else if((num>140)&&(num<150))
- gIndex=1;
- else if(num>155) // 最暗
- gIndex=0;
- }
- /***********************18b20初始化函數*****************************/
- void init_18b20()
- {
- bit q;
- dq = 1; //把總線拿高
- delay_uint(1); //15us
- dq = 0; //給復位脈沖
- delay_uint(80); //750us
- dq = 1; //把總線拿高 等待
- delay_uint(10); //110us
- q = dq; //讀取18b20初始化信號
- delay_uint(20); //200us
- dq = 1; //把總線拿高 釋放總線
- }
- /*************寫18b20內的數據***************/
- void write_18b20(uchar dat)
- {
- uchar i;
- for(i=0;i<8;i++)
- { //寫數據是低位開始
- dq = 0; //把總線拿低寫時間隙開始
- dq = dat & 0x01; //向18b20總線寫數據了
- delay_uint(5); // 60us
- dq = 1; //釋放總線
- dat >>= 1;
- }
- }
- /*************讀取18b20內的數據***************/
- uchar read_18b20()
- {
- uchar i,value;
- for(i=0;i<8;i++)
- {
- dq = 0; //把總線拿低讀時間隙開始
- value >>= 1; //讀數據是低位開始
- dq = 1; //釋放總線
- if(dq == 1) //開始讀寫數據
- value |= 0x80;
- delay_uint(5); //60us 讀一個時間隙最少要保持60us的時間
- }
- return value; //返回數據
- }
- /*************讀取溫度的值 讀出來的是小數***************/
- uint read_temp()
- {
- uint value;
- uchar low; //在讀取溫度的時候如果中斷的太頻繁了,就應該把中斷給關了,否則會影響到18b20的時序
- init_18b20(); //初始化18b20
- write_18b20(0xcc); //跳過64位ROM
- write_18b20(0x44); //啟動一次溫度轉換命令
- delay_uint(50); //500us
- init_18b20(); //初始化18b20
-
- write_18b20(0xcc); //跳過64位ROM
- write_18b20(0xbe); //發出讀取暫存器命令
-
- EA = 0;
- low = read_18b20(); //讀溫度低字節
- value = read_18b20(); //讀溫度高字節
- EA = 1;
- value <<= 8; //把溫度的高位左移8位
- value |= low; //把讀出的溫度低位放到value的低八位中
- value *= 0.625; //轉換到溫度值 小數
- return value; //返回讀出的溫度 帶小數
- }
- /******************1ms 延時函數*******************/
- void delay_1ms(uint q)
- {
- uint i,j;
- for(i=0;i<q;i++)
- for(j=0;j<120;j++);
- }
- ///******************寫星期函數*******************/
- //void write_week(uchar hang,uchar add,uchar week)//寫星期函數
- //{
- // if(hang==1)
- // write_com(0x80+add);
- // else
- // write_com(0x80+0x40+add);
- // switch(week)
- // {
- // case 1:write_data('M');//星期數為1時,顯示
- // write_data('O');
- // write_data('N');
- // break;
- //
- // case 2:write_data('T');//星期數據為2時顯示
- // write_data('U');
- // write_data('E');
- // break;
- //
- // case 3:write_data('W');//星期數據為3時顯示
- // write_data('E');
- // write_data('D');
- // break;
- //
- // case 4:write_data('T');//星期數據為4是顯示
- // write_data('H');
- // write_data('U');
- // break;
- //
- // case 5:write_data('F');//星期數據為5時顯示
- // write_data('R');
- // write_data('I');
- // break;
- //
- // case 6:write_data('S');//星期數據為6時顯示
- // write_data('T');
- // write_data('A');
- // break;
- //
- // case 7:write_data('S');//星期數據為7時顯示
- // write_data('U');
- // write_data('N');
- // break;
- // }
- //}
- /******************寫亮度函數*******************/
- void write_light(uchar hang,uchar add,uchar light)//寫星期函數
- {
- if(hang==1)
- write_com(0x80+add);
- else
- write_com(0x80+0x40+add);
-
- write_data(0x30+light);//顯示亮度等級
-
- }
- /*************時鐘顯示***************/
- void init_1602_ds1302()
- {
- write_sfm2_ds1302(1,1,shi); //顯示時
- write_sfm2_ds1302(1,4,fen); //顯示分
- write_sfm2_ds1302(1,7,miao); //顯示秒
- write_light(2,13,gIndex); //顯示亮度
- //write_sfm1(1,14,week); //顯示星期
- if(temperature<900)
- {
- write_sfm3_18B20(1,11,temperature); //顯示溫度
- }
- write_sfm2_ds1302(2,2,nian); //顯示年
- write_sfm2_ds1302(2,5,yue); //顯示月
- write_sfm2_ds1302(2,8,ri); //顯示日
- }
- /************定時器0初始化程序*********/
- void init_time0()
- {
- EA = 1; //開總中斷
- TMOD = TMOD|0x01; //定時器0、工作方式1
- TH0 = 252; //給定時器0的TH0裝初值
- TL0 = 24; //給定時器0的TL0裝初值
- ET0 = 1; //開定時器0中斷
- TR0 = 1; //允許定時器0定時
- }
- /********************獨立按鍵程序*****************/
- uchar key_can; //按鍵值
- void key() //獨立按鍵
- {
- static uchar key_new;
- key_can = 20; //按鍵值還原
- if(k1==0) //檢測按鍵K1是否按下
- {
- delay_1ms(10); //消除抖動 一般大約10ms
- if(k1==0) //再次判斷按鍵是否按下
- {
- key_new = 0;
- key_can = 1;
- }
- while(!k1); //檢測按鍵是否松開
- }
- else
- key_new = 1;
-
- if(k2==0) //檢測按鍵K1是否按下
- {
- delay_1ms(10); //消除抖動 一般大約10ms
- if(k2==0) //再次判斷按鍵是否按下
- {
- key_new = 0;
- key_can = 2;
- }
- while(!k2); //檢測按鍵是否松開
- }
- else
- key_new = 1;
-
- if(k3==0) //檢測按鍵K1是否按下
- {
- delay_1ms(10); //消除抖動 一般大約10ms
- if(k3==0) //再次判斷按鍵是否按下
- {
- key_new = 0;
- key_can = 3;
- }
- while(!k3); //檢測按鍵是否松開
- }
- else
- key_new = 1;
-
- if(k4==0) //檢測按鍵K1是否按下
- {
- delay_1ms(10); //消除抖動 一般大約10ms
- if(k4==0) //再次判斷按鍵是否按下
- {
- key_new = 0;
- key_can = 4;
- }
- while(!k4); //檢測按鍵是否松開
- }
- else
- key_new = 1;
-
- if(k5==0) //檢測按鍵K5是否按下
- {
- delay_1ms(10); //消除抖動 一般大約10ms
- if(k5==0) //再次判斷按鍵是否按下
- {
- LED=~LED; // 切換LED燈狀態
- }
- while(!k5); //檢測按鍵是否松開
- }
-
- }
- /**********************設置函數************************/
- void key_with()
- {
- if(key_can == 1)
- {
- menu_1++;
- if(menu_1 == 1)
- {
- menu_2 = 1;
- write_string(1,0," : : W: ");
- write_string(2,0," 20 - - ");
- }
-
- if(menu_1 > 1)
- {
- menu_1 = 0;
- write_guanbiao(1,2,0);
- init_1602_dis_csf(); //初始化液晶顯示
- }
- }
- if(key_can == 2)
- {
- flag_200ms = 1;
- if(menu_1 == 1)
- {
- menu_2 ++;
- if(menu_2 > 7)
- menu_2 = 1;
- }
- }
- if(menu_1 == 1)
- {
- if(menu_2 == 1)
- {
- if(key_can == 3)
- {
- shi+=0x01;
- if((shi & 0x0f) >= 0x0a)
- shi = (shi & 0xf0) + 0x10; ///***shi & 0xf0低四位清零,(shi & 0xf0) + 0x10向高位進1(高四位加1)***/// if(shi >= 0x24)
- shi = 0;
- }
- if(key_can == 4)
- {
- if(shi == 0x00)
- shi = 0x24;
- if((shi & 0x0f) == 0x00)
- shi = (shi | 0x0a) - 0x10; ///***如果個位為0,高四位減1***///
- shi -- ;
- }
- }
- if(menu_2 == 2)
- {
- if(key_can == 3)
- {
- fen+=0x01;
- if((fen & 0x0f) >= 0x0a)
- fen = (fen & 0xf0) + 0x10;
- if(fen >= 0x60)
- fen = 0;
- }
- if(key_can == 4)
- {
- if(fen == 0x00)
- fen = 0x5a;
- if((fen & 0x0f) == 0x00)
- fen = (fen | 0x0a) - 0x10;
- fen -- ;
- }
- }
- if(menu_2 == 3)
- {
- if(key_can == 3)
- {
- miao+=0x01;
- if((miao & 0x0f) >= 0x0a)
- miao = (miao & 0xf0) + 0x10;
- if(miao >= 0x60)
- miao = 0;
- }
- if(key_can == 4)
- {
- if(miao == 0x00)
- miao = 0x5a;
- if((miao & 0x0f) == 0x00)
- miao = (miao | 0x0a) - 0x10;
- miao -- ;
- }
- }
- if(menu_2 == 4)
- {
- if(key_can == 3)
- {
- week+=0x01;
- if((week & 0x0f) >= 0x0a)
- week = (week & 0xf0) + 0x10;
- if(week >= 0x08)
- week = 1;
- }
- if(key_can == 4)
- {
- if(week == 0x01)
- week = 0x08;
- if((week & 0x0f) == 0x00)
- week = (week | 0x0a) - 0x10;
- week -- ;
- }
- }
- if(menu_2 == 5)
- {
- if(key_can == 3)
- {
- nian+=0x01;
- if((nian & 0x0f) >= 0x0a)
- nian = (nian & 0xf0) + 0x10;
- if(nian >= 0x9a)
- nian = 1;
- }
- if(key_can == 4)
- {
- if(nian == 0x01)
- nian = 0x9a;
- if((nian & 0x0f) == 0x00)
- nian = (nian | 0x0a) - 0x10;
- nian -- ;
- }
- }
- if(menu_2 == 6)
- {
- if(key_can == 3)
- {
- yue+=0x01;
- if((yue & 0x0f) >= 0x0a)
- yue = (yue & 0xf0) + 0x10;
- if(yue >= 0x13)
- yue = 1;
- }
- if(key_can == 4)
- {
- if(yue == 0x01)
- yue = 0x13;
- if((yue & 0x0f) == 0x00)
- yue = (yue | 0x0a) - 0x10;
- yue -- ;
- }
- }
- if(menu_2 == 7)
- {
- if(key_can == 3)
- {
- ri+=0x01;
- if((ri & 0x0f) >= 0x0a)
- ri = (ri & 0xf0) + 0x10;
- if(ri >= 0x32)
- ri = 0;
- }
- if(key_can == 4)
- {
- if(ri == 0x01)
- ri = 0x32;
- if((ri & 0x0f) == 0x00)
- ri = (ri | 0x0a) - 0x10;
- ri -- ;
- }
- }
- write_sfm2_ds1302(1,2,shi);
- write_sfm2_ds1302(1,5,fen);
- write_sfm2_ds1302(1,8,miao);
- write_sfm1(1,14,week);
- write_sfm2_ds1302(2,3,nian);
- write_sfm2_ds1302(2,6,yue);
- write_sfm2_ds1302(2,9,ri);
- ///***write_sfm3_18B20(2,12,temperature);
- switch(menu_2) // 光標顯示
- {
- case 1: write_guanbiao(1,2,1); break;
- case 2: write_guanbiao(1,5,1); break;
- case 3: write_guanbiao(1,8,1); break;
- case 4: write_guanbiao(1,14,1); break;
- case 5: write_guanbiao(2,3,1); break;
- case 6: write_guanbiao(2,6,1); break;
- case 7: write_guanbiao(2,9,1); break;
- }
- write_time(); //把時間寫進去
- }
-
- }
- /*****************主函數********************/
- void main()
- {
- P0 = P1 = P2 = P3 = 0xff; //單片機IO口初始化為1
-
- LED=0; // 指示燈點亮(自動模式指示燈)
- ret=Get_ADC0832(); // 獲取AD采集結果(環境光照強度)
- AutoControl(ret); // 上電先進行一次自動亮度控制
- AutoControl(ret+7);
- delay_1ms(150);
- Init_ultrasonic_wave(); //超聲波定時器初始化
- init_time0(); //初始化定時器
- init_ds1302(); //ds1302初始化
- init_1602(); //lcd1602初始化
- init_1602_dis_csf(); //lcd1602初始化顯示
- init_eeprom(); //開始初始化保存的數據
- temperature = read_temp(); //先讀出溫度的值
- delay_1ms(650);
- temperature = read_temp(); //先讀出溫度的值
- while(1)
- {
- key(); //按鍵程序
- if(key_can < 10)
- {
- key_with();
- if(menu_1 == 0)
- {
- if(LED==1)
- {
- if(key_can == 2) //左移鍵
- {
- gIndex=1;
- }
-
- if(key_can == 3) //加鍵
- {
- gIndex=5;
- }
-
- if(key_can == 4) //減鍵
- {
- gIndex=9;
- }
- }
- }
- }
-
- /* 亮度控制 */
- if(LED==0) // 如果LED是亮的
- {
- if(gTime<60000)
- {
- ret=Get_ADC0832(); // 獲取AD采集結果(環境光照強度)
- AutoControl(ret); // 進行自動控制
- }
- }
- delay_1ms(100);
- /*檢測是否有人*/
- if(Module==1)
- {
- gTime=0; // 檢測到有人,則把60秒計時清零
- }
- if(gTime>60000) // 如果gTime的值超過了60000
- {
- gTime=60000; // 則把gTime的值重新賦值為60000,避免過大溢出
- gIndex=0; // 如果1分鐘檢測不到有人,則把臺燈熄滅
- }
- if(flag_200ms == 1)
- {
- flag_200ms = 0;
- if(menu_1 == 0)
- {
- read_time(); //讀時間
- temperature = read_temp(); //先讀出溫度的值
- init_1602_ds1302(); //顯示時鐘
- }
- }
- delay_1ms(1);
- StartModule();//啟動超聲波
- while(!RX) //當RX為零時等待
- TR1=1; //開啟計數
- while(RX); //當RX為1計數并等待
- TR1=0; //關閉計數
- delay_1ms(20);
-
- Conut(); //計算距離
- //距離小于30
- if(L_ < 30)
- {
- Beep=~Beep;
- delay_1ms(1);
- Beep=~Beep;
- delay_1ms(1);
- delay_1ms(100);
- }
- else
- Beep=1;
- }
- }
- /**************定時器0中斷程序*****************/
- void time0() interrupt 1
- {
- static uchar value;
- TH0 = 252;
- TL0 = 24; //1ms
- value ++;
- if((value % 100) == 0) //100ms
- {
- flag_100ms = 1;
- }
- if(value >= 200) //200ms
- {
- value = 0;
- flag_200ms = 1;
- }
- gTime++; // 每1毫秒,gTime變量加1
- gCount++; // 每1毫秒,gCount變量加1
- if(gCount==10) // 如果gCount加到10了
- {
- gCount=0; // 則將gCount清零,進入新一輪的計數
- if(gIndex!=0) // 如果說臺燈不是最暗的(熄滅)
- {
- Lamp=0; // 則把臺燈點亮
- }
- }
- if(gCount==gIndex) // 如果gCount計數到和gIndex一樣了
- {
- if(gIndex!=9) // 如果說臺燈不是最亮的
- {
- Lamp=1; // 則把臺燈熄滅
- }
- }
- }
- void time1() interrupt 3 //T1中斷用來計數器溢出,超過測距范圍
- {
- TH1=0;
- TL1=0;
- }
復制代碼 資料群(注明來自51黑)861514012
必備的單片機開發軟件和教程視頻我已上傳到群里,有需要的可以自行進去下載
全部資料51hei下載地址:
仿真.rar
(78.23 KB, 下載次數: 317)
2020-12-21 13:36 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
源程序.rar
(74.89 KB, 下載次數: 326)
2020-12-21 13:37 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|