AutoLeaders控制组-51单片机数字时钟

一.DS1302

二.中断

三.矩阵键盘

四.数字时钟

.DS1302

DS1302是低功耗实时时钟芯片,它可以对年月周时分秒进行计时,且具有闰年补偿等多种功能

1.初始化将CE置于0,SCLK置0

2.数据写入:先写地址后写数据

地址有秒,分,时,日,月,星期,年,写保护等,如下图第二列就是写入时的地址,通过地址将数据写入DS1302,就完成了时间的初始化

开始后将CE置1;

确定要写入的地址和数据data(8位的二进制数);

通过字节运算取出地址和data的每一位(第0位到第七位)赋值给I/O;

将SLCK置1;

将SLCK置0;

这样就完成一个位的写入了。通过for循环将地址和数据共十六位写入了DS1302.

同样读出数据也是先输入地址(第一列,和写入的地址不同),再读出数据。

注意,写入和读出都是按照BCD码

举个例子,想要将23写入秒,首先将22的个位和十位拆开分别是2和3,然后十位的2用四位二进制表示0010,个位2用四位二进制表示0011,再拼起来就是0010 0011,也就是说在BCD码中0010 0011表示23这个数据

二.中断

中断系统包括:

5个中断源(外部中断0,1;定时器中断0,1;串行通信口中断)

中断源寄存器,分定时器/计数器控制寄存器TCON和串行通信口控制寄存器SCON

中断允许寄存器IE

中断优先级控制寄存器IP

中断系统结构如下:

定时器0的使用

代码如下:

/**
  * @brief  定时器0初始化,1毫秒@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
	PT0=0;
}

/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
		
	}
}
*/

单片机内部定时器的结构:

三.矩阵键盘

矩阵键盘判断哪个按键被按下是通过行列式扫描

由P1控制,P0~P3控制行,P4~P7控制列,下图就是每个键盘对应的行和列

下列是获取键码值函数:

#include <REGX52.H>
#include "Delay.h"

/**
  * @brief  矩阵键盘读取按键键码
  * @param  无
  * @retval KeyNumber 按下按键的键码值
			如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0
  */
unsigned char MatrixKey()
{
	unsigned char KeyNumber=0;
	
	P1=0xFF;
	P1_3=0;
	if(P1_7==0){Delay(20);while(P1_7==0){TimeShow();}Delay(20);KeyNumber=1;}
	if(P1_6==0){Delay(20);while(P1_6==0){TimeShow();}Delay(20);KeyNumber=5;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
	
	P1=0xFF;
	P1_2=0;
	if(P1_7==0){Delay(20);while(P1_7==0){TimeShow();}Delay(20);KeyNumber=2;}
	if(P1_6==0){Delay(20);while(P1_6==0){TimeShow();}Delay(20);KeyNumber=6;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
	
	P1=0xFF;
	P1_1=0;
	if(P1_7==0){Delay(20);while(P1_7==0){TimeShow();}Delay(20);KeyNumber=3;}
	if(P1_6==0){Delay(20);while(P1_6==0){TimeShow();}Delay(20);KeyNumber=7;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
	
	P1=0xFF;
	P1_0=0;
	if(P1_7==0){Delay(20);while(P1_7==0){TimeShow();}Delay(20);KeyNumber=4;}
	if(P1_6==0){Delay(20);while(P1_6==0){TimeShow();}Delay(20);KeyNumber=8;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}
	
	return KeyNumber;
}

四.数字时钟

利用数码管,DS1302,中断,矩阵键盘设置的数字时钟

解决按键按下未松开时数码管卡住:将时间显示函数TimeShow()插入获取键码函数MatrixKey()的死循环中。

数字时钟代码如下:

#include <REGX52.H>
#include "DS1302.h"
#include "MatrixKey.h"
#include "Timer0.h"
#include "Delay.h"


unsigned char KeyNumber,TimeSetFlashFlag=0;//键码值和时钟闪烁标志 
unsigned char b=1,c,d=0;

//nixie()第一个参数是数码管位置loc,第二个参数是数码管某位置显示的数字/不显示 
unsigned char table[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};             //0 1 2 3 4 5 6 7 8 9 空 
void nixie(unsigned char loc,num)
{
switch(loc)
{
case 1:P2_4=1;P2_3=1;P2_2=1;break;
case 2:P2_4=1;P2_3=1;P2_2=0;break;
case 3:P2_4=1;P2_3=0;P2_2=1;break;
case 4:P2_4=1;P2_3=0;P2_2=0;break;
case 5:P2_4=0;P2_3=1;P2_2=1;break;
case 6:P2_4=0;P2_3=1;P2_2=0;break;
case 7:P2_4=0;P2_3=0;P2_2=1;break;
case 8:P2_4=0;P2_3=0;P2_2=0;break;
}
P0 =table[num];
}

//时间显示函数 
void TimeShow(void)
{
	
	
	//数码管第一,二 位显示的设置:当处于时间设置模式 且按下s1或s5时,闪烁数字 
	//否则固定数字 并实时更新时间 
	if((KeyNumber==1||KeyNumber==5)&&TimeSetFlashFlag==1)
	{Delay(1);nixie(1,10);Delay(1);nixie(2,10);}
	else{
	nixie(1,DS1302_Time[3]/10);Delay(2);
	nixie(2,DS1302_Time[3]%10);Delay(2);}
	
	//数码管第三位在计时模式时闪烁-,在设置模式时固定- 
	if(b==1&&TimeSetFlashFlag==1)
	{P2_4=1;P2_3=0;P2_2=1;P0=0x40;Delay(2);}	
	if(b==0){P2_4=1;P2_3=0;P2_2=1;P0=0x40;Delay(2);}
	
	//数码管第四,五 位显示的设置:当处于时间设置模式 且按下s2或s6时,闪烁数字
	//否则固定数字 并实时更新时间
	if((KeyNumber==2||KeyNumber==6)&&TimeSetFlashFlag==1)
	{Delay(1);nixie(4,10);Delay(1);nixie(5,10);}
	else{
	nixie(4,DS1302_Time[4]/10);Delay(2);
	nixie(5,DS1302_Time[4]%10);Delay(2);}
	
	//数码管第五位在计时模式时闪烁-,在设置模式时固定- 
	if(b==1&&TimeSetFlashFlag==1)
	{P2_4=0;P2_3=1;P2_2=0;P0=0x40;Delay(2);}
	if(b==0){P2_4=0;P2_3=1;P2_2=0;P0=0x40;Delay(2);}
	
	//数码管第七,八 位显示的设置:当处于时间设置模式 且按下s3或s7时,闪烁数字
	//否则固定数字 并实时更新时间
	if((KeyNumber==3||KeyNumber==7)&&TimeSetFlashFlag==1)
	{Delay(1);nixie(7,10);Delay(1);nixie(8,10);}
	else{
	nixie(7,DS1302_Time[5]/10);Delay(2);
	nixie(8,DS1302_Time[5]%10);Delay(2);}	
	//DS1302_Time[5]/10用于表示秒的十位;DS1302_Time[5]%10用于表示秒的个位;
	//DS1302_Time[4]/10用于表示分的十位;DS1302_Time[4]%10用于表示分的个位;
	//DS1302_Time[3]/10用于表示时的十位;DS1302_Time[3]%10用于表示时的个位;
	

		
	}


void main()
{
	//初始化 
	DS1302_Init();
	Timer0Init();
	DS1302_SetTime();		//设置显示的起始时间10:00:00 
	
	while(1)
	{
	KeyNumber=MatrixKey();	//通过s1~s8按键被按下的情况更新键码值 
	if(KeyNumber==4)
	b=0;					//b=0是设置模式,按s4进入设置模式 
		
	if(KeyNumber==8)
	{
	b=1;
	DS1302_SetTime();
	}
	
	//b=1是显示模式,按s8,将设置模式调好的时间通过 DS1302_SetTime();写入DS1302,再进入显示模式 
	
	//显示模式 
	if(b==1)
	{
	DS1302_ReadTime();	
	TimeShow();	
	}
	
	//设置模式 
	if(b==0)
	{
		TimeShow();
		
		if(KeyNumber==1)
		{
		  c=DS1302_Time[3];
		  c++;
		  DS1302_Time[3]=c;	
		}
		
		if(KeyNumber==5)
		{
		  c=DS1302_Time[3];
		  c--;
		  DS1302_Time[3]=c;	
		}
		
		if(KeyNumber==2)
		{
		  c=DS1302_Time[4];
		  c++;
		  DS1302_Time[4]=c;	
		}
		
		if(KeyNumber==6)
		{
		  c=DS1302_Time[4];
		  c--;
		  DS1302_Time[4]=c;	
		}
		if(KeyNumber==3)
		{
		  c=DS1302_Time[5];
		  c++;
		  DS1302_Time[5]=c;
		}
		
		if(KeyNumber==7)
		{
		  c=DS1302_Time[5];
		  c--;
		  DS1302_Time[5]=c;	
		}
		
	}
		//越界判断 
		if(DS1302_Time[3]>23){DS1302_Time[3]=0;}
		if(DS1302_Time[4]>59){DS1302_Time[4]=0;}
		if(DS1302_Time[5]>59){DS1302_Time[5]=0;}
		if(DS1302_Time[3]<0){DS1302_Time[3]=23;}
		if(DS1302_Time[4]<0){DS1302_Time[4]=59;}
		if(DS1302_Time[5]<0){DS1302_Time[5]=59;}
	}

}

//中断模式 
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count1;
	TL0 = 0x18;		
	TH0 = 0xFC;		
	T0Count1++;
	if(T0Count1>=450)
	{
		T0Count1=0;
		TimeSetFlashFlag=!TimeSetFlashFlag;
	}
	
}
  • 11
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值