#include<reg51.h>
#include<intrins.h>
#include"DS1302.h"
#include"KEY.h"
#include"IIC.H"
#define uchar unsigned char
#define uint unsigned int
#define LEDIO P0
#define LEDCHIP P2
sbit BEEP=P3^7;
/*************************数码管定义**************************************/
//段码 0 1 2 3 4 5 6 7 8 9 A B - P d
uchar code led[15]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x40,0x73,0x5E};
//位选信号 全灭
uchar code selchip[7]={0x01,0x02,0x04,0x08,0x10,0x20,0x10};
//数据格式: 秒 分 时 日 月 星期 年
uchar time_temp[7]={0x00,0x50,0x10,0x12,0x30,0x01,0x11}; //存放初始化时间及设置ds1302的数据
uchar DataTime[7]; //读取DS1302的数据
/**********************************************************/
uchar display[4][6]={0x06,0x5b,0x6d,0x6f,0x6d,0x6f}; //数码管显示
uchar i=0,key1,key2=20,pos=0,p,k; //按键和扫描变量
uchar mod=0; //模式:设置时间进入按钮
bit bflash=0,clockdown=0; //设置和闹铃标志
uchar hour,minute,second,year,month,date; //有关时间的变量寄存
uchar ss=1;//闹铃响的次数可以自己修改
uchar clock1[3]={0x06,0,0x01},clock2[3]={14,0,0x01}; //闹钟时间与开关,默认开关开
uint num=5000; //设置自动返回主界面时间
/////////////////////////////////
void TimeInit() //定时扫描初始化
{
EA = 0;
TMOD |= 0x10;
TH1 = 0xfd;
TL1 = 0xe6;
EA=1;
// ET0=1;
ET1=1;
TR1=1;
}
///////////////////////////////////////////////////////
/*
void t0int() interrupt 1 //T0中断程序,控制发音的音调
{
TR0 = 0; //先关闭T0
BEEP = ~BEEP; //输出方波, 发音
TH0 = t0h; //下次的中断时间, 这个时间, 控制音调高低
TL0 = t0l;
TR0 = 1; //启动T0
LEDIO=display[mod][i];
LEDCHIP=selchip[i];
if(i>=5)
i=0;
else
i++;
}
*/
/////////////////////////////////////////
void TimeInt() interrupt 3 //定时扫描中断
{
if(i==pos)
{
if(bflash==1) //闪烁标志;设置时间日期和闹铃
{
if(k++<40)
{
if(i==4)
i=0;
else
i=i+2;
}
else
{
if(p++>40)
{
p=0;
k=0;
}
}
}
}
LEDIO=display[mod][i];
LEDCHIP=selchip[i];
if(num==0) //自动还回时间界面
{
mod=0;
bflash=0;
}
else
num--;
if(i>=5)
i=0;
else
i++;
TH1=0xfa;
TL1=0xd8;
}
////////////////////////////////////////////////////////
void TimeToBin() //把时间变成2进制
{
second=DataTime[0]/16*10+DataTime[0]%16;
minute=DataTime[1]/16*10+DataTime[1]%16;
hour=DataTime[2]/16*10+DataTime[2]%16;
date=DataTime[3]/16*10+DataTime[3]%16;
month=DataTime[4]/16*10+DataTime[4]%16;
year=DataTime[6]/16*10+DataTime[6]%16;
}
////////////////////////////////////////////////////////
void TimeToBCD() //把时间变为BCD码
{
time_temp[0]=second/10*16+second%10;
time_temp[1]=minute/10*16+minute%10;
time_temp[2]=hour/10*16+hour%10;
time_temp[3]=date/10*16+date%10;
time_temp[4]=month/10*16+month%10;
time_temp[6]=year/10*16+year%10;
}
////////////////////////////////////////////////
void TimerDis()
{ /************************时间扫描设置************************/
display[0][0]=led[hour/10];
display[0][1]=led[hour%10]|0x80;
display[0][2]=led[minute/10];
display[0][3]=led[minute%10]|0x80;
display[0][4]=led[second/10];
display[0][5]=led[second%10];
/************************日期扫描设置************************/
display[1][0]=led[year/10];
display[1][1]=led[year%10]|0x80;
display[1][2]=led[month/10];
display[1][3]=led[month%10]|0x80;
display[1][4]=led[date/10];
display[1][5]=led[date%10];
/**********************闹铃1扫描设置****************************/
display[2][0]=led[10]; //第一个闹钟
display[2][1]=led[14-clock1[2]]; //P闹钟开d闹钟关
display[2][2]=led[clock1[0]/10];
display[2][3]=led[clock1[0]%10]|0x80;
display[2][4]=led[clock1[1]/10];
display[2][5]=led[clock1[1]%10];
/***********************闹铃2扫描设置**************************/
display[3][0]=led[11]; //第一个闹钟
display[3][1]=led[14-clock2[2]]; //P闹钟开d闹钟关
display[3][2]=led[clock2[0]/10];
display[3][3]=led[clock2[0]%10]|0x80;
display[3][4]=led[clock2[1]/10];
display[3][5]=led[clock2[1]%10];
/********************************************************/
//second=DataTime[0]/16*10+DataTime[0]%16;
}
///////////////////////////////////////////////////////
void KeySet()
{
key1=KeyTab[KeyRvs()]; //读取键盘值
if(key2!=key1) //防止连续跳动,释放按键
{
if(key1=='*')
{
pos=0; //返回首位方便设置
if(!bflash) //先进设置时间的界面
mod=0;
else
mod=(mod+1)%4; //功能选择
bflash=1; //进入时钟设置标志
num=5000; //若是没有操作自动返回主界面
}
/////////////////////////////移位按键选择设置的位置
if((key1=='0')&&(bflash))
{
pos=(pos+2)%6;
num=5000;
}
if((!bflash)&&(key1=='0')) //一键关闭闹铃睡懒觉按键,下次又开闹铃
{
clockdown=1;
}
///////////////////////////// 时分秒设置,加按键,
if((key1=='#')&&(bflash))
{
num=5000; //
if(mod==0) //时间设置
{
if(pos==0)
{
hour=(hour+1)%24;
}
else if(pos==2)
{
minute=(minute+1)%60;
}
else
{
second=(second+1)%60;
}
}
////////////////////////////////年月日设置
if(mod==1)
{
if(pos==0)
{
year=(year+1)%100;
}
else if(pos==2)
{
month=(month+1)%13;
}
else
{
if(month==2) //二月处理
{
if(year%4==0) //闰年二月
date=(date+1)%30;
else
date=(date+1)%29;
}
/////////////////////////////////////////////////大月设置
else if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12))
date=(date+1)%32;
else /////////////////////////////////////////小月设置
date=(date+1)%31;
}
}
//////////////////////////////////////////////闹铃1设置
if(mod==2)
{
if(pos==0) //闹铃1开关设置
{
clock1[2]=(clock1[2]+1)%2;
}
if(pos==2)
{
clock1[0]=(clock1[0]+1)%24;
}
if(pos==4)
{
clock1[1]=(clock1[1]+1)%60;
}
}
//////////////////////////////////////////////闹铃2设置
if(mod==3)
{
if(pos==0) //闹铃2开关设置
{
clock2[2]=(clock2[2]+1)%2;
}
if(pos==2)
{
clock2[0]=(clock2[0]+1)%24;
}
if(pos==4)
{
clock2[1]=(clock2[1]+1)%60;
}
}
}
if((!bflash)&&(key1=='#')) //查看闹铃设置
{
mod=(mod+1)%2+2;
}
///////////////////////////////////////////////确认键设置
if(key1=='D')
{
if(bflash) //清除设置标志
{
bflash=0;
mod=0;
TimeToBCD();
Set_Ds1302(time_temp);
while(!Write_Nbyte_iic(SLAVE,0x50,clock1,3));
while(!Write_Nbyte_iic(SLAVE,0x60,clock2,3));
}
else //切换时间和日期
mod=(mod+1)%2;
num=5000; //自动返回时间界面
}
key2=key1;
} //键值保存。释放按键用
}
//////////////////////////////////////
/********************闹铃响一分钟****************************/
void CLOCK()
{
if((clock1[0]==hour)&&(clock1[1]==minute)&&(clock1[3])||((clock2[0]==hour)&&(clock2[1]==minute)&&(clock2[3])))
{
if(!clockdown) //没有睡懒觉则正常响铃
BEEP=~BEEP;
else
BEEP=1; //否则关闭闹铃
}
else
{
clockdown=0; //恢复闹铃
BEEP=1; //关闭闹铃
}
}
/////////////////////////////////////////
main()
{
while(!Read_Nbyte_iic(SLAVE,0x50,clock1,3));
while(!Read_Nbyte_iic(SLAVE,0x60,clock2,3));
TimeInit(); //断电以后唤醒时钟
Init_Ds1302();
while(1)
{
Get_Ds1302(DataTime); //读取时间
TimerDis(); //段码处理
KeySet(); //扫描按键
if(!bflash) //如果没有进入设置时间则正常显示否则时间暂停
{
TimeToBin();
}
CLOCK(); //闹铃设置
}
}
/*******************************************************************************************************************************/
#ifndef _DS1302_H_
#define _DS1302_H_
/*********************************************************************************/
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit RST = P3^4;
sbit SCLK = P3^5;
sbit IO = P3^6;
/********以下是函数声明********/
void Ds1302_Write_Byte(uchar ch); //写一字节数据函数声明
uchar Ds1302_Read_Byte(); //读一字节数据函数声明
void Write_Ds1302(uchar cmd,uchar indata); //写DS1302函数声明
uchar Read_Ds1302(uchar addr); //读DS1302函数声明
void Set_Ds1302(uchar *str); //设置时钟数据地址 格式为: 秒 分 时 日 月 星期 年
void Get_Ds1302(uchar *str); //读当前时间函数声明
void Init_Ds1302(); //DS1302初始化函数声明
/********以下是写一字节数据函数********/
void Ds1302_Write_Byte(uchar ch)
{
uchar n;
EA=0;
for(n=0;n<8;n++)
{
SCLK=0; //写时低电平改变数据
if(ch&0x01)
IO=1;
else
IO=0;
SCLK=1; //高电平把数据写入DS1302
_nop_();
_nop_();
ch=ch>>1;
}
EA=1;
}
/********以下是读一字节数据函数********/
uchar Ds1302_Read_Byte()
{
uchar n,temp=0;
EA=0;
IO=1;
for(n=0;n<8;n++)
{
SCLK=1;
if(IO)
temp|=0x80;
else
temp&=0x7f;
SCLK=0; //产生下跳沿
temp=temp>>1;
}
EA=1;
return (temp);
}
/********写DS1302函数, 往DS1302的某个地址写入数据 ********/
void Write_Ds1302(uchar cmd,uchar indata)
{
SCLK=0;
RST=1;
Ds1302_Write_Byte(cmd);
Ds1302_Write_Byte(indata);
SCLK=0;
RST=0;
}
/********读DS1302函数,读DS1302某地址的的数据********/
uchar Read_Ds1302(uchar addr)
{
uchar backdata;
RST=0;
SCLK=0;
RST=1;
Ds1302_Write_Byte(addr); //先写地址
backdata=Ds1302_Read_Byte(); //然后读数据
SCLK=0;
RST=0;
return (backdata);
}
/********设置初始时间函数********/
void Set_Ds1302(uchar *str)
{
uchar n,addr = 0x80;
Write_Ds1302(0x8e,0x00); //写控制字,允许写操作
for(n=0;n<7;n++)
{
Write_Ds1302(addr,*str);
addr=addr+2;
str++;
}
Write_Ds1302(0x8e,0x80); //写保护,不允许写
}
/********读取当前时间函数********/
void Get_Ds1302(uchar *str)
{
uchar n,addr = 0x81;
for(n=0;n<7;n++)
{
str[n]=Read_Ds1302(addr);
addr+=2;
}
}
/************初始化时间********************/
void Init_Ds1302()
{
RST=0;
SCLK=0;
RST=1;
Write_Ds1302(0x80,0x00); //写秒寄存器
Write_Ds1302(0x90,0xab); //写充电器
Write_Ds1302(0x8e,0x80); //写保护控制字,禁止写
}
///////////////////////////////////////
#endif
/***********************************************************************************************************************/
#ifndef _KEY_H_
#define _KEY_H_
/****************************************************/
#define KEYIO P1 //定义键盘的输入口
unsigned char code KeyTab[17]="123A456B789C*0#D"; //键盘查表
/***********************************************/
void delay_ms(unsigned int time) //误差 -0.000000000003us
{
unsigned char a,b;
while(time--)
{
for(b=102;b>0;b--)
for(a=3;a>0;a--);
}
}
/**************************************************/
///////////////////////////////////////////////
unsigned char KeyRvs(void) //反转法
{
unsigned char temH, temL, key;
delay_ms(10); //两次扫描间隔为10ms,消除抖动导致的误操作
KEYIO = 0x0f; temL = KEYIO;//高四位先输出0;读入,低四位含有按键信息
KEYIO = 0xf0; temH = KEYIO;//然后反转输出0;读入,高四位含有按键信息
switch(temL)
{
case 0x0e: key = 0; break;
case 0x0d: key = 1; break;
case 0x0b: key = 2; break;
case 0x07: key = 3; break;
default: return 16;//按下的不是上述按键,就当是没有按键
}
switch(temH)
{
case 0xe0: return key;
case 0xd0: return (key + 4);
case 0xb0: return (key + 8);
case 0x70: return (key + 12);
default: return 16;//按下的不是上述按键,就当是没有按键
}
}
/**********************************************************/
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef _IIC_H
#define _IIC_H_
/***************************************************/
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define SLAVE 0xa0 //IIC器件地址 注意全部接地
#define Rslave SLAVE+1 //送读控制字
sbit SDA=P3^0; //IIC数据接口
sbit SCL=P3^1; //IIC时钟接口
////////////////////////////////////////////////////////
void delay_iic(uint time)
{
for(time;time>0;time--);
}
///////////////////////////////////////
void start_iic()
{
SDA=1;
SCL=1;
delay_iic(10);
SDA=0;
delay_iic(10);
SCL=0;
}
void stop_iic()
{
SDA=0;
SCL=1;
delay_iic(10);
SDA=1;
delay_iic(10);
SCL=0;
}
void ack_iic()
{
SDA=0;
SCL=1;
delay_iic(10);
SCL=0;
SDA=1;
}
void nack_iic()
{
SDA=1;
SCL=1;
delay_iic(10);
SCL=0;
SDA=0;
}
////////////////////////* write 1 byte *//////////////////////
void write_byte(uchar ch)
{
uchar i;
for(i=0;i<8;i++)
{
if(ch&0x80)
SDA=1;
else
SDA=0;
SCL=1;
delay_iic(10);
SCL=0;
ch=ch<<1;
}
SDA=1;
SCL=1;
delay_iic(10);
if(SDA==1)
F0=0;
else
F0=1;
SCL=0;
}
///////////////////////////* read 1 byte *////////////////////////
uchar read_byte()
{
uchar i;
uchar r=0;
SDA=1;
for(i=0;i<8;i++)
{
r=r<<1;
SCL=1;
delay_iic(10);
if(SDA==1)
r++;
SCL=0;
}
return r;
}
/***********************写一个字节**************************
bit Write_Byte_iic(uchar addr,uchar ch)
{
start_iic(); //产生起始信号
write_byte(SLAVE); //发送从器件地址
if(F0==0) return 0; //检查应答位
write_byte(addr); //发送目的地址
if(F0==0) return 0;
write_byte(ch); //发送8为数据
if(F0==0) return 0;
stop_iic(); //停止信号
return 1;
}
/********************读一个字节***************************
uchar Read_Byte_iic(uchar addr)
{
uchar ch;
start_iic(); //启动IIC
write_byte(SLAVE); //写器件地址
if(F0==0)return 0;
write_byte(addr); //写读取的地址
if(F0==0)return 0;
start_iic(); //再次产生起始信号,不能少
write_byte(Rslave); //送读控制字
if(F0==0)return 0;
ch=read_byte(); //读出指定单元的内容
nack_iic(); //非应答信号
stop_iic(); //停止IIC
return (ch);
}
************************************************************/
////////////////////////////////////////////////////////////
bit Read_Nbyte_iic(uchar slave,uint addr,uchar *str,uchar numb)
{
uchar i;
start_iic();
write_byte(slave); //write iic addr
if(F0==0)
return 0;
write_byte(addr); //write data addr
if(F0==0)
return 0;
start_iic(); //再次产生起始信号,不能少
write_byte(Rslave); //送读控制字
if(F0==0)
return 0;
for(i=0;i<numb-1;i++) //
{
*str=read_byte();
ack_iic();
str++;
}
*str=read_byte();
nack_iic();
stop_iic();
return(1);
}
/////////////////////////* write n byte *////////////////////////////
bit Write_Nbyte_iic(uchar slave,uint addr,uchar *str,uchar numb)
{
uchar i;
start_iic();
write_byte(slave); //write iic addr
if(F0==0)
return 0;
write_byte(addr); //write data addr
if(F0==0)
return 0;
for(i=0;i<numb;i++) //write data
{
write_byte(*str);
if(F0==0)
return 0;
str++;
}
stop_iic(); //stop iic
return(1);
}
/////////////////////////////////////////////////////////////////
#endif