本帖最后由 电子哎嗨 于 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、靠近超声波时,蜂鸣器报警。
需要设计实物请私聊~
制作出来的实物图如下:
具体位置参考实物图
原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #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)
源程序.rar
(74.89 KB, 下载次数: 326)
|