蓝桥杯单片机开发及应用-基础模块15-时钟模块DS1302

目录

一、相关知识

        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();       // 显示
	}
}

四、运行图片

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Micropython中的`onewire`模块提供了一种在Micropython设备上使用1-Wire协议的方法。 1-Wire是一种串行通信协议,它允许多个设备通过单根线连接到同一个总线上。Micropython中的`onewire`模块提供了访问这些设备的方法。 在使用`onewire`模块之前,需要先导入它并初始化一个1-Wire总线对象。例如,如果你使用的是ESP8266芯片,你可以将一个GPIO口配置为1-Wire总线的引脚,并使用以下代码初始化1-Wire总线对象: ```python import machine import onewire # 配置GPIO2为1-Wire总线引脚 ow = onewire.OneWire(machine.Pin(2)) # 通过ow对象访问1-Wire设备 ``` 在初始化了1-Wire总线对象后,你可以通过`ow`对象访问连接到该总线上的1-Wire设备。`ow`对象提供了下列方法: - `reset()`:重置总线,并检查是否有设备存在。 - `readbyte()`:从总线上读取一个字节。 - `writebyte(val)`:向总线上写入一个字节。 - `readbytes(n)`:从总线上读取n个字节。 - `writebytes(buf)`:向总线上写入一个字节数组。 例如,假设你将一个DS18B20温度传感器连接到1-Wire总线上,并将其地址设置为`28:FF:6F:AC:4A:16:03:EE`。你可以使用以下代码读取该传感器的温度: ```python import machine import onewire import ds18x20 # 配置GPIO2为1-Wire总线引脚 ow = onewire.OneWire(machine.Pin(2)) # 创建一个DS18X20对象,用于访问DS18B20传感器 ds = ds18x20.DS18X20(ow) # 重置总线并搜索所有设备 roms = ds.scan() # 选择你要读取的设备 ds.select_rom(roms[0]) # 向设备发送温度转换命令 ds.convert_temp() # 等待转换完成 machine.delay(750) # 读取设备的温度 temp = ds.read_temp(roms[0]) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汽小迪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值