/*时钟显示1602
独立键盘(P1口)设置时钟(K1设置时分秒星期年月日,K2加一,K3减一) */
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define AddWr 0x90 //写数据地址
#define AddRd 0x91 //读数据地址
sbit Sda=P2^7; //定义总线连接端口
sbit Scl=P2^6;
//DS1302控制端口定义
sbit CE=P1^4;
sbit SDA=P1^5;
sbit SCLK=P1^6;
//LCD1602控制端口定义
sbit LCD_RS = P1^0;
sbit LCD_RW = P1^1;
sbit LCD_EN = P1^2;
//独立按键定义
sbit K1=P3^7; //功能键
sbit K2=P3^6; //增大键
sbit K3=P3^5; //减小键
sbit K5=P3^4; //确定
sbit K6=P3^3; //强制关闭
sbit K7=P3^2; //恢复
sbit K4=P2^5; //红外
sbit jd=P2^3;
uchar K6FLAG=0,K7FLAG=0,gflag=0;
bit k=0;
//bit ADFlag; //定义AD采样标志位
uchar table[]={"0123456789a"};
//屏幕初始化图标
uchar table1[]={" 2017- - "};
uchar table2[]={" : : "};
//星期LOGO
uchar code table3[]={"MON TUE WED THU FRI SAT SUN"};
uchar table4[]={"DSL:00 DSH:08"};
//uchar TempData[]={"000"};
//uchar table5[]={"shezhi: "};
//初始化 年 月 日 星期 时 分 秒
char year_h,year_l,month_h,month_l,day_h,day_l,hour_h,hour_l,min_h,min_l,sec_h,sec_l,date=3;
uchar year=0x17,month=1,day=1,hour=0,min=0,sec=0;
int hourn=0;min1=0;sec1=0; //设置闹钟
uchar dsh=8,dsl=0;
uchar K1num=0;
uchar flag=0;
//声明延时函数毫秒级
void delay1ms(uint ms);
/*******************************************************************************************
* 以下为DS1302驱动程序 *
*******************************************************************************************/
/***********************************/
/* 延时程序 */
/***********************************/
void delayus()
{
;
;
;
}
uchar DS1302_Read(uchar address)
{
uchar i,temp=0x00;
CE=0;
SDA=1;
SCLK=0;
CE=1;
for (i=0;i<8;i++) //循环8次 写入地址数据
{
SCLK=0;
SDA=address&0x01; //每次传输低字节
address>>=1; //右移一位
SCLK=1;
}
delay1ms(1);
if(SDA)
temp|=0x80; //每次传输低字节
SCLK=0;
temp>>=1;
for (i=0;i<7;i++) //循环8次 读取数据
{
SCLK=0;
if(SDA)
temp|=0x80; //每次传输低字节
SCLK=1;
temp>>=1; //右移一位
}
SCLK=1;
CE=0;
SDA=0;
return temp; //返回
}
void DS1302_Write(uchar address,uchar dat)
{
uchar i;
CE=0;
SCLK=0;
CE=1;
for (i=0;i<8;i++) //循环8次 写入地址数据
{
SCLK=0;
_nop_();
SDA=address&0x01; //每次传输低字节
address>>=1; //右移一位
SCLK=1;
_nop_();
}
for (i=0;i<8;i++) //循环8次 写入数据
{
SCLK=0;
_nop_();
SDA=dat&0x01; //每次传输低字节
dat>>=1; //右移一位 DSCLK=1
SCLK=1;
_nop_();
}
CE=0;
_nop_();
}
void DS1302_initW() //初始化时间设置(写)
{
DS1302_Write(0x8e,0x00); //写保护关
DS1302_Write(0x80,sec); //秒
DS1302_Write(0x82,min); //分
DS1302_Write(0x84,hour); //时
DS1302_Write(0x86,day); //日
DS1302_Write(0x88,month); //月
DS1302_Write(0x8a,date); //周
DS1302_Write(0x8c,year); //年
DS1302_Write(0x8e,0x80); //写保护开
}
void DS1302_initR()
{
sec=DS1302_Read(0x81); //读秒数据
min=DS1302_Read(0x83); //读分钟数据
hour=DS1302_Read(0x85); //读小时数据
date=DS1302_Read(0x8b); //读星期数据
day=DS1302_Read(0x87); //读日数据
month=DS1302_Read(0x89); //读月数据
year=DS1302_Read(0x8d); //读年数据
}
/*******************************************************************************************
* 以上为DS1302驱动程序 *
*******************************************************************************************/
/*******************************************************************************************
* 以下为LCD1602驱动显示程序 *
*******************************************************************************************/
void delay1ms(uint ms) //延时程序1ms
{
uint i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}
void LCD_writecom(uchar com) //写命令
{
LCD_RS=0;
LCD_RW=0;
LCD_EN=1;
delay1ms(2);
P0=com;
LCD_EN=0;
delay1ms(2);
}
void LCD_writedat(uchar dat) //写数据
{
LCD_RS=1;
LCD_RW=0;
LCD_EN=1;
delay1ms(2);
P0=dat;
LCD_EN=0;
delay1ms(2);
}
void init()
{
LCD_EN=0;
LCD_writecom(0x38); //工作方式设置(8位数据接口;两行显示;5*7点阵字符)
LCD_writecom(0x06); //输入方式设置(数据读写操作后AC自动加1;数据读写操作后画面不移动)
LCD_writecom(0x0C); //显示开关控制(开显示,关光标,关闪烁)
LCD_writecom(0x01); //清屏
}
void display1() //初始化屏幕 格式: 20 - -
{ // : :
uchar num;
init();
LCD_writecom(0x80);
for(num=0;num<12;num++)
{
LCD_writedat(table1[num]);
delay1ms(2);
}
LCD_writecom(0x80+0x40);
for(num=0;num<15;num++)
{
LCD_writedat(table2[num]);
delay1ms(2);
}
}
void display2(uchar date)
{
uchar num;
LCD_writecom(0x80+12);
if(date==1) //星期一
{
for(num=0;num<3;num++)
{
LCD_writedat(table3[num]);
delay1ms(2);
}
}
if(date==2) //星期二
{
for(num=4;num<7;num++)
{
LCD_writedat(table3[num]);
delay1ms(2);
}
}
if(date==3) //星期三
{
for(num=8;num<11;num++)
{
LCD_writedat(table3[num]);
delay1ms(2);
}
}
if(date==4) //星期四
{
for(num=12;num<15;num++)
{
LCD_writedat(table3[num]);
delay1ms(2);
}
} //星期五
if(date==5)
{
for(num=16;num<19;num++)
{
LCD_writedat(table3[num]);
delay1ms(2);
}
}
if(date==6) //星期六
{
for(num=20;num<23;num++)
{
LCD_writedat(table3[num]);
delay1ms(2);
}
} //星期日
if(date==7)
{
for(num=24;num<27;num++)
{
LCD_writedat(table3[num]);
delay1ms(2);
}
}
}
void write_sfm(uchar add,char date) //时分秒写入显示
{
char shi,ge;
shi=date/16;
ge=date%16;
LCD_writecom(0x80+0x40+add);
LCD_writedat(0x30+shi);
LCD_writedat(0x30+ge);
}
void write_nyrx(uchar add,char date) //年月日星期写入显示
{
char shi,ge;
shi=date/16;
ge=date%16;
LCD_writecom(0x80+add);
LCD_writedat(0x30+shi);
LCD_writedat(0x30+ge);
}
/*******************************************************************************************
* 以上为LCD1602驱动显示程序 *
*******************************************************************************************/
void display3() //时间显示程序
{
if(k==0) //时间显示停止控制标志
{
DS1302_initR();
write_sfm(7,sec);
write_sfm(4,min);
write_sfm(1,hour);
write_nyrx(3,year);
write_nyrx(6,month);
write_nyrx(9,day);
display2(date);
}
}
void keyscan() //键盘扫描
{
char K5FLAG=0;
display3();
if(K5==0)
{
delay1ms(5);
if(K5==0)
{
K5FLAG=1;
}
}
if(K1num>0&& K5FLAG==1)
{
LCD_writecom(0x0c);
gflag=0;
K1num=0;
K5FLAG=0; //K1按键计数清零
k=0; //时间继续走
write_sfm(7,sec);
write_sfm(4,min);
write_sfm(1,hour);
write_nyrx(3,year);
write_nyrx(6,month);
write_nyrx(9,day);
display2(date);
DS1302_initW(); //将设置的时间日期等写入DS1302中
DS1302_Write(0x8e,0x80); //写保护开
}
if(K1==0)
{
delay1ms(5);
if(K1==0)
{
K1num++;
gflag++;
while(!K1); //K1按键计数
k=1;
DS1302_Write(0x8e,0x00); //写保护关
switch(K1num)
{
case 1:LCD_writecom(0x80+0x40+8);
LCD_writecom(0x0f);
k=1; //时间暂停显示
break;
case 2:LCD_writecom(0x80+0x40+5);
break;
case 3:LCD_writecom(0x80+0x40+2);
break;
case 4:LCD_writecom(0x80+14);
break;
case 5:LCD_writecom(0x80+10);
break;
case 6:LCD_writecom(0x80+7);
break;
case 7:LCD_writecom(0x80+4);
break;
case 8:LCD_writecom(0x01);
break;
case 10:LCD_writecom(0x0c);
K1num=0; //K1按键计数清零
k=0; //时间继续走
write_sfm(7,sec);
write_sfm(4,min);
write_sfm(1,hour);
write_nyrx(3,year);
write_nyrx(6,month);
write_nyrx(9,day);
display2(date);
DS1302_initW(); //将设置的时间日期等写入DS1302中
DS1302_Write(0x8e,0x80); //写保护开
break;
}
}
}
if(K1num!=0) //如果K1按下进行以下操作
{
if(K2==0) //K1按下进行K2按键检测
{
delay1ms(5);
if(K2==0)
{
while(!K2);
switch(K1num)
{ //秒++
case 1: DS1302_initW();
sec_h=sec/16;
sec_l=sec%16;
sec_l++;
if(sec_l==10)
{
sec_l=0;
sec_h++;
}
if(sec_h==6)
sec_h=0;
sec=sec_h*16+sec_l;
write_sfm(7,sec);
LCD_writecom(0x80+0x40+8);
break;
case 2: min_h=min/16; //分++
min_l=min%16;
min_l++;
if(min_l==10)
{
min_l=0;
min_h++;
}
if(min_h==6)
min_h=0;
min=min_h*16+min_l;
write_sfm(4,min);
LCD_writecom(0x80+0x40+5);
break;
case 3: hour_h=hour/16;
hour_l=hour%16; //时++
if(hour_h==2)
{
if(hour_l>3)
{
hour_h=0;
hour_l=0;
}
}
hour_l++;
if(hour_l==10)
{
hour_l=0;
hour_h++;
}
if((hour_h==2)&&(hour_l>3))
{
hour_h=0;
hour_l=0;
}
hour=hour_h*16+hour_l;
write_sfm(1,hour);
LCD_writecom(0x80+0x40+2);
break;
case 4: date++;
if(date==8)
date=1;
display2(date);
LCD_writecom(0x80+14);
break;
case 5: day_h=day/16;
day_l=day%16;
if(day_h==3)
{
if(day_l>1)
{
day_h=0;
day_l=1;
}
}
day_l++;
if(day_l==10)
{
day_l=0;
day_h++;
}
if((day_h==3)&&(day_l>1))
{
day_h=0;
day_l=1;
}
day=day_h*16+day_l;
write_nyrx(9,day);
LCD_writecom(0x80+10);
break;
case 6: month_h=month/16; //月++
month_l=month%16;
if(month_h==1)
{
if(month_l>2)
{
month_h=0;
month_l=1;
}
}
month_l++;
if(month_l==10)
{
month_l=0;
month_h++;
}
if((month_h==1)&&(month_l>2))
{
month_h=0;
month_l=1;
}
month=month_h*16+month_l;
write_nyrx(6,month);
LCD_writecom(0x80+7);
break;
case 7: year_h=year/16;
year_l=year%16;
year_l++;
if(year_l==10)
{
year_l=0;
year_h++;
}
if(year_h==6)
year_h=0;
year=year_h*16+year_l;
write_nyrx(3,year);
LCD_writecom(0x80+4);
break;
case 10: LCD_writecom(0x0c);
K1num=0;
k=0;
display2(date);
display3();
DS1302_Write(0x8e,0x80); //写保护开
break;
}
}
}
if(K3==0) //K1按下进行K3按键检测
{
delay1ms(5);
if(K3==0)
{
while(!K3);
switch(K1num)
{
case 1: sec_h=sec/16;
sec_l=sec%16;
sec_l--;
if(sec_l==-1)
{
sec_l=9;
sec_h--;
}
if(sec_h==-1)
sec_h=5;
sec=sec_h*16+sec_l;
write_sfm(7,sec);
LCD_writecom(0x80+0x40+8);
break;
case 2: min_h=min/16;
min_l=min%16;
min_l--;
if(min_l==-1)
{
min_l=9;
min_h--;
}
if(min_h==-1)
min_h=5;
min=min_h*16+min_l;
write_sfm(4,min);
LCD_writecom(0x80+0x40+5);
break;
case 3: hour_h=hour/16;
hour_l=hour%16;
hour_l--;
if(hour_l==-1)
{
hour_l=9;
hour_h--;
}
if(hour_h==-1)
{
hour_h=2;
hour_l=3;
}
hour=hour_h*16+hour_l;
write_sfm(1,hour);
LCD_writecom(0x80+0x40+2);
break;
case 4: date--;
if(date==0)
date=7;
display2(date);
LCD_writecom(0x80+14);
break;
case 5: day_l--;
if(day_l==-1)
{
day_l=9;
day_h--;
}
if(day_h==-1)
{
day_h=3;
day_l=1;
}
if((day_h==0)&&(day_l==0))
{
day_h=3;
day_l=1;
}
day=day_h*16+day_l;
write_nyrx(9,day);
LCD_writecom(0x80+10);
break;
case 6: month_l--;
if(month_l==-1)
{
month_l=9;
month_h--;
}
if(month_h==-1)
{
month_h=1;
month_l=2;
}
if((month_h==0)&&(month_l==0))
{
month_h=1;
month_l=2;
}
month=month_h*16+month_l;
write_nyrx(6,month);
LCD_writecom(0x80+7);
break;
case 7: year_h=year/16;
year_l=year%16;
year_l--;
if(year_l==-1)
{
year_l=9;
year_h--;
}
if(year_h==-1)
year_h=5;
year=year_h*16+year_l;
write_nyrx(3,year);
LCD_writecom(0x80+4);
break;
case 10: LCD_writecom(0x0c);
K1num=0;
k=0;
DS1302_initW();
display2(date);
display3();
DS1302_Write(0x8e,0x80); //写保护开
break;
}
}
}
}
}
///////////////////////以下为AD采集程序////////////////////////
/*------------------------------------------------
延时程序
------------------------------------------------*/
void mDelay(unsigned char j)
{
unsigned int i;
for(;j>0;j--)
{
for(i=0;i<125;i++)
{;}
}
}
/*------------------------------------------------
初始化定时器1
------------------------------------------------*/
void Init_Timer1(void)
{
TMOD |= 0x10;
TH1=0xff; /* Init value */
TL1=0x00;
//PT1=1; /* 优先级 */
EA=1; /* interupt enable */
ET1=1; /* enable timer1 interrupt */
TR1=1;
}
/*------------------------------------------------
启动IIC总线
------------------------------------------------*/
void Start(void)
{
Sda=1;
_nop_();
Scl=1;
_nop_();
Sda=0;
_nop_();
Scl=0;
}
/*------------------------------------------------
停止IIC总线
------------------------------------------------*/
void Stop(void)
{
Sda=0;
_nop_();
Scl=1;
_nop_();
Sda=1;
_nop_();
Scl=0;
}
/*------------------------------------------------
应答IIC总线
------------------------------------------------*/
void Ack(void)
{
Sda=0;
_nop_();
Scl=1;
_nop_();
Scl=0;
_nop_();
}
/*------------------------------------------------
非应答IIC总线
------------------------------------------------*/
void NoAck(void)
{
Sda=1;
_nop_();
Scl=1;
_nop_();
Scl=0;
_nop_();
}
/*------------------------------------------------
发送一个字节
------------------------------------------------*/
void Send(unsigned char Data)
{
unsigned char BitCounter=8;
unsigned char temp;
do
{
temp=Data;
Scl=0;
_nop_();
if((temp&0x80)==0x80)
Sda=1;
else
Sda=0;
Scl=1;
temp=Data<<1;
Data=temp;
BitCounter--;
}
while(BitCounter);
Scl=0;
}
/*------------------------------------------------
读入一个字节并返回
------------------------------------------------*/
unsigned char Read(void)
{
unsigned char temp=0;
unsigned char temp1=0;
unsigned char BitCounter=8;
Sda=1;
do
{
Scl=0;
_nop_();
Scl=1;
_nop_();
if(Sda)
temp=temp|0x01;
else
temp=temp&0xfe;
if(BitCounter-1)
{
temp1=temp<<1;
temp=temp1;
}
BitCounter--;
}
while(BitCounter);
return(temp);
}
/*------------------------------------------------
写入DA数模转换值
------------------------------------------------*/
void DAC(unsigned char Data)
{
Start();
Send(AddWr); //写入芯片地址
Ack();
Send(0x40); //写入控制位,使能DAC输出
Ack();
Send(Data); //写数据
Ack();
Stop();
}
/*------------------------------------------------
读取AD模数转换的值,有返回值
------------------------------------------------*/
unsigned char ReadADC(unsigned char Chl)
{
unsigned char Data=0;
Start(); //写入芯片地址
Send(AddWr);
Ack();
Send(0x40|Chl);//写入选择的通道,本程序只用单端输入,差分部分需要自行添加
//Chl的值分别为0、1、2、3,分别代表1-4通道
Ack();
Start();
Send(AddRd); //读入地址
Ack();
Data=Read(); //读数据
Scl=0;
NoAck();
Stop();
return Data; //返回值
}
//////////////////////以上为AD采集程序/////////////////////////
void main()
{
uchar n,K5FLAG;
unsigned char bai,shi,ge; //DA数模输出变量
unsigned char ADtemp; //定义中间变量
unsigned char flag=0;
display1(); //初始化屏幕显示
DS1302_initW(); //初始化时间日期
DS1302_initR(); //读取时间日期
jd=1;
while(1)
{
if(K6==0) //按键按下强制关闭
{
delay1ms(5);
if(K6==0)
{
K6FLAG=1;
LCD_writecom(0x01);
}
}
if(K7==0) //按键7按下恢复系统
{
delay1ms(5);
if(K7==0)
{
K6FLAG=0;
display1(); //初始化屏幕显示
}
}
if(K1num==10) //第一个按键第10次按下系统恢复显示主界面
{
LCD_writecom(0x0c);
gflag=0;
K1num=0;
K5FLAG=0; //K1按键计数清零
k=0; //时间继续走
display1();
write_sfm(7,sec);
write_sfm(4,min);
write_sfm(1,hour);
write_nyrx(3,year);
write_nyrx(6,month);
write_nyrx(9,day);
display2(date);
DS1302_initW(); //将设置的时间日期等写入DS1302中
DS1302_Write(0x8e,0x80); //写保护开
}
if(K1num==8||K1num==9) //第一个按键按下第8次用于调整定时的下限值,第9次按下用于调整定时的上限值,定时范围在0点到8点
{
if(K1==0)
{
delay1ms(100);
if(K1==0)
{
K1num++;
}
}
if(K5==0) //确认键按下,定时时间调整完成
{
delay1ms(5);
if(K5==0)
{
K5FLAG=1;
}
}
if(K1num>0&& K5FLAG==1)
{
LCD_writecom(0x0c);
gflag=0;
K1num=0;
K5FLAG=0; //K1按键计数清零
k=0; //时间继续走
LCD_writecom(0x80);
display1();
write_sfm(7,sec);
write_sfm(4,min);
write_sfm(1,hour);
write_nyrx(3,year);
write_nyrx(6,month);
write_nyrx(9,day);
display2(date);
DS1302_initW(); //将设置的时间日期等写入DS1302中
DS1302_Write(0x8e,0x80); //写保护开
}
else{
table4[4]=table[dsl/10];
table4[5]=table[dsl%10];
table4[14]=table[dsh/10];
table4[15]=table[dsh%10];
LCD_writecom(0x80);
for(n=0;n<16;n++)
{
LCD_writedat(table4[n]);
delay1ms(2);
}
LCD_writecom(0x80+0x40);
if(K1num==9)
{
LCD_writedat('D');
LCD_writedat('S');
LCD_writedat('H');
for(n=3;n<16;n++)
{
LCD_writedat(' ');
delay1ms(2);
}
}
if(K1num==8)
{
LCD_writedat('D');
LCD_writedat('S');
LCD_writedat('L');
for(n=3;n<16;n++)
{
LCD_writedat(' ');
delay1ms(2);
}
}
}
if(K1num==8)
{
if(K2==0)
{
delay1ms(100);
if(K2==0)
{
if(dsl<(dsh-1))
{
dsl++;
}
}
}
if(K3==0)
{
delay1ms(100);
if(K3==0)
{
if(dsl>0)
{
dsl--;
}
}
}
}
if(K1num==8)
{
if(K2==0)
{
delay1ms(100);
if(K2==0)
{
if(dsl<(dsh-1))
{
dsl++;
}
}
}
if(K3==0)
{
delay1ms(100);
if(K3==0)
{
if(dsl>0)
{
dsl--;
}
}
}
}
if(K1num==9)
{
if(K2==0)
{
delay1ms(100);
if(K2==0)
{
if(dsh<8)
{
dsl++;
}
}
}
if(K3==0)
{
delay1ms(100);
if(K3==0)
{
if(dsh>dsl)
{
dsh--;
}
}
}
}
}
else
{
if(K6FLAG==0)
{
if(gflag==0)
{
// display1();
ADtemp=255-ReadADC(2);
bai=ADtemp/100;//处理0通道电压显示
shi=ADtemp%100/10;
ge=ADtemp%10;
LCD_writecom(0x80+0x40+11);
LCD_writedat(table[bai]);
LCD_writecom(0x80+0x40+12);
LCD_writedat(table[shi]);
LCD_writecom(0x80+0x40+13);
LCD_writedat(table[ge]);
keyscan();
//设定时间0点到7点之间路灯关闭,当红外传感器检测到有人路过时自动打开路灯,10s后关闭
if(dsh>=((((hour/16)*10)+(hour%16)))&&((((hour/16)*10)+(hour%16)))>=dsl)//在设置的时间段以红外检测的结果作为开灯的依据
{
jd=1;
if(K4==1)
{
jd=0;
LCD_writecom(0x80+0x40+15);
LCD_writedat('h');
// mDelay(50);
}
else
{
LCD_writecom(0x80+0x40+15);
LCD_writedat('l');
jd=1;
// mDelay(50);
}
}
// }
else
{
//在其他时间段根据光敏电阻的光照值来打开路灯,即在傍晚时自动打开路灯
if(ADtemp<100)
{jd=0;}
else
{jd=1;}
}
}
else
{
keyscan();
}
if(gflag>10)
{
gflag=0;
}
}
}
}
}
|