DS1302实时时钟驱动-SPI模拟通讯(下)

写的不知道好不好,有什么不对的地方还请指出,谢了。

1、本节基于DS1302-SPI接口驱动,需要用到上节SPI接口驱动。

2、驱动DS1302,单独读写有14个接口,RTC突发模式读写,RAM突发模式读写。

3、对于DS1302除去RAM,内部存储的是BCD码,不懂的可以自行学下。

4、本驱动里含有接口:数据转换BCD码、BCD码转换数据、关闭写保护、打开写保护、写1字节命令和写数据、写1字节命令和读数据、7个日历独立的读写、7个日历连续读写、RAM连续读写。

5、本DS1302驱动里,每次进行读写的时候均为:关闭写保护——启动SPI——1字节命令——1字节数据——结束SPI——打开写保护。

6、在时钟突发模式下写数据,网上数的是传送8个字节(第8个字节发送0),传送7个字节也可以。(这个问题我也有点搞不懂)

7、RAM突发模式我没有测试,他和时钟突发指令不同,时钟突发模式可以正常读写,RAM我觉的没有问题。
 

#ifndef __DS1302_H__
#define __DS1302_H__

extern unsigned char DS1302[7];//年 星期 月  日 时 分 秒,读取和写入的数据均会保存在数组里面
extern unsigned char DS1302_RAM[31];

void write_year(unsigned char year);//写入年(0 - 99年)
void write_month(unsigned char month);//写入月(1-12)
void write_date(unsigned char date);//写入日(1-31)
void write_day(unsigned char day);//写入星期(1-7)
void write_hour_12(unsigned char hour_12, unsigned char AM_PM);//AP_PM=1表示上午 //写入小时(12小时制)AM=BCD+0x80,PM=BCD+0xa0
void write_hour_24(unsigned char hour_24);//写入小时(24小时制)
void write_min(unsigned char min);//写入分钟(0-59)
void write_sec(unsigned char sec, unsigned char stop_no_stop);//stop_no_stop=1表示停止计时 //写入秒(0-59)若DS1302停止计时=BCD码+0x80,否BCD码+0x00

unsigned int read_year(void);//1、读取年(2000-2099年)
unsigned char read_month(void);//2、读取月(1-12)
unsigned char read_day(void);//3、读取星期(1-7)
unsigned char read_date(void);//4、读取日(1-31)
unsigned char read_hour_12(void);//5、读取小时(12小时制)
unsigned char read_hour_24(void);//5、读取小时(24小时制)
unsigned char read_min(void);//6、读取分钟(0-59)
unsigned char read_sec(void);//7、读取秒(0-59)

//时钟工作在突发模式下24小时制  突发指令0xbe 写数据
void write_RTC(unsigned char year, unsigned char day, unsigned char month, unsigned char date, unsigned char hour_24, unsigned char min, unsigned char sec);
//时钟工作在突发模式下读 0xbf
void read_RTC(void);//读取的数据会存放在DS1302[7]数组里

//RAM工作在突发模式下写 0xfe
void write_RAM(void);//依次写入DS1302_RAM[31]数组元素
//RAM工作在突发模式下读 0xff
void read_RAM(void);//读取的数据存放到DS1302_RAM[31]数组里

#endif // !__DS1302_H__
/* DS1302 RAM=31个8位连续地址存储空间,可以用来存储自定义数据(掉电会丢失)
DS1302控制字:
	7	1关闭写保护/0开启写保护
	6	RAM读写ram数据/CK__读写日历时钟数据
	5	操作单元地址
	4	操作单元地址
	3	操作单元地址
	2	操作单元地址
	1	操作单元地址
	0	1读取/0写入
	上面1字节对应如下结果:
秒:写地址0x80		数据0-59(须要转换BCD码,如BCD码或+0x80将会让DS1302时钟震荡停止工作)
	读地址0x81		BCD码数据最高位为1则表示DS1302时钟震荡停止工作
分:写地址0x82		数据0-59(必须转换BCD码在写入芯片)
	读地址0x83		须将BCD码转换为十进制数
时:写地址0x84		12小时制和24小时制,12小时制则(BCD码+0x80AM上午,+0xa0=PM下午),24小时则不用处理BCD码
	读地址0x85		接收到的BCD码需要判断最高位(1:12小时,0:24小时)若为1则在判断bit5(1:PM,0:AM)
日:写地址0x86		数据1-31(须转换BCD码后在发送出去)
	读地址0x87		须将BCD码转换十进制数
月:写地址0x88		数据1-12(须转换BCD码后在发送出去)
	读地址0x89		须将BCD码转换十进制数
星期:写地址0x8a	1-7(须转换BCD码后在发送出去)
	  读地址0x8b	须将BCD码转换十进制数
年:写地址0x8c		0-99(须转换BCD码后在发送出去)
	读地址0x8d		须将BCD码转换十进制数

写保护:写地址0x8e  0x00(关闭写保护)0x80(开启写保护,拒绝向时钟日历写数据)
		读地址0x8f	同上
*/
#include "SPI.h"							//0写保护 1年  2月  3星期  4日	 5时   6分  7秒
unsigned char code write_data_DS1302[8] = { 0x8e ,0x8c ,0x88 ,0x8a ,0x86 ,0x84 ,0x82 ,0x80 };
unsigned char code read_data_DS1302[8] = { 0x8f ,0x8d ,0x89 ,0x8b ,0x87 ,0x85 ,0x83 ,0x81 };

