51单片机 时钟显示、设置闹钟功能的实现 (附详细算法思路、proteus电路图)

功能要求:

1.利用定时器中断实现时钟功能,格式:时-分-秒。
2.实现时钟显示和闹钟设置两个功能的切换。
3.闹钟设置,且限定字符格式(如时针不得超过24等)。
4.时钟到达预设值时,闹铃正常响起,且用按键关闭。

思维导图:

1.主函数
在这里插入图片描述
2.时钟显示
在这里插入图片描述
3.闹钟设置

在这里插入图片描述
4.闹铃
在这里插入图片描述
**

Proteus电路图

晶振频率12mhz
在这里插入图片描述

代码

**
头文件

#ifndef colock_h
#define colock_h

#include <reg52.h>

#define LedD P0                                              //段选
#define LedC P2                                              //位选

unsigned char s=57,m=59,h=23;									//时、分、秒初始值

unsigned char	j=0;														//闪烁位的延时参数

unsigned char flag=0;												//闪烁位
	
unsigned char	key1=0,key2=0,key3=0;					//三个中断按键
	
unsigned char	f1=0,f2=1,f3=0;								//f1:时钟到达闹钟预设值 标志位
																						//f2:闹钟关闭按键 标志位
																						//f3:闹钟状态 标志位

unsigned int i=0;														//计数器延时参数

sbit cl=P3^0; 							//闹钟功能切换提示
sbit bz=P1^0;								//闹铃输出口
																																
																	//共阴极数码管
																																	
unsigned char num1[] = {1,0,10,0,0,10,0,0};         	 						/* 时钟待显示字符对应key值*/  

unsigned char num2[] = {0,0,10,0,0,10,1,0};												/* 闹钟待显示字符对应key值*/ 

code unsigned char wx[] = {0xfe,0xfd,0xfb,0xf7,            			/* 位选编码 字符对应value值	*/           
                               0xef,0xdf,0xbf,0x7f};   

code unsigned char dx[] = {0x3f,0x06,0x5b,0x4f,0x66,      			 /* 0-9数字,-的编码 */
                               0x6d,0x7d,0x07,0x7f,0x6f,0x40};

void init();																				//初始化
void delay(unsigned char);													//延时
void display();																			//时针显示
void count();																				//时针计数(计时)
void transform();																		//将时分秒的个位十位分离
void twinkle(unsigned char);												//闹钟显示界面 控制某一位闪烁 
void int0();																				//外部中断0
void int1();																				//外部中断1
void it0();																					//定时器0
void compare();															 				//闹钟预设值与时钟值比较			
void ring();																				//闹铃
												
#endif

c文件

#include "colock.h"

void main(void)
{
	init();
	while(1)
	{
		compare();
		if(key1==1)
		{
			cl=1;
			twinkle(flag);							//已切换到闹钟功能 提示
		}
		else													//切换到时钟显示
		{
			cl=0;
			display();
		}
	}
}



void init(void)                /*初始化*/
{
	LedD = 0x00;                    /* 段码置0 */
	LedC = 0xff;                    /* 位选置1 */ 
	
	EA=1;													//总中断
	ET1=1;										//开启定时器中断1
	ET0=1;										//定时器0

	TR1=1;										//开启定时器1
	TMOD=0x20;								//定时器1,工作方式2,八位自动重装载
	TH1=156;
	TL1=156;									//0.1ms

	IT0=1;										//下降沿有效
	IT1=1;
	EX0=1;										//外部中断0、1
	EX1=1;
	
	ET0=1;												//开启定时器中断
	TMOD=0x06;										//八位自动重装载计数器0 扩展为中断
	TR0=1;												//开启定时器0
	TH0=0xff;
	TL0=0xff;
	
	bz=0;											//闹铃关闭
}

void display()												//字符显示
{
	unsigned char i;
	for(i=0; i<8; i++)
	{
		LedC = wx[i];            			 /* 选通某一位,例如i=0,即选通第0位 */
		LedD = dx[num1[i]];            /* 通过码表数组将第i位要显示的数字转换成数码管能识别的编码 */
		delay(20);                     /* 微量延时,用于显示保持 */
		LedD=0x00;										 //消隐
	}
}

void delay(unsigned char t)							//延时
{
	unsigned char i,j;
	for(i=0; i<20; i++)
		for(j=0; j<t; j++);

}

void transform()														//数位转换
{
	h%=24;
	num1[0]=h/10;				//十位
	num1[1]=h%10;				//个位
	num1[3]=m/10;
	num1[4]=m%10;
	num1[6]=s/10;
	num1[7]=s%10;
}

void count() interrupt 3								//计时
{
	i++;
	if(i==100)
	{
		s++;
		if(s==60)
		{
			s=0;
			m++;
		}
		if(m==60)
		{
			m=0;
			h++;
		}
		transform();
		i%=100;
		if(f1&&f2)														//启动闹铃
			ring();
		else
			bz=0;
	}
}

									//闹钟界面相关程序

void twinkle(unsigned char t)				//某一位闪烁
{	
	unsigned char i;
	j%=50;
	for(i=0;i<8;i++)
	{
		if((i==t)&&(j<25))
			continue;
		else
		{
			delay(20);
			P2=wx[i];
			P0=dx[num2[i]];
		}
	}
		j++;
}

void int0() interrupt 0							//进入闹钟界面
{
	key1++;
	key1%=2;
}

void int1() interrupt 2							//移动调整位(闪烁位)   关闭闹铃
{
	flag++;
	if(flag==2||flag==5)							//跳过分隔符
		flag++;
	flag%=8;
	
	if(f1)														//关闭闹铃标志符f2的赋值
	{
		f2=0;
		f1=0;
	}
	else
		f2=1;
}

void it0() interrupt 1							//闪烁位数字加一
{
	if(flag==0&&num2[flag]==2)				//限制 时针高位不得破2
	{
		num2[flag]=0;
		return;
	}
	else if(flag==1&&num2[flag]==3&&num2[0]==2)					//限制 时针为2时,低位不得破4
	{
		num2[flag]=0;
		return;
	}
	else if((flag==3||flag==6)&&num2[flag]==5)				//分针、秒针高位不得破6
	{
		num2[flag]=0;
		return;
	}
		num2[flag]++;
		num2[flag]%=10;														//防止任意数字破9
}

void compare()																		//闹钟,比较是否到达预定时间
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		if(num1[i]==num2[i])
			f1=1;
		else
		{
			if(f3)
				return;
			else
			{
				f1=0;
				return;
			}
		}
	}
	f3=1;
}

void ring()																		//闹铃
{
	bz=~bz;
}


部分说明:
num1[] 储存时钟数值
num2[] 储存闹钟数值
关闭闹铃的按键与更换闪烁位复用了
闹铃的闪烁与时钟的定时器复用了
(待后续补充)

效果展示

1.时钟显示
在这里插入图片描述

2.闹钟设置
切换
在这里插入图片描述

换位在这里插入图片描述
数值+1
在这里插入图片描述

3.闹钟开启与关闭
利用中断持续闪烁
在这里插入图片描述
关闭
在这里插入图片描述

**
1.闹铃的蜂鸣器我使用了led灯代替,便于显示
2.proteus里的延时似乎是受电脑性能影响,故代码中的延时参数 i 等全局变量并非理论值,应个性化调整
3.待后续补充…

ps:欢迎评论区咨询讨论
电路图与代码

2020.8.6:

事实上,当初因时间限制,程序(判断闹钟是否到时)这部分算法有些臃肿复杂,存在很大的优化空间(我用了f1,f2,f3三个flag变量,实则并无必要),个人建议可以将闹钟判断响应部分的代码推翻重写
目前闹钟存在只能响应一次的问题,bug也是出在对f1,f2,f3三个状态量的if判断语句上

  • 63
    点赞
  • 413
    收藏
    觉得还不错? 一键收藏
  • 64
    评论
评论 64
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值