/******************************************************************** * 文件名 : 时钟DS1302LCD.c * 描述 : 该程序实现了用单片机来控制时钟芯片DS1302进行时钟的显示。 时钟会在1602上显示. ***********************************************************************/ #include<reg52.h> #include<intrins.h> #define uchar unsigned char #define uint unsigned int sbit ACC0 = ACC^0; sbit ACC7 = ACC^7; sbit T_CLK = P3^6; /*实时时钟时钟线引脚 */ sbit T_IO = P3^4; /*实时时钟数据线引脚 */ sbit T_RST = P3^5; /*实时时钟复位线引脚 */ //这三个引脚参考资料 sbit E=P2^6; //1602使能引脚 sbit RW=P2^5; //1602读写引脚 sbit RS=P2^4; //1602数据/命令选择引脚 /******************************************************************** * 名称 : delay() * 功能 : 延时,延时时间大概为5US。 * 输入 : 无 * 输出 : 无 ***********************************************************************/ void delay() { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); } void Delay(uint i) { uint x,j; for(j=0;j<i;j++) for(x=0;x<=148;x++); } /******************************************************************** * 名称 : bit Busy(void) * 功能 : 这个是一个读状态函数,读出函数是否处在忙状态 * 输入 : 输入的命令值 * 输出 : 无 ***********************************************************************/ bit Busy(void) { bit busy_flag = 0; RS = 0; RW = 1; E = 1; delay(); busy_flag = (bit)(P0 & 0x80); E = 0; return busy_flag; } /******************************************************************** * 名称 : wcmd(uchar del) * 功能 : 1602命令函数 * 输入 : 输入的命令值 * 输出 : 无 ***********************************************************************/ void wcmd(uchar del) { while(Busy()); RS = 0; RW = 0; E = 0; delay(); P0 = del; delay(); E = 1; delay(); E = 0; } /******************************************************************** * 名称 : wdata(uchar del) * 功能 : 1602写数据函数 * 输入 : 需要写入1602的数据 * 输出 : 无 ***********************************************************************/ void wdata(uchar del) { while(Busy()); RS = 1; RW = 0; E = 0; delay(); P0 = del; delay(); E = 1; delay(); E = 0; } /******************************************************************** * 名称 : L1602_init() * 功能 : 1602初始化,请参考1602的资料 * 输入 : 无 * 输出 : 无 ***********************************************************************/ void L1602_init(void) { wcmd(0x38); Delay(5); wcmd(0x38); Delay(5); wcmd(0x38); Delay(5); wcmd(0x38); wcmd(0x08); wcmd(0x0c); wcmd(0x04); wcmd(0x01); } /******************************************************************** * 名称 : L1602_char(uchar hang,uchar lie,char sign) * 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符显示"b" ,调用该函数如下 L1602_char(1,5,'b') * 输入 : 行,列,需要输入1602的数据 * 输出 : 无 ***********************************************************************/ void L1602_char(uchar hang,uchar lie,char sign) { uchar a; if(hang == 1) a = 0x80; if(hang == 2) a = 0xc0; a = a + lie - 1; wcmd(a); wdata(sign); } /******************************************************************** * 名称 : L1602_string(uchar hang,uchar lie,uchar *p) * 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符开始显示"ab cd ef" ,调用该函数如下 L1602_string(1,5,"ab cd ef;") * 输入 : 行,列,需要输入1602的数据 * 输出 : 无 ***********************************************************************/ void L1602_string(uchar hang,uchar lie,uchar *p) { uchar a,b=0; if(hang == 1) a = 0x80; if(hang == 2) a = 0xc0; a = a + lie - 1; while(1) { wcmd(a++); if((*p == '\0')||(b==16)) break; b++; wdata(*p); p++; } } /******************************************************************** * 名称 : v_RTInputByte() * 功能 : 往DS1302写入1Byte数据 * 输入 : ucDa 写入的数据 * 输出 : 无 ***********************************************************************/ void v_RTInputByte(uchar ucDa) { uchar i; ACC = ucDa; T_RST = 1; for(i=8; i>0; i--) { T_IO = ACC0; T_CLK = 1; T_CLK = 0; ACC = ACC >> 1; } } /******************************************************************** * 名称 : uc_RTOutputByte() * 功能 : 从DS1302读取1Byte数据 * 输入 : 无 * 返回值: ACC ***********************************************************************/ uchar uc_RTOutputByte(void) { uchar i; T_RST = 1; for(i=8; i>0; i--) { ACC = ACC >>1; T_IO=1; ACC7 = T_IO; T_CLK = 1; T_CLK = 0; } return(ACC); } /******************************************************************** * 名称 : v_W1302(uchar ucAddr, uchar ucDa) * 功能 : 往DS1302写入数据 * 输入 : ucAddr: DS1302地址, ucDa: 要写的数据 * 返回值 : 无 ***********************************************************************/ void v_W1302(uchar ucAddr, uchar ucDa) { T_RST = 0; T_CLK = 0; T_RST = 1; v_RTInputByte(ucAddr); // 写地址 _nop_(); _nop_(); v_RTInputByte(ucDa); // 写1Byte数据 T_CLK = 1; T_RST = 0; } /******************************************************************** * 名称 : uc_R1302(uchar ucAddr) * 功能 : 读取DS1302某地址的数据 * 输入 : ucAddr: DS1302地址 * 返回值 : ucDa :读取的数据 ***********************************************************************/ uchar uc_R1302(uchar ucAddr) { uchar ucDa; T_RST = 0; T_CLK = 0; T_RST = 1; v_RTInputByte(ucAddr); //写地址,命令 _nop_(); _nop_(); ucDa = uc_RTOutputByte(); //读1Byte数据 T_CLK = 1; T_RST = 0; return(ucDa); } /******************************************************************** * 名称 : v_BurstW1302T * 功能 : 往DS1302写入时钟数据(多字节方式) * 输入 : pSecDa: 时钟数据地址 格式为: 秒 分 时 日 月 星期 年 控制 * 8Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B 1B * 返回值 : 无 ***********************************************************************/ void v_BurstW1302T(uchar *pSecDa) { uchar i; v_W1302(0x8e, 0x00); //控制命令,WP=0,写操作 T_RST = 0; T_CLK = 0; T_RST = 1; v_RTInputByte(0xbe); //0xbe:时钟多字节写命令 for(i=8; i>0; i--) //8Byte = 7Byte 时钟数据 + 1Byte 控制 { v_RTInputByte(*pSecDa); //写1Byte数据 pSecDa++; } T_CLK = 1; T_RST = 0; } /******************************************************************** * 名称 : v_BurstR1302T(uchar *pSecDa) * 功能 : 读取DS1302时钟数据 * 输入 : pSecDa: 时钟数据地址 格式为: 秒 分 时 日 月 星期 年 * 7Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B * 返回值 : ucDa :读取的数据 ***********************************************************************/ void v_BurstR1302T(uchar *pSecDa) { uchar i; T_RST = 0; T_CLK = 0; T_RST = 1; v_RTInputByte(0xbf); //0xbf:时钟多字节读命令 for(i=8; i>0; i--) { *pSecDa = uc_RTOutputByte(); //读1Byte数据 pSecDa++; } T_CLK = 1; T_RST = 0; } /******************************************************************** * 名称 : v_BurstW1302R(uchar *pReDa) * 功能 : 往DS1302寄存器数写入数据(多字节方式) * 输入 : pReDa: 寄存器数据地址 * 返回值 : 无 ***********************************************************************/ void v_BurstW1302R(uchar *pReDa) { uchar i; v_W1302(0x8e,0x00); //控制命令,WP=0,写操作 T_RST = 0; T_CLK = 0; T_RST = 1; v_RTInputByte(0xfe); //0xbe:时钟多字节写命令 for(i=31; i>0; i--) //31Byte 寄存器数据 { v_RTInputByte(*pReDa); //写1Byte数据 pReDa++; } T_CLK = 1; T_RST = 0; } /******************************************************************** * 名称 : v_BurstR1302R(uchar *pReDa) * 功能 : 读取DS1302寄存器数据 * 输入 : pReDa: 寄存器数据地址 * 返回值 : 无 ***********************************************************************/ void v_BurstR1302R(uchar *pReDa) { uchar i; T_RST = 0; T_CLK = 0; T_RST = 1; v_RTInputByte(0xff); //0xbf:时钟多字节读命令 for(i=31; i>0; i--) //31Byte 寄存器数据 { *pReDa = uc_RTOutputByte(); //读1Byte数据 pReDa++; } T_CLK = 1; T_RST = 0; } /******************************************************************** * 名称 : v_Set1302(uchar *pSecDa) * 功能 : 设置初始时间 * 输入 : pSecDa: 初始时间地址。初始时间格式为: 秒 分 时 日 月 星期 年 * 7Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B * 返回值: 无 ***********************************************************************/ void v_Set1302(uchar *pSecDa) { uchar i; uchar ucAddr = 0x80; v_W1302(0x8e, 0x00); //控制命令,WP=0,写操作 for(i=7; i>0; i--) { v_W1302(ucAddr, *pSecDa); // 秒 分 时 日 月 星期 年 pSecDa++; ucAddr += 2; } v_W1302(0x8e, 0x80); //控制命令,WP=1,写保护 } /******************************************************************** * 名称 : v_Get1302(uchar ucCurtime[]) * 功能 : 读取DS1302当前时间 * 输入 : ucCurtime: 保存当前时间地址。当前时间格式为: 秒 分 时 日 月 星期 年 * 7Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B * 返回值 : 无 ***********************************************************************/ void v_Get1302(uchar ucCurtime[]) { uchar i; uchar ucAddr = 0x81; for(i=0; i<7; i++) { ucCurtime[i] = uc_R1302(ucAddr); //格式为: 秒 分 时 日 月 星期 年 ucAddr += 2; } } /******************************************************************** * 名称 : dectobcd(uchar dec) * 功能 : DEC码转换为BCD码 * 输入 : dec码 * 输出 : bcd码 ***********************************************************************/ uchar dectobcd(uchar dec) { uchar bcd; bcd = 0; while(dec >= 10) { dec -= 10; bcd++; } bcd <<= 4; bcd |= dec; return bcd; } /******************************************************************** * 名称 : bcdtodec(uchar bcd) * 功能 : BCD码转换为DEC码 * 输入 : bcd码 * 输出 : dec码 ***********************************************************************/ uchar bcdtodec(uchar bcd) { uchar data1; data1 = bcd & 0x0f; //取BCD低4位 bcd = bcd & 0x70; //剔除BCD的最高位和低4位。 data1 += bcd >> 1; data1 += bcd >> 3; //用位移代替乘法运算 return data1; } /******************************************************************** * 名称 : Write_DS1302Init() * 功能 : 往DS1302中写入数据。最开始显示的数据就是在这里设置的。 * 输入 : 无 * 输出 : 无 ***********************************************************************/ void Write_DS1302Init(void) { v_W1302(0x8e,0); v_W1302(0x80,0x50); //写入秒 v_W1302(0x8e,0); v_W1302(0x82,0x59); //写入分 v_W1302(0x8e,0); v_W1302(0x84,0x07); //写入小时 v_W1302(0x8e,0); v_W1302(0x86,0x08); //写入日 v_W1302(0x8e,0); v_W1302(0x88,0x08); //写入月 v_W1302(0x8e,0); v_W1302(0x8a,0x05); //写入星期 v_W1302(0x8e,0); v_W1302(0x8c,0x08); //写入年 } /******************************************************************** * 名称 : Run_DS1302(void) * 功能 : 读出DS1302中的数据,并在液晶1602上进行显示 * 输入 : 无 * 输出 : 无 ***********************************************************************/ void Run_DS1302(void) { uchar sec, min, hour, day, month, year; while(1) { v_W1302(0x8f, 0); sec = bcdtodec(uc_R1302(0x81)); //读出DS1302中的秒 v_W1302(0x8f, 0); min = bcdtodec(uc_R1302(0x83)); //读出DS1302中的分 v_W1302(0x8f, 0); hour = bcdtodec(uc_R1302(0x85)); //读出DS1302中的小时 v_W1302(0x8f, 0); day = bcdtodec(uc_R1302(0x87)); //读出DS1302中的日 v_W1302(0x8f, 0); month = bcdtodec(uc_R1302(0x89)); //读出DS1302中的月 v_W1302(0x8f, 0); year = bcdtodec(uc_R1302(0x8d)); //读出DS1302中的年 L1602_char(2, 6, hour / 10 % 10 + 48); L1602_char(2, 7, hour % 10 + 48); L1602_char(2, 8, '-'); L1602_char(2, 9, min / 10 % 10 + 48); L1602_char(2, 10, min % 10 + 48); L1602_char(2, 11, '-'); L1602_char(2, 12, sec / 10 % 10 + 48); L1602_char(2, 13, sec % 10 + 48); L1602_char(1, 8, year / 10 % 10 + 48); L1602_char(1, 9, year % 10 + 48); L1602_char(1, 10, '-'); L1602_char(1, 11, month / 10 % 10 + 48); L1602_char(1, 12, month % 10 + 48); L1602_char(1, 13, '-'); L1602_char(1, 14, day / 10 % 10 + 48); L1602_char(1, 15, day % 10 + 48); } } /******************************************************************** * 名称 : Main(void) * 功能 : 主函数 * 输入 : 无 * 输出 : 无 ***********************************************************************/ void Main(void) { L1602_init(); L1602_string(1,1,"DAYS 20"); L1602_string(2,1,"TIME"); Write_DS1302Init(); Run_DS1302(); }