unsigned char DS1302[7]={0,0,0,0,0,0,0};//秒 分 时 日 月 星期 年
unsigned char DS1302_RAM[31];

//数据转换为BCD码(dat不能大于2位数)
unsigned char data_BCD(unsigned char dat)
{
	unsigned char dat1, dat2;
	dat1 = dat / 10;//结果为十六进制的高位
	dat2 = dat % 10;//结果为十六进制的低位
//	dat2 = dat1 * 16 + dat2;
	dat2 = (dat1 << 4) + dat2;//新算法,速度快(没有加小括号,优先级问题)
	return dat2;
}

//BCD码转换为数据
unsigned char BCD_data(unsigned char dat)
{
	unsigned char dat1, dat2;
	dat1 = dat / 16;//结果为十进制数高位
	dat2 = dat % 16;//结果为十进制数低位
//	dat2 = dat1 * 10 + dat2;
	dat2 = (dat1 << 3)+(dat1 << 1)+ dat2;//新算法,速度快
	return dat2;
}

//关闭写保护
void stop_WP(void)
{
	STATR_SPI();//启动SPI通讯
	write_1_byte_SPI(write_data_DS1302[0]);//准备向0x8e这个地方写数据
	write_1_byte_SPI(0x00);//关闭DS1302的写保护
	STOP_SPI();//结束SPI通讯
}

//打开写保护
void open_WP(void)
{
	STATR_SPI();//启动SPI通讯
	write_1_byte_SPI(write_data_DS1302[0]);//准备向0x8e这个地方写数据
	write_1_byte_SPI(0x80);//打开DS1302的写保护
	STOP_SPI();//结束SPI通讯
}

//写1字节命令,写1字节数据
void write_cmd_dat_DS1302(unsigned char cmd, unsigned char dat)
{
	stop_WP();//关闭写保护
	STATR_SPI();//启动SPI通讯
	write_1_byte_SPI(cmd);//写时钟命令
	write_1_byte_SPI(data_BCD(dat));//写数据
	STOP_SPI();//结束SPI通讯
	open_WP();//开启写保护
}

//写1字节命令,读1字节数据
unsigned char read_cmd_dat_DS1302(unsigned char cmd)
{
	unsigned int read;
	STATR_SPI();//启动SPI通讯
	write_1_byte_SPI(cmd);//写1字节命令
	read = BCD_data(read_1_byte_SPI());//读1字节数据
	STOP_SPI();//结束SPI通讯
	return read;
}

//1、写入年(0-99年)
void write_year(unsigned char year)
{
	write_cmd_dat_DS1302(write_data_DS1302[1],year);
}
//1、读取年(2000-2099年)
unsigned int read_year(void)
{
	unsigned int year;
	year=read_cmd_dat_DS1302(read_data_DS1302[1])+2000;//读取xx年
	return year;	
}

//2、写入月(1-12)
void write_month(unsigned char month)
{
	write_cmd_dat_DS1302(write_data_DS1302[2], month);
}
//2、读取月(1-12)
unsigned char read_month(void)
{
	unsigned char month;
	month = read_cmd_dat_DS1302(read_data_DS1302[2]);//读取月
	return month;
}

//3、写入星期(1-7)
void write_day(unsigned char day)
{
	write_cmd_dat_DS1302(write_data_DS1302[3], day);
}
//3、读取星期(1-7)
unsigned char read_day(void)
{
	unsigned char day;
	day = read_cmd_dat_DS1302(read_data_DS1302[3]);//读取周
	return day;
}

//4、写入日(1-31)
void write_date(unsigned char date)
{
	write_cmd_dat_DS1302(write_data_DS1302[4], date);
}
//4、读取日(1-31)
unsigned char read_date(void)
{
	unsigned char date;
	date = read_cmd_dat_DS1302(read_data_DS1302[4]);//读取日
	return date;
}

