51单片机 时钟显示、设置闹钟功能的实现 (附详细算法思路、proteus电路图)_51单片机闹钟程序-程序员宅基地

技术标签: 51单片机  

功能要求:

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判断语句上

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Aspiration_H/article/details/105845277

智能推荐

ffmpeg音视频处理流程核心技术_视频效果演示系统的核心技术-程序员宅基地

文章浏览阅读712次。视频播放器原理 什么是ffmpeg? ffmpeg 音视频编/解码 流程图 ffmpeg 常用 struct AVFormatContext AVStream AVCodecContext AVCodec AVPacket AVFrame ffmpeg 常用Api av_register_all() avformat_alloc_output_context2() avio_open()..._视频效果演示系统的核心技术

Java List集合多种情况处理方法_java list reduce-程序员宅基地

文章浏览阅读449次。Java List集合多种情况处理方法:List集合交集、并集、差集、去重、与数组互转、删除、排序等操作_java list reduce

【UML】软件需求说明书_uml需求文档访客管家-程序员宅基地

文章浏览阅读2.3k次,点赞77次,收藏80次。需求:指人对客观事务需要的表现,体现为愿望、意向和兴趣,因而成为行动的一种直接原因。软件需求(IEEE软件工程标准词汇表):(1)用户解决问题或达到目标所需的条件或能力。(2)系统或系统部件要满足合同、标准、规范或者其他正式规定文档所需具有条 件或能力。(3)对(1)或(2)中的一个条件或一种能力的一种文档化表述。用例:定义 1 用例是对一个活动者使用一个系统的一项功能时进行交互过程中的一个文字描述序列。_uml需求文档访客管家

linux笔记-根文件系统及文件管理命令详解_根文件系统文本登陆-程序员宅基地

文章浏览阅读574次。第三章、Linux根文件系统及文件管理命令详解02_03_Linux根文件系统详解文件系统:rootfs: 根文件系统 FHS:Filesystem Hierarchy Standard(文件系统目录标准)的缩写,多数Linux版本采用这种文件组织形式,类似于Windows操作系统中c盘的文件目录,FHS采用树形结构组织文件。FHS定_根文件系统文本登陆

马克 · 扎克伯格期望的元宇宙到底会是什么样子?_马克扎克伯格博客-程序员宅基地

文章浏览阅读358次。马克 · 扎克伯格期望的元宇宙到底会是什么样子?_马克扎克伯格博客

使用Python开发游戏运行脚本(二)实现模拟点击_大漠窗口绑定成功按键-程序员宅基地

文章浏览阅读1.4w次,点赞8次,收藏78次。本文接上一篇文章 使用Python开发游戏运行脚本(一)成功调用大漠插件上一篇我们已经简单实现了python调用大漠插件并输出版本号的功能,接下来我们要做的就是通过大漠插件模拟鼠标点击和键盘文字输入。 由于近年来最热门的游戏基本都是手游,所以我们也会以手游为例来进行游戏脚本的开发。大漠插件是一款针对Windows平台的鼠标键盘模拟+图文查找库,这样我们要想实现手游脚本开发的第一步,就是下载Android模拟器,然后在对安卓模拟器进行鼠标和键盘的模拟,以此来实现自动化游戏脚本。一、Android模拟器的_大漠窗口绑定成功按键

随便推点

Canvas实现黑客帝国字符雨_canvas画字符雨-程序员宅基地

文章浏览阅读1k次。 利用Canvas的fillText(),隔一定时间在画布上作画&lt;!DOCTYPE html&gt;&lt;head&gt; &lt;meta charset="utf-8"&gt; &lt;meta name="viewport" content="width=device-width,initial-scale=1.0"&gt; &_canvas画字符雨

微信公众号跳转微信小程序,自定义微信跳转标签_opentaglist-程序员宅基地

文章浏览阅读1.1k次。微信公众号跳转微信小程序,自定义微信跳转标签_opentaglist

数据恢复技术与LVM数据恢复方法_vgreduce --removemissing恢复-程序员宅基地

文章浏览阅读4.3k次。数据恢复技术与LVM数据恢复方法 1摘要 随着计算机网络应用的发展,数据存储的安全性变的越来越重要。在常见的基于RAID和LVM的环境下面,当出现硬盘故障或者错误操作导致数据丢失的情况下,采用适当的数据恢复策略可以在很大程度上提供数据恢复的成功概率。本文研究了几种情况下的数据恢复技术和方法,为数据恢复和数据安全的预防提供了指导。 2数据恢复需求 2.1Linux IO存储栈 图(1)Linux IO 存储..._vgreduce --removemissing恢复

程序员如何年薪百万?深度学习必读书籍!_年薪百万的程序员看什么书-程序员宅基地

文章浏览阅读307次。深度学习程序员想年薪百万,基础必须打牢,所以推荐重点书籍Deep Learning花书Deep Learning with PythonDeep Learning for Computer Vision with PythonScikit-Learn与TensorFLow机器学习实用指南深度学习实践Tensorflow机器学习指南..._年薪百万的程序员看什么书

Window系统下C/C++程序毫秒和微秒级程序运行时间的获取方法_large_integer nfreq, t1, t2;-程序员宅基地

文章浏览阅读1.3k次。一、使用clock()函数,获取毫秒级(ms)时间[1]#include &lt;time.h&gt;//clock()头文件clock_t start = clock();{statement section}//测试代码段clock_t end = clock();printf("the running time is :%fs\n", (double)(end -s..._large_integer nfreq, t1, t2;

IntelliJ IDEA 使用教程-- 从入门到上瘾(配套视频教程)_idea使用视频教程-程序员宅基地

文章浏览阅读6.8k次,点赞3次,收藏31次。 前言: 至于用哪个开发工具本文暂且不做任何讨论, 今天着重讲解IntelliJ IDEA这款开发工具的使用 前言:IntelliJ IDEA如果说IntelliJ IDEA是一款现代化智能开发工具的话,Eclipse则称得上是石器时代的东西了。其实笔者也是一枚从Eclipse转IDEA的探索者,随着近期的不断开发实践和调试,逐步..._idea使用视频教程

推荐文章

热门文章

相关标签