//DS1302时钟程序
#include
#include
#define uchar unsigned char
#define uint unsigned int
/********************************************************************/
//少占鱼制作 河北正定欢迎您 长沙航空职业技术学院 2010 年QQ:411656434
#define LCD1602_RS P2_5 //定义引脚
#define LCD1602_RW P2_6
#define LCD1602_E P2_7
#define LCD1602_IO P0
#define Busy 0x80 //用于检测LCD1602状态字中的Busy标识
const uchar num[]=" 3456789+";
uchar code a[] = {" E N v"};
void WriteData(uchar DAT);
void WriteCommand(uchar command,BuysC);
uchar ReadData(void);
void Readbusy(void);
void LCD1602_Init(void);
void DisplayOneChar(uchar X, uchar Y, uchar DData);
void Displaystring(uchar X, uchar Y, uchar *DData);
void Delay5Ms(void);
void Delay400Ms(void);
void delayms(uint);
void delays(uint m) ;
void delayus(uchar x) ;
sbit DS1302_CLK =P2^0;// P1^0;
sbit DS1302_IO =P2^1;// P1^1;
sbit DS1302_RST =P2^2;// P1^2;
uchar shuju;
unsigned char time[]={0x11,0x03,0x28,0x01,0x12,0x39,0x00};// 初始化时间年月日星期时分秒
uchar Display_Buffer[12]={"12:25:00"};//时、分、秒 的格式
uchar riqi[12]={"11-03-28"};//年、月、日 的格式
uchar xingqi[5]="week";//星期
unsigned char second,minute,hour,week,day,month,year;
/******************1602函数********************************/
/********************************************************************/
void delays(uint m)
{
uint i,j;
for(i=0;i
for(j=0;j<1000;j++)
{;}
}
}
void Delay(void)
{
unsigned char i;
unsigned int j;
for(i=0;i<200;i++)
for(j=300;j>0;j--);
}
/*****************************************************************************
函数功能:向DS1302送一字节数据子程序
入口参数:
出口参数:
*****************************************************************************/
void InputByte(unsigned char BYTE)
{
char i;
for(i=8;i>0;i--)
{ //前面在read_ds1302()函数里已经把CLK清0了
DS1302_CLK=0;//这里再清0一次,看着清楚。呵呵
_nop_();
DS1302_IO=(bit)(BYTE&0x01);//取出低位数据给数据引脚
_nop_();
_nop_();
DS1302_CLK=1;//置1,时钟上升沿,引脚上的数据传入1302寄存器中
_nop_();
_nop_();
BYTE>>=1;//因为这里移位的BYTE不是最后要的结果,虽然最后循环完会多移一位,但没影响。
_nop_();
//循环最后一次后,时钟状态是高电平。
}
_nop_();
_nop_();
}
/*****************************************************************************
函数功能:读DS1302一个字节子程序,读数据是下降沿读
入口参数:
出口参数:
*****************************************************************************/
unsigned char OutputByte(void)
{
unsigned char i;
unsigned char ucdat=0;
for(i=8;i>0;i--)
{ //前面时钟状态是高电平。
ucdat>>=1; //移位注意,移位不能放在循环语句末,否则最后循环完会多移一位。得到结果就错了。
DS1302_IO=1;//单片机端置高防止破坏1302传来的数据,开始接收1302端的高低数据对数据线的改变。
DS1302_CLK=0;//紧接着时钟变低,下降沿数据输出。
if(DS1302_IO)//数据已经输出,判断是1还是0.
ucdat|=0x80;//如果引脚是高则此位保存1。低不保存,右移的时候自然补0了。
_nop_();
DS1302_CLK=1;//读完一位数据,再置高时钟,准备读下一个。
_nop_();//延时一下。
}
//读完数据还是把时钟清0,下次好直接用。
DS1302_CLK=0;//读完数据还是把时钟清0,下次好直接用。
_nop_();
_nop_();
DS1302_RST=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
DS1302_CLK=0;
_nop_();
_nop_();
_nop_();
_nop_();
DS1302_RST=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
return(ucdat);
}
/*****************************************************************************
函数功能:向DS1302某地址写一字节数据子程序
入口参数:addr,TDat
出口参数:
*****************************************************************************/
void write_ds1302(unsigned char addr,unsigned char TDat)
{
DS1302_RST=0;
_nop_();
_nop_();
DS1302_CLK=0;
_nop_();
_nop_();
DS1302_RST=1;
_nop_();
_nop_();
_nop_();
_nop_();
InputByte(addr);//先写地址
_nop_();
_nop_();
InputByte(TDat);//再写数据
DS1302_IO=1;//单片机端置高防止破坏1302传来的数据,开始接收1302端的高低数据对数据线的改变。
DS1302_RST=0;
delayus(10);
DS1302_CLK=0;
delayus(10);
}
/*****************************************************************************
函数功能:读DS1302地址子程序
入口参数:add
出口参数:timedata
*****************************************************************************/
unsigned char read_ds1302(unsigned char addr)
{
unsigned char timedata;
DS1302_RST=0;
_nop_();
DS1302_CLK=0;
_nop_();
DS1302_RST=1;
InputByte(addr);//先写入读命令
timedata=OutputByte();//再读出数据
DS1302_IO=1;//单片机端置高防止破坏1302传来的数据,开始接收1302端的高低数据对数据线的改变。
DS1302_RST=0;
delayus(10);
DS1302_CLK=0;
delayus(10);
return(timedata);
}
/*****************************************************************************
函数功能:初始化DS1302子程序
入口参数:time[](全局变量)
出口参数:
*****************************************************************************/
void initial_ds1302()
{
DS1302_IO=1;//单片机端置高防止破坏1302传来的数据,开始接收1302端的高低数据对数据线的改变。
DS1302_RST=0;
delayms(100);
DS1302_CLK=0;
delayms(100);
write_ds1302(0x8e,0x00); //写保护寄存器,在对时钟或RAM写前WP一定要为0
write_ds1302(0x8c,time[0]); //年
write_ds1302(0x88,time[1]); //月
write_ds1302(0x86,time[2]); //日
write_ds1302(0x8A,time[3]); //星期
write_ds1302(0x84,time[4]); //时
write_ds1302(0x82,time[5]); //分
write_ds1302(0x80,time[6]); //秒
write_ds1302(0x8e,0x80); //写保护寄存器
}
/*****************************************************************************
函数功能:读DS1302时间子程序
入口参数:
出口参数:全局变量(second,minute,hour,week,day,month,year)
*****************************************************************************/
void read_time()
{
second=read_ds1302(0x81); //秒寄存器
_nop_();
minute=read_ds1302(0x83); //读分
_nop_();
hour=read_ds1302(0x85); //读时
_nop_();
week=read_ds1302(0x8B); //读星期
_nop_();
day=read_ds1302(0x87); //日
_nop_();
month=read_ds1302(0x89); //月
_nop_();
year=read_ds1302(0x8d); //年
_nop_();
}
void main(void)
{uchar shuju;
delayms(2);
Delay400Ms(); //启动等待,等LCM讲入工作状态
delays(1);
LCD1602_Init(); //LCM初始化
Delay5Ms(); //延时片刻(可不要)
DS1302_RST=0;
delayms(1000);
DS1302_CLK=0;
delayms(1000);
shuju=ReadData();
Displaystring(2, 0, a);
Delay();Delay();
delayms(2000);
Displaystring(3,0,riqi);
Displaystring(12,0,xingqi);
delayms(4000);
// initial_ds1302(); //初始化DS1302
delayms(1200);
while(1)
{
read_time();//读取时间
Display_Buffer[0]=hour/16+'0';//存储下时的高位进数组
Display_Buffer[1]=hour%16+'0';//存储下时的低位进数组
Display_Buffer[3]=minute/16+'0';//注意+'0'后存储的是ASCII。用于下面液晶显示。
Display_Buffer[4]=minute%16+'0';//注意+'0'后存储的是ASCII。用于下面液晶显示。
Display_Buffer[6]=second/16+'0';
Display_Buffer[7]=second%16+'0';
riqi[0]=year/16+'0';
riqi[1]=year%16+'0';
riqi[3]=month/16+'0';
riqi[4]=month%16+'0';
riqi[6]=day/16+'0';
riqi[7]=day%16+'0';
Displaystring(3,0,riqi);
delayms(1);
DisplayOneChar(14,1,week+'0');
Displaystring(3,1,Display_Buffer);
}
}
//写数据
void WriteData(uchar DAT)
{
Readbusy();
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_IO = DAT;
LCD1602_E = 0; //若晶振速度太高可以在这后加小的延时
LCD1602_E = 0; //延时
LCD1602_E = 1;
LCD1602_E=1;
LCD1602_E=0;
}
//写指令
void WriteCommand(uchar command,BuysC) //BuysC为0时忽略忙检测
{
LCD1602_IO=0x00;
if (BuysC)
Readbusy(); //根据需要检测忙
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_IO = command;
LCD1602_E = 0;
LCD1602_E = 0;
LCD1602_E = 1;
LCD1602_E = 1;
LCD1602_E=0;
}
//读数据
uchar ReadData(void)
{
Readbusy();
LCD1602_RS = 1;
LCD1602_RW = 1;
LCD1602_E = 0;
LCD1602_E = 0;
LCD1602_E = 1;
delayms(1);
LCD1602_E = 0;
return(LCD1602_IO);
}
//读忙
void Readbusy(void)
{
LCD1602_IO = 0xff;
LCD1602_RS = 0;
LCD1602_RW = 1;
LCD1602_E = 0;
LCD1602_E = 0;
LCD1602_E = 1;
delayms(2);
while (LCD1602_IO&0x80); //检测忙信号
LCD1602_E = 0;
}
//初始化
void LCD1602_Init(void) //LCM初始化
{
Delay400Ms();
LCD1602_E = 0;
LCD1602_IO=0x00;
WriteCommand(0x38,0); //三次显示模式设置,不检测忙信号
Delay5Ms();
WriteCommand(0x38,0);
Delay5Ms();
WriteCommand(0x38,0);
Delay5Ms();
WriteCommand(0x38,1); //显示模式设置,开始要求每次检测忙信号
Delay5Ms();
WriteCommand(0x08,1); //关闭显示 ]
Delay5Ms();
WriteCommand(0x01,1); //显示清屏
Delay5Ms();
WriteCommand(0x06,1); // 显示光标移动设置
Delay5Ms();
WriteCommand(0x0f,1); // 显示开及光标设置
Delay5Ms();
}
//按指定位置显示一个字符
void DisplayOneChar(uchar X, uchar Y, uchar DData)
{
Y &= 0x01;
X &= 0x0f; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
X |= 0x80; // 算出指令码
WriteCommand(X, 0); //这里不检测忙信号,发送地址码
WriteData(DData);
}
//按指定位置显示一串字符
void Displaystring(uchar X, uchar Y, uchar *DData)
{
uchar ListLength;
ListLength = 0;
Y &= 0x01;
X &= 0x0f; //限制X不能大于15,Y不能大于1
while (DData[ListLength]>0x20) //若到达字串尾则退出
{
if (X <= 0x0f) //X坐标应小于0x0f
{
DisplayOneChar(X, Y, DData[ListLength]); //显示单个字符
ListLength++;
X++;
}
}
}
//5ms延时
void Delay5Ms(void)
{
unsigned int t = 5552;
while(t--);
}
//400ms延时
void Delay400Ms(void)
{
uchar i = 5;
uint j;
while(i--)
{
j=7269;
while(j--);
}
}
//
void delayms(uint k)
{
uint data i,j;
for(i=0;i
for(j=0;j<121;j++)
{;}
}
}
void delayus(uchar x)
{
while(--x);
}