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

 

#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;
sbit K1 = P2^3;
sbit K2 = P2^4;
sbit K3 = P2^5;
sbit K4 = P2^6;
void delay(int a,int b)
{
	int i,j;
	for(i = 0;i <= a;i ++)
	{
		for(j = 0;j <= b;j ++)
		{}
	}
}
/*DS1302中的数据以BCD码存储,每4位2进制表示一位十进制
下面Time数组中的第一个0x00就表示0十秒0秒;0x15表示24小时
形式的下午15点*/
unsigned 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;
	unsigned char temp1,temp2;
	Ds1320_Init();
	K1 = 1;K2 = 1;K3 = 1;K4 = 1;
	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;
		/*按键调时间程序,K1调整小时的个位,K2调整小时的10位。以此类推/
		if(K1 == 0)
		{
			delay(300,10);
			if(K1 == 0)
			{
				Time[2] ++;
				if((Time[2]&0x0f)==10)
				{
					Time[2] = (Time[2]&0xf0);
				}
				Ds1320_Init();
			}
			delay(30,10);
		}
		if(K2 == 0)
		{
			temp1 = Time[2];
			delay(300,10);
			if(K2 == 0)
			{
				Time[2] = Time[2] >> 4;
				Time[2] ++;
				if(Time[2] == 3)
				{
					Time[2] = 0x0f&temp1;
					Ds1320_Init();
				}
				else
				{
					Time[2] = Time[2] << 4;
					temp1 = temp1&0x0f;
					Time[2] = (Time[2]|temp1);
					Ds1320_Init();
				}
			}
			delay(30,10);
		}		
		
		if(K3 == 0)
		{
			delay(300,10);
			if(K3 == 0)
			{
				Time[1] ++;
				if((Time[1]&0x0f)==10)
				{
					Time[1] = (Time[1]&0xf0);
				}
				Ds1320_Init();
			}
			delay(30,10);
		}
		if(K4 == 0)
		{
			temp1 = Time[1];
			delay(300,10);   
			if(K4 == 0)
			{
				Time[1] = Time[1] >> 4;
				Time[1] ++;
				if(Time[1] == 6)
				{
					Time[1] = 0x0f&temp1;
					Ds1320_Init();
				}
				else
				{
					Time[1] = Time[1] << 4;
					temp1 = temp1&0x0f;
					Time[1] = (Time[1]|temp1);
					Ds1320_Init();
				}
			}
			delay(30,10);
		}
		Display(Hour1,Hour2,Min1,Min2,Sec1,Sec2);		
	}
}

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

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

  • 1
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值