一、原理分析
DS1302实时时钟:http://t.csdnimg.cn/JnDl7
HC573/HC138:http://t.csdnimg.cn/W0a0U
数码管:http://t.csdnimg.cn/kfm9Y
独立键盘:http://t.csdnimg.cn/YPInc
二、示例题目
在CT107D单片机综合训练平台上新建工程,采用I/O模式编写代码,实现以下功能:
- 将DS1302的底层驱动代码文件正确移植到工程中。
- 配置J5为BTN模式,将S4、S5和S6设置为独立按键。
- 初始化DS1302的默认启动参数为:24年3月28日23时59分40秒,周四。
- 系统上电后,DS1302实时时钟从默认参数启动运行,并将当前的时、分、秒显示在数码管上,时分秒之间用“_”分隔。
- 按键S4实现“暂停/启动”功能。系统上电时,实时时钟处于启动工作状态,数码管显示实时时间。按下S4按键,数码管的实时时间显示暂停;再次按下S4按键,从当前显示时间点重新启动,继续显示实时时间;如此往复,实现循环控制。
- 按键S5实现“分钟减1”功能。仅在实时时间显示暂停的情况下,每按下1次,分钟减1。在00分的情况下减1,分钟恢复59,忽略时的退位。
- 按键S6实现“分钟加1”功能。该按键仅在实时时间显示暂停的情况下有效,每按下1次,分钟加1。在59分的情况下加1,分钟恢复0,忽略时的进位。
三、示例代码
#include "stc15.h"
#include "ds1302.h"#define TSMG 500
#define TKEY 200sbit s4 = P3^3;
sbit s5 = P3^2;
sbit s6 = P3^1;code unsigned char write_rtc[7] = {0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //rtc写入地址
code unsigned char read_rtc[7] = {0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; //rtc读取地址
//默认启动参数 40秒 59分 23时 28日 3月 周四 24年
code unsigned char now_rtc[7] = {0x40, 0x59, 0x23, 0x28, 0x03, 0x04, 0x24};unsigned char smg_hou; //数码管显示时
unsigned char smg_min; //数码管显示分
unsigned char smg_s; //数码管显示秒
unsigned char date = 1; //数码管显示是否从DS1302获取更新 1更新 0停止更新
unsigned char start_stop = 1; //暂停0/启动1
unsigned char hou = 0; //时
unsigned char min = 0; //分
unsigned char s = 0; //秒void delay_smg(unsigned int t) //数码管延时函数
{while(t--);
}void delay_key(unsigned int t) //键盘延时函数
{while(t--);
}// 共阳数码管段码表
code unsigned char Seg_Table[] =
{0xc0, //00xf9, //10xa4, //20xb0, //30x99, //40x92, //50x82, //60xf8, //70x80, //80x90, //90x88, //A0x83, //b0xc6, //C0xa1, //d0x86, //E0x8e //F
};//控制所有数码管
void smg_all(unsigned char dat)
{hc573(6,0xff);hc573(7,dat);
}
//控制单个数码管
void smg_bit(unsigned char pos, unsigned char dat)
{hc573(6,0x01 << pos);hc573(7,dat);delay_smg(TSMG);hc573(6,0x01 << pos);hc573(7,0xff);
}//数码管显示函数
void smg_dispaly()
{if(date == 1) //如果要从DS1302获取信息{read_rtc_ds1302();smg_hou = hou;smg_min = min;smg_s = s;}smg_bit(0, Seg_Table[smg_hou >> 4]); //时smg_bit(1, Seg_Table[smg_hou & 0x0f]);smg_bit(2, 0xbf);smg_bit(3, Seg_Table[smg_min >> 4]); //分smg_bit(4, Seg_Table[smg_min & 0x0f]);smg_bit(5, 0xbf);smg_bit(6, Seg_Table[(smg_s >> 4) & 0x07]); //秒smg_bit(7, Seg_Table[smg_s & 0x0f]);
}//初始化时钟信息
void init_rtc_ds1302()
{unsigned char n;Write_Ds1302_Byte( 0x8e,0x00 );//解除写保护for(n = 0; n < 7; n++){Write_Ds1302_Byte( write_rtc[n],now_rtc[n] );}Write_Ds1302_Byte( 0x8e,0x80 );//使能写保护
}//读出时钟信息
void read_rtc_ds1302()
{hou = Read_Ds1302_Byte ( read_rtc[2] );min = Read_Ds1302_Byte ( read_rtc[1] );s = Read_Ds1302_Byte ( read_rtc[0] );
}//写入时钟信息
void write_rtc_ds1302()
{Write_Ds1302_Byte( 0x8e,0x00 );//解除写保护//写入时钟信息Write_Ds1302_Byte( 0x84,smg_hou );Write_Ds1302_Byte( 0x82,smg_min );Write_Ds1302_Byte( 0x80,smg_s );Write_Ds1302_Byte( 0x8e,0x80 );//使能写保护
}void scan_key()
{if(s4 == 0){delay_key(TKEY);if(s4 == 0){if(start_stop == 1) //如果处于启动{date = 0; //数码管显示暂停更新start_stop = 0;}else{write_rtc_ds1302(); //写入时钟信息start_stop = 1;date = 1; //数码管显示更新}while(s4 == 0){smg_dispaly();}}}if(s5 == 0){delay_key(TKEY);if(s5 == 0){if(start_stop == 0) //如果处于暂停{min = (min/16)*10 + min%16; //BCD码转十进制if(min == 0){min = 59;}elsemin--;min = (min/10)*16 + min%10; //BCD码转十六进制smg_min = min;}while(s5 == 0){smg_dispaly();}}}if(s6 == 0){delay_key(TKEY);if(s6 == 0){if(start_stop == 0) //如果处于暂停{min = (min/16)*10 + min%16; //BCD码转十进制if(min == 59){min = 0;}elsemin++;min = (min/10)*16 + min%10; //BCD码转十六进制smg_min = min;}while(s6 == 0){smg_dispaly();}}}
}void init_sys()
{hc573(5, 0x00); //关闭蜂鸣器与继电器hc573(4, 0xff); //关闭LEDsmg_all(0xff); //关闭数码管init_rtc_ds1302(); //初始化DS1302
}void main()
{init_sys();while(1){smg_dispaly(); //数码管显示函数scan_key(); //键盘扫描函数}
}