目录
一、相关知识
1.关于DS1302(这里只是简述,更详细专业的介绍请看芯片手册)
2.DS1302相关的寄存器
①读写寄存器(数据格式:BCD码,相当于用十六进制表示十进制)
②读写寄存器的控制字格式
3.SPI接口时序
4.DS1302的日历时钟数据读取基本步骤
①定义三个数组,分别为读寄存器地址,写寄存器地址,日历时钟数据地址
②编写日历时钟配置函数
③编写日历时钟数据读取函数
5.注意事项
二、所要实现的功能
三、代码实现
1.参数定义
2.138译码器通道选择函数
3.初始化系统
4.延时函数
5.单个数码管显示函数
6.数码管动态显示
7.DS1302配置
8.DS1302读时间
9.完整代码
四、运行图片
关于共阳数码管等部分已在之前的文章中介绍过了,此处不再介绍了。
需要用到的芯片手册和驱动文件都已上传资源可以自行免费下载使用!
【免费】蓝桥杯最新驱动文件包括onewire、iic、ds1302资源-CSDN文库
【免费】蓝桥杯单片机开发及应用的中英两版芯片手册资源-CSDN文库
一、相关知识
1.关于DS1302(这里只是简述,更详细专业的介绍请看芯片手册)
DS1302是内含有一个实时时钟/日历和31字节静态RAM,通过简单的串行接口与单片机通信的涓流充电时钟芯片。实时时钟/日历电路提供秒、分、时、日、月、周、年的信息,每月的天数和闰年的天数可自动调整。
简单来说,DS1302可以理解为一个电子表,里面带有一个31字节的RAM内存。DS1302中的两块存储器:日历时钟寄存器用于记录实时时间;静态RAM存储器用于记录其他数据。我们重点需要关注日历时钟寄存器。
2.DS1302相关的寄存器
①读写寄存器(数据格式:BCD码,相当于用十六进制表示十进制)
秒的读写寄存器(80H和81H)的位7(CH)为时钟暂停标志位。CH=1时,时钟振荡停止;CH=0时,时钟振荡开始。
时的读写寄存器(84H和85H)的bit7=1时,12小时制;bit7=0时,24小时制。bit5=1时,下午模式;bit5=0时,上午模式。
控制位的读写寄存器(8EH和8FH)的位7(WP)为读写保护位。WP=1时,禁止进行写操作;WP=0时,可以对寄存器进行写操作。
BCD码,是用4位二进制数来表示1位十进制数中的0~9这10个数码,是一种二进制的数字编码形式,用二进制编码的十进制代码。BCD码这种编码形式利用了四个位元来储存一个十进制的数码,使二进制和十进制之间的转换得以快捷的进行。
8421BCD码是最基本和最常用的BCD码,它和四位自然二进制码相似,各位的权值为8、4、2、1,故称为有权BCD码。和四位自然二进制码不同的是,它只选用了四位二进制码中前10组代码,即用0000~1001分别代表它所对应的十进制数,余下的六组代码不用。所以BCD码可以看作是二进制表示十进制。但由于它还是二进制码表示的,所以在取商和取余的时候除以的是16,而不是10。
②读写寄存器的控制字格式
BIT7:必须为1,若为0,则不能把数据写入DS1302中。(这就是为什么读写寄存器都是8~H,8保证了BIT7=1)
BIT6:0表示存取日历时钟数据,1表示存取RAM数据。
BIT5~BIT1:表示操作单元地址。
BIT0:0表示写操作,1表示读操作。(这就是为什么读寄存器的地址都比写寄存器多了1)
3.SPI接口时序
也就是上升沿写入数据,下降沿读出数据。这里只是作为了解,可以更好地理解底层驱动代码。
4.DS1302的日历时钟数据读取基本步骤
①定义三个数组,分别为读寄存器地址,写寄存器地址,日历时钟数据地址
// 写、读寄存器地址
unsigned char code Write_DS1302_ADDR[7] = {0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
unsigned char code Read_DS1302_ADDR[7] = {0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
// 与读写寄存器地址对应,从左到右顺序依次是:秒、分、时、日、月、周、年
unsigned char TIME[7] = {0x24,0x25,0x16,0x11,0x12,0x01,0x23};
②编写日历时钟配置函数
// DS1302配置
void DS1302_Config(void)
{
unsigned char i = 0;
Write_Ds1302_Byte( 0x8e , 0x00 ); // 控制寄存器允许写操作
for( i=0 ; i<7 ; i++ )
{
Write_Ds1302_Byte( Write_DS1302_ADDR[i] , TIME[i] );
}
Write_Ds1302_Byte( 0x8e , 0x80 ); // 写完之后,控制寄存器禁止写操作
}
// 在这里我们并没有把0x8E和0x8F加到数组中,因为这两个地址不太常用。而且为了与秒分时日月周年7个数据对应,读写寄存器的数组也是7个数据
③编写日历时钟数据读取函数
// 读取时间
void Read_DS1302(void)
{
unsigned char i = 0;
for( i=0 ; i<7 ; i++ )
{
TIME[i] = Read_Ds1302_Byte( Read_DS1302_ADDR[i] );
}
}
5.注意事项
①使用DS1302需要用到ds1302的库,比赛时会提供ds1302.c和ds1302.h。
②非常重要的一点!!!就是组委会可能会在提供的文件中动一些手脚,以增加难度,这时读取的时间可能会出现异常情况。那么我们在使用之前就要认真分辨,哪里动了手脚,我们再改回来(onewire、iic、ds1302文件都已上传资源,需要的可自行下载);
二、所要实现的功能
使用DS1302读取时间。具体操作为在数码管上显示年月日或者时分秒。(比赛的时候不会这么简单,可能会让我们在程序运行的时候,通过按键调整时分秒的数值,并且在改变的时候数值要进行亮灭闪烁,这就需要结合标志位和定时器来进行操作)
三、代码实现
1.参数定义
#include <STC15F2K60S2.H>
#include "Delay_ms.h"
#include "ds1302.h"
// 不加code会影响单片机运行速度,会改变RAM,加了code之后内容就固定不变了,不会占用RAM
unsigned char code SMG_Duanma[19] =
{
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f,0x00
}; // 0~F - . 全部
// 带点显示数
unsigned char code SMG_Dian[10] =
{
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10
}; // 0.~9.
// 写、读寄存器地址
unsigned char code Write_DS1302_ADDR[7] = {0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
unsigned char code Read_DS1302_ADDR[7] = {0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
// 与读写寄存器地址对应,从左到右顺序依次是:秒、分、时、日、月、周、年
unsigned char TIME[7] = {0x24,0x25,0x16,0x11,0x12,0x01,0x23};
2.138译码器通道选择函数
// 通道选择函数
void HC138_Init( unsigned char channel )
{
switch( channel )
{
case 0:
P2 = ( P2 & 0x1f ) | 0x00; // 0
break;
case 4:
P2 = ( P2 & 0x1f ) | 0x80; // Y4C
break;
case 5:
P2 = ( P2 & 0x1f ) | 0xa0; // Y5C
break;
case 6:
P2 = ( P2 & 0x1f ) | 0xc0; // Y6C
break;
case 7:
P2 = ( P2 & 0x1f ) | 0xe0; // Y7C
break;
}
}
3.初始化系统
// 初始化系统
void System_Init(void)
{
// 关闭LED灯
HC138_Init( 4 );
P0 = 0xff;
// 关闭蜂鸣器和继电器
HC138_Init( 5 );
P0 = 0xaf; // 1010 1111
// 关闭通道选择
HC138_Init( 0 );
}
4.延时函数
void Delay_tms( unsigned int t )
{
int i;
while( t-- )
{
for( i=115 ; i>0 ; i-- )
{}
}
}
5.单个数码管显示函数
// 数码管显示
void SMG_Light( unsigned char pos , unsigned char dat )
{
HC138_Init( 6 );
P0 = 0x01 << pos;
HC138_Init( 7 );
P0 = dat;
}
6.数码管动态显示
年月日
//void SMG_Show(void)
//{
// SMG_Light( 0 , SMG_Duanma[ TIME[6] / 16 ] );
// Delay_tms( 5 );
// SMG_Light( 1 , SMG_Duanma[ TIME[6] % 16 ] );
// Delay_tms( 5 );
// SMG_Light( 2 , SMG_Duanma[ 16 ] );
// Delay_tms( 5 );
// SMG_Light( 3 , SMG_Duanma[ TIME[4] / 16 ] );
// Delay_tms( 5 );
// SMG_Light( 4 , SMG_Duanma[ TIME[4] % 16 ] );
// Delay_tms( 5 );
// SMG_Light( 5 , SMG_Duanma[ 16 ] );
// Delay_tms( 5 );
// SMG_Light( 6 , SMG_Duanma[ TIME[3] / 16 ] );
// Delay_tms( 5 );
// SMG_Light( 7 , SMG_Duanma[ TIME[3] % 16 ] );
// Delay_tms( 5 );
//}
// 时分秒
void SMG_Show(void)
{
SMG_Light( 0 , SMG_Duanma[ TIME[2] / 16 ] );
Delay_tms( 5 );
SMG_Light( 1 , SMG_Duanma[ TIME[2] % 16 ] );
Delay_tms( 5 );
SMG_Light( 2 , SMG_Duanma[ 16 ] );
Delay_tms( 5 );
SMG_Light( 3 , SMG_Duanma[ TIME[1] / 16 ] );
Delay_tms( 5 );
SMG_Light( 4 , SMG_Duanma[ TIME[1] % 16 ] );
Delay_tms( 5 );
SMG_Light( 5 , SMG_Duanma[ 16 ] );
Delay_tms( 5 );
SMG_Light( 6 , SMG_Duanma[ TIME[0] / 16 ] );
Delay_tms( 5 );
SMG_Light( 7 , SMG_Duanma[ TIME[0] % 16 ] );
Delay_tms( 5 );
}
7.DS1302配置
// DS1302配置
void DS1302_Config(void)
{
unsigned char i = 0;
Write_Ds1302_Byte( 0x8e , 0x00 ); // 控制寄存器允许写操作
for( i=0 ; i<7 ; i++ )
{
Write_Ds1302_Byte( Write_DS1302_ADDR[i] , TIME[i] );
}
Write_Ds1302_Byte( 0x8e , 0x80 ); // 写完之后,控制寄存器禁止写操作
}
8.DS1302读时间
// 读取时间
void Read_DS1302(void)
{
unsigned char i = 0;
for( i=0 ; i<7 ; i++ )
{
TIME[i] = Read_Ds1302_Byte( Read_DS1302_ADDR[i] );
}
}
9.完整代码
#include <STC15F2K60S2.H>
#include "Delay_ms.h"
#include "ds1302.h"
// 不加code会影响单片机运行速度,会改变RAM,加了code之后内容就固定不变了,不会占用RAM
unsigned char code SMG_Duanma[19] =
{
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f,0x00
}; // 0~F - . 全部
// 带点显示数
unsigned char code SMG_Dian[10] =
{
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10
}; // 0.~9.
// 写、读寄存器地址
unsigned char code Write_DS1302_ADDR[7] = {0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
unsigned char code Read_DS1302_ADDR[7] = {0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
// 与读写寄存器地址对应,从左到右顺序依次是:秒、分、时、日、月、周、年
unsigned char TIME[7] = {0x24,0x25,0x16,0x11,0x12,0x01,0x23};
// 通道选择函数
void HC138_Init( unsigned char channel )
{
switch( channel )
{
case 0:
P2 = ( P2 & 0x1f ) | 0x00; // 0
break;
case 4:
P2 = ( P2 & 0x1f ) | 0x80; // Y4C
break;
case 5:
P2 = ( P2 & 0x1f ) | 0xa0; // Y5C
break;
case 6:
P2 = ( P2 & 0x1f ) | 0xc0; // Y6C
break;
case 7:
P2 = ( P2 & 0x1f ) | 0xe0; // Y7C
break;
}
}
// 初始化系统
void System_Init(void)
{
// 关闭LED灯
HC138_Init( 4 );
P0 = 0xff;
// 关闭蜂鸣器和继电器
HC138_Init( 5 );
P0 = 0xaf; // 1010 1111
// 关闭通道选择
HC138_Init( 0 );
}
// 数码管显示
void SMG_Light( unsigned char pos , unsigned char dat )
{
HC138_Init( 6 );
P0 = 0x01 << pos;
HC138_Init( 7 );
P0 = dat;
}
年月日
//void SMG_Show(void)
//{
// SMG_Light( 0 , SMG_Duanma[ TIME[6] / 16 ] );
// Delay_tms( 5 );
// SMG_Light( 1 , SMG_Duanma[ TIME[6] % 16 ] );
// Delay_tms( 5 );
// SMG_Light( 2 , SMG_Duanma[ 16 ] );
// Delay_tms( 5 );
// SMG_Light( 3 , SMG_Duanma[ TIME[4] / 16 ] );
// Delay_tms( 5 );
// SMG_Light( 4 , SMG_Duanma[ TIME[4] % 16 ] );
// Delay_tms( 5 );
// SMG_Light( 5 , SMG_Duanma[ 16 ] );
// Delay_tms( 5 );
// SMG_Light( 6 , SMG_Duanma[ TIME[3] / 16 ] );
// Delay_tms( 5 );
// SMG_Light( 7 , SMG_Duanma[ TIME[3] % 16 ] );
// Delay_tms( 5 );
//}
// 时分秒
void SMG_Show(void)
{
SMG_Light( 0 , SMG_Duanma[ TIME[2] / 16 ] );
Delay_tms( 5 );
SMG_Light( 1 , SMG_Duanma[ TIME[2] % 16 ] );
Delay_tms( 5 );
SMG_Light( 2 , SMG_Duanma[ 16 ] );
Delay_tms( 5 );
SMG_Light( 3 , SMG_Duanma[ TIME[1] / 16 ] );
Delay_tms( 5 );
SMG_Light( 4 , SMG_Duanma[ TIME[1] % 16 ] );
Delay_tms( 5 );
SMG_Light( 5 , SMG_Duanma[ 16 ] );
Delay_tms( 5 );
SMG_Light( 6 , SMG_Duanma[ TIME[0] / 16 ] );
Delay_tms( 5 );
SMG_Light( 7 , SMG_Duanma[ TIME[0] % 16 ] );
Delay_tms( 5 );
}
// DS1302配置
void DS1302_Config(void)
{
unsigned char i = 0;
Write_Ds1302_Byte( 0x8e , 0x00 ); // 控制寄存器允许写操作
for( i=0 ; i<7 ; i++ )
{
Write_Ds1302_Byte( Write_DS1302_ADDR[i] , TIME[i] );
}
Write_Ds1302_Byte( 0x8e , 0x80 ); // 写完之后,控制寄存器禁止写操作
}
// 读取时间
void Read_DS1302(void)
{
unsigned char i = 0;
for( i=0 ; i<7 ; i++ )
{
TIME[i] = Read_Ds1302_Byte( Read_DS1302_ADDR[i] );
}
}
int main(void)
{
System_Init(); // 系统初始化
DS1302_Config(); // DS1302配置
while(1)
{
Read_DS1302(); // 读取
SMG_Show(); // 显示
}
}
四、运行图片