//5、写入小时(12小时制)AM=BCD+0x80,PM=BCD+0xa0
void write_hour_12(unsigned char hour_12,unsigned char AM_PM)//AM_PM=1则为上午否则为下午
{
	if (AM_PM == 1)
	{
		hour_12=BCD_data((data_BCD(hour_12) | 0x80));//写入12小时制并且是上午
	}
	else
	{
		hour_12= BCD_data(data_BCD(hour_12) | 0xa0);//写入12小时制并且是下午
	}
	write_cmd_dat_DS1302(write_data_DS1302[5], hour_12);
}
//5、读取小时(12小时制)
unsigned char read_hour_12(void)
{
	unsigned char hour_12;
	hour_12 = read_cmd_dat_DS1302(read_data_DS1302[5]);//读取12小时
	return hour_12;
}

//5、写入小时(24小时制)
void write_hour_24(unsigned char hour_24)
{
	write_cmd_dat_DS1302(write_data_DS1302[5], hour_24);
}
//5、读取小时(24小时制)
unsigned char read_hour_24(void)
{
	unsigned char hour_24;
	hour_24 = read_cmd_dat_DS1302(read_data_DS1302[5]);//读取24小时
	return hour_24;
}

//6、写入分钟(0-59)
void write_min(unsigned char min)
{
	write_cmd_dat_DS1302(write_data_DS1302[6], min);
}
//6、读取分钟(0-59)
unsigned char read_min(void)
{
	unsigned char min;
	min = read_cmd_dat_DS1302(read_data_DS1302[6]);//读取分钟
	return min;
}

//7、写入秒(0-59)若DS1302停止计时=BCD码+0x80,否BCD码&0x7f
void write_sec(unsigned char sec,unsigned char stop_no_stop)//默认情况下下入秒后自动开始计时
{
	if (stop_no_stop == 1)//若为1则表示想要停止计时
	{
		sec=BCD_data(data_BCD(sec) | 0x80);//秒并停止计时
	}
	else//若为0则表示想要开始计时
	{
		sec=BCD_data(data_BCD(sec) & 0x7f);//秒并开始计时
	}
	write_cmd_dat_DS1302(write_data_DS1302[7], sec);
}
//7、读取秒(0-59)
unsigned char read_sec(void)
{
	unsigned char sec;
	sec = read_cmd_dat_DS1302(read_data_DS1302[7]);//读取秒
	return sec;
}

//时钟工作在突发模式下24小时制  突发指令0xbe 写数据
void write_RTC(unsigned char year, unsigned char day, unsigned char month, unsigned char date, unsigned char hour_24, unsigned char min, unsigned char sec)
{
	unsigned char i;
	DS1302[6] = data_BCD(year);//年
	DS1302[5] = data_BCD(day);//周
	DS1302[4] = data_BCD(month);//月
	DS1302[3] = data_BCD(date);//日
	DS1302[2] = data_BCD(hour_24);// & 0x3f;//防止hour_24写入的数据不是24小时格式(好像没有什么用)
	DS1302[1] = data_BCD(min);//分钟
	DS1302[0] = data_BCD(sec) & 0x7f;//DS1302开始计时,防止sec写入的数据动到bit7位时钟暂停启动位
	stop_WP;//关闭写保护
	
	STATR_SPI();//启动SPI通讯
	write_1_byte_SPI(0xbe);//让芯片工作在突发模式下
	for ( i = 0;  i < 7;  i++)//时钟突发模式下应该先传送秒,最后是年
	{
		write_1_byte_SPI(DS1302[i]);
	}
	write_1_byte_SPI(0);//网上说的是时钟突发模式传送8个字节,要像只传送7个字节就可以
	STOP_SPI();//结束SPI通讯
	
	open_WP;//打开写保护
}

//时钟工作在突发模式下读 0xbf
void read_RTC(void)
{
	unsigned char i,x;
	STATR_SPI();//启动SPI通讯
	write_1_byte_SPI(0xbf);//让芯片工作在突发模式下
	for ( i = 0; i < 7; i++)//应该先读秒,最后读年
	{
		DS1302[i]=BCD_data(read_1_byte_SPI());// 读取一个字节(BCD)并转换为数据,并存放到数组里
	}
	STOP_SPI();//结束SPI通讯
}

//RAM工作在突发模式下写 0xfe
void write_RAM(void)
{
	unsigned char i;
	stop_WP;//关闭写保护
	
	STATR_SPI();//启动SPI通讯
	write_1_byte_SPI(0xfe);//让芯片工作在突发模式下
	for ( i = 0; i < 31; i++)
	{
		write_1_byte_SPI(DS1302_RAM[i]);
	}
	STOP_SPI();//结束SPI通讯
	
	open_WP;//打开写保护
}

//RAM工作在突发模式下读 0xff
void read_RAM(void)
{
	unsigned char i;
	STATR_SPI();//启动SPI通讯
	write_1_byte_SPI(0xff);//让芯片工作在突发模式下
	for ( i = 0; i < 31; i++)
	{
		DS1302_RAM[i]=read_1_byte_SPI();
	}
	STOP_SPI();//结束SPI通讯
	
}

猜你喜欢

转载自blog.csdn.net/qq_44829055/article/details/107440212