51单片机与DS1320动态数码管时钟

51单片机与DS1320动态数码管时钟

1、DS1320操作顺序:先给芯片一个命令,读或者写。然后再进行操作,读命令就从芯片读取数据;写命令就把数据写到芯片。

2、注意事项:最好使用无符号字符型,因为涉及到数据移位操作,带符号数容易出问题!!

#include<reg52.h>
#include<intrins.h>
sbit IO = P3^4;					//数据输入和输出引脚
sbit CE = P3^5;         //复位引脚,高电平启用数据传输
sbit Clock = P3^6;			//时钟输入引脚
/*38译码器的输入端定义*/
sbit AA = P2^0;
sbit BB = P2^1;
sbit CC = P2^2;
/*DS1302中的数据以BCD码存储,每4位2进制表示一位十进制
下面Time数组中的第一个0x00就表示0十秒0秒;0x15表示24小时
形式的下午15点*/
char Time[] = {0x25,0x31,0x11,0x03,0x05,0x01,0x22};//初始化时间秒,分,时,日,月,周,年
char Read_Cmd[7] = {0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; 
char Write_Cmd[7] = {0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
/*数码管0-F段码值*/
unsigned char Seg_Code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
/*向DS1320发送命令,告知对其进行的操作是读还是写,和读写的是时分秒等的哪一位*/
void Ds1302_Cmd(char Cmd)
{
	char n;
	CE = 0;_nop_();
	Clock = 0;_nop_();
	CE = 1;_nop_();
	for(n = 0;n <= 7;n ++)//发送八位命令代码,已保存在上面的数组中
	{
		IO = Cmd & 0x01;
		Cmd = Cmd >> 1;
		Clock = 1;          //上升沿读取数据
		_nop_();
		Clock = 0;          
		_nop_();
	}
}
/*向DS1320中写入8位数据*/
void WriteDatToDs1320(char Dat)
{
	char n;
	for(n = 0;n <= 7;n ++)
	{
		IO = Dat & 0x01;
		Dat = Dat >> 1;
		Clock = 1;          //上升沿读取数据
		_nop_();
		Clock = 0;          //时钟重置为0
		_nop_();
	}
	CE = 0;               //传输数据结束
	_nop_();
}
/*从DS1320接收8位数据*/
char ReadDatFromDs1320()		//数据是从最低位开始接收,因此要进行下列移位操作
{
	char n;
  unsigned char Data_Temp,Data; /*这里注意使用无符号字符类型,否则移位会发生错误!!!
	具体原因可能是C51的编译器关于移位是逻辑右移还是算术右移的问题,我也搞不懂*/
	for(n = 0;n <= 7;n ++)
	{
		Data_Temp = IO;
		Data = ((Data >> 1) | (Data_Temp << 7));
		/*Data右移1位,空出最高位(为0);Data_Temp为接收到的一
		位数据将其左移7位,这样就与Data最高位对齐,在进行“或”运
		算,将数据传给Data,再进行下一次循环,这样先接收的数据就
		逐渐移到了低位,最后接收的数据就到了高位。*/
		Clock= 1;_nop_();
		Clock= 0;					//下降沿放置数据.
		_nop_();
	}
	/*DS1320复位稳定时间*/
	CE = 0;								//关闭数据传输
	_nop_();
	Clock = 1;	
	_nop_();
  IO = 0;	
	_nop_();
	IO = 1;
	_nop_();
	return Data;
}
/*从DS1320中读取全部时间,要进行7次读数据操作,每次读取一个参数*/
void ReadTimeFromDs1320()
{
	unsigned char n;
	for(n = 0;n <= 6;n ++)
	{
		Ds1302_Cmd(Read_Cmd[n]);      //先发送读的命令
		Time[n] = ReadDatFromDs1320();//读取8位数据
	}
}
/*初始化DS1320中的时间为Time数组中的时间,将预先设定的全部时间
写到DS1320中,由于有7个参数,因此要循环7次*/
void Ds1320_Init()
{
	int n;
	Ds1302_Cmd(0x8e);
	WriteDatToDs1320(0x00);//这两句话是关闭写保护
	/*像DS1320中写入:秒,分,时,日,月,周,年七组8位数据*/
	for(n = 0;n <= 6;n ++)
	{
		Ds1302_Cmd(Write_Cmd[n]);WriteDatToDs1320(Time[n]);
		/*例如:当n = 1时,先发送写秒的命令,再发送秒的数据
		命令和数据都提前保存在了数组中,具体命令代码查阅数
		据手册,如下图*/
	}
	Ds1302_Cmd(0x8e);WriteDatToDs1320(0x80);//打开写保护.
}
//扫描数码管显示程序
void Display(int Hour1,int Hour2,int Min1,int Min2,int Sec1,int Sec2)
{
	int i,j;
	for(i=0;i<8;i++)
	{
		switch(i)	 //位选,选择点亮的数码管,
		{
			case(0):AA=0;BB=0;CC=0;P0 = Seg_Code[Hour1];break;//显示第0位			
			case(1):AA=1;BB=0;CC=0;P0 = Seg_Code[Hour2];break;//显示第1位
			case(2):AA=0;BB=1;CC=0;P0 = 0X40;break;//显示第2位
			case(3):AA=1;BB=1;CC=0;P0 = Seg_Code[Min1];break;//显示第3位
			case(4):AA=0;BB=0;CC=1;P0 = Seg_Code[Min2];break;//显示第4位
			case(5):AA=1;BB=0;CC=1;P0 = 0X40;break;//显示第5位
			case(6):AA=0;BB=1;CC=1;P0 = Seg_Code[Sec1];break;//显示第6位
			case(7):AA=1;BB=1;CC=1;P0 = Seg_Code[Sec2];break;//显示第7位	
		}
		j = 50; 
		while(j--);
		P0 = 0X00;
	}
}
/*主程序*/
void main()
{
	int Hour1,Hour2,Min1,Min2,Sec1,Sec2;
	Ds1320_Init();
	while(1)
	{
		ReadTimeFromDs1320();//读取时间并存储到Time数组中
		Hour1 = Time[2]/16;  //小时的十位,Time[2]对16取余,因为是16进制
		Hour2 = Time[2]&0x0f;//保留低四位的小时个位数
		Min1 = Time[1]/16;
		Min2 = Time[1]&0x0f;
		Sec1 = Time[0]/16;
		Sec2 = Time[0]&0x0f;
		Display(Hour1,Hour2,Min1,Min2,Sec1,Sec2);		
	}
}

 

上一篇:LED点阵_单片机_普中


下一篇:基于单片机的八路抢答器的设计