51单片机编程基础(C语言):电子时钟(LED1602作为显示)

题目要求:

审题时这个题是用数码管来显示的,数码管显示时钟我完成了一个,只是要求跟他不一样,所以这次想用LCD1602来显示,所以我先用LCD1602完成,再用数码管完成(其实也只要在我之前的项目基础上改一下就OK了)。

其实从第一个要求就看出来了,数码管无法显示:,只能显示.这次我用LCD显示,把所以得.改为:

1、显示“时.分”进行显示,例如“12.18”,其中.每秒闪烁一次。

2、能够校正时间的时和分,按键分为5个功能键

(1)设定键:在计时模式时,按下此键时停止计时,进入设置状态,并切换到分钟的设置状态,再按一次切换到小时的设置状态,每按下一次完成时.分设置的切换,用点亮时.分个位的数码管小数点表示分或秒处于设置状态。在闹钟时间设定状态时,按下此键同样进入设置状态,完成分、秒设置的切换。

(2)递增键:在设置状态时,按一次递增键,被设置的分钟数字或时钟数字增1,持续按下数字自动增1。

(3)递减键:在设置状态时,按一次递减键,被设置的分钟数字或时钟数字减1,持续按下数字自动增1。

(4)计时键:在设置状态或闹钟时间设定状态时,按下此键则单片机切换到计时的显示模式,按照新的时.分设置值进行计时。如果已经在计时状态则此键无效。

(5)闹钟键:在计时模式时,按下此键则单片机切换到闹钟时间设定状态的显示模式。等待“设定键”、“递增键”、“递减键”来设定分钟和秒钟。

3、当计时到闹钟设定时间,用发光二极管闪烁,十秒钟后结束闪烁,正常计时

总代码:

main.c     剩下的都是模块化编程好的,在我的模块化编程大全里面,

调试视频在我视频里

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey"
#include "Timer0.h"unsigned char hour=23;  //小时位
unsigned char min=57;  //分钟位  
unsigned char miao=0;   //秒位
unsigned char keyNumber;     //接收矩阵键盘的返回值
unsigned char Mode=0;       // :显示标志位
unsigned char Start=0;       // 0为开始计时,1暂停计时
unsigned char min_hour_set; //当S1按下时,切换到计时小时和分钟设置位
unsigned char clock_hour;//闹钟的小时位
unsigned char clock_min;  //闹钟的分钟位 
unsigned char clock_miao;   //闹钟的秒位
unsigned char clock_counttime=0; //界面显示标记位,0为显示时钟模式,1为显示clock模式
unsigned char clock_min_clock_hour_set; //在闹钟模式显示下,切换到闹钟小时和分钟设置位   //按键不可能同时是两个值。
unsigned char flag=0;  //处于计时界面下,flag=0,处于clock界面下,flag=1,//flag=0时,此时按下S1就是时钟模式设置键,flag=1,此时就是clock模式设置键
unsigned char who=0;   //由于加加,减减键是对min,hour起作用,即使进入闹钟模式,按下s1,按加加键无法改变闹钟的设置//反而让计时模式下的时钟改变了,因为min_hour_set非0即1,//所以对加加,减减键设置标志位,
sbit  LED=P2^0;
sbit BEEP=P2^5;
unsigned int i=1000;    //蜂鸣器报警时长。
unsigned int j=10;void main()
{Timer0Init();LCD_Init();LCD_ShowChar(2,3,':');while(1){keyNumber=MatrixKey();if(Mode==0){LCD_ShowChar(2,3,':');}if(Mode==1){LCD_ShowChar(2,3,' ');}if(clock_counttime==0){LCD_ShowString(1,1,"count time");LCD_ShowNum(2,4,min,2);//更新显示LCD_ShowNum(2,15,miao,2);//更新显示LCD_ShowNum(2,1,hour,2);}if(clock_counttime==1){LCD_ShowString(1,1,"clock      ");LCD_ShowString(2,7,"           ");LCD_ShowNum(2,4,clock_min,2);//更新为闹钟模式显示LCD_ShowNum(2,1,clock_hour,2);//更新为闹钟模式显示}if(keyNumber==5)//S5按下,进入闹钟模式界面{clock_counttime=1;LCD_ShowString(1,12,"        ");flag=1;who=1;}if(keyNumber==4)//S4按下,进入计时模式界面{clock_counttime=0;LCD_ShowString(2,7,"           ");LCD_ShowString(1,12,"        ");Start=0;flag=0;who=0;}if(flag==0){if(keyNumber==1)//S1按下 进入设置按键{Start=1;min_hour_set++;LCD_ShowString(2,7,"min ");if(min_hour_set>=2){min_hour_set=0;LCD_ShowString(2,7,"hour");}		}}if(flag==1){	if(keyNumber==1)//S1按下 进入设置按键{clock_min_clock_hour_set++;LCD_ShowString(1,12,"min        ");if(clock_min_clock_hour_set>=2){clock_min_clock_hour_set=0;LCD_ShowString(1,12,"hour       ");}		}}if(keyNumber==2)//S2按下,设置加加键{if(who==0){if(min_hour_set==1)//分钟设置状态{min++;if(min>=60){min=0;}}if(min_hour_set==0)//小时设置状态{hour++;if(hour>=24){hour=0;}}}if(who==1){if(clock_min_clock_hour_set==1)//时钟分钟设置状态{clock_min++;if(clock_min>=60){clock_min=0;}}if(clock_min_clock_hour_set==0)//时钟小时设置状态{clock_hour++;if(clock_hour>=24){clock_hour=0;}}}}if(keyNumber==3)//S2按下  设置减减键{if(who==0){if(min_hour_set==1)//分钟设置时间{if(min==0){min=60;}min--;}if(min_hour_set==0)//小时设置状态{if(hour==0){hour=24;}hour--;}}if(who==1){if(clock_min_clock_hour_set==1)//时钟分钟设置状态{if(clock_min==0){clock_min=60;}clock_min--;}if(clock_min_clock_hour_set==0)//时钟小时设置状态{if(clock_hour==0){clock_hour=24;}clock_hour--;}}}if(clock_hour==hour&&clock_min==min){
//			LED=0;
//			while(j--)//LED闪烁
//			{
//			 LED=~LED;
//			 Delay(1);
//			}while(i--){BEEP=!BEEP;Delay(1);}i=1000;}}
}
//定时器0中断函数模板
void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 = 0x18;		//设置定时初值TH0 = 0xFC;		//设置定时初值T0Count++;if(T0Count>=1000){T0Count=0;if(Start==0){	miao++;if(miao>=60){min++;miao=0;}if(min>=60){hour++;min=0;}if(hour>=24&&min==0){hour=0;}Mode++;if(Mode>=2){Mode=0;}}}
}

设计思路:

一个一个功能实现,但是要有自己的整体框架,不然后面会越敲越晕,因为都是嵌套的,这个跳到那个,没有系统的框图是不行的,我刚开始就没设计闹钟的那一块代码,所以定时器模块写完之后,突然加闹钟模块就很乱,思绪就没有了,后面就休息了,特别累的时候,想不明白的时候一定要好好休息,也许休息好了就会有灵感了,我就是休息之后,想到应该要设置两个界面显示。一个是闹钟界面,一个是时钟界面,通过按键来切换,

项目总结:

其实在设计的时候,我都是一步一步调试的,每写一段代码自己去找问题,去发现跟自己预期的是不是一样的。有问题就去找解决方案,确实这一个过程是极其费时间的,特别遇到一些bug,更会折磨人的心态,但是往往是这些问题,才会让我们更加去思考,

比如我在实现第一个功能时,就花了很多时间,也遇到了bug.

1.先实现第一个要求(wo当时第一步开始想的是这样的)

直接调用LCD1602模块和延时函数模块,下面是main函数代码

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
unsigned char hour=12;
unsigned char min=18;void main()
{LCD_Init();LCD_ShowNum(2,1,hour,2);LCD_ShowNum(2,4,min,2);LCD_ShowChar(2,3,':');while(1){ Delay(1000);LCD_ShowChar(2,3,' ');Delay(1000);LCD_ShowChar(2,3,':');}
}

虽然很好的实现了,但是后面又出现问题了。。。。。

但是配上定时器扫描后,就会让秒每隔2秒显示一次。 因为Delay了2秒,然而,定时器与CPU是分开工作的,虽然题目不对秒显示有要求,但是我觉得上面显示不妥,所以我把:的显示放在定时器中断里面,这样:就会按秒每加一而闪烁。 下面是代码。

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey"
#include "Timer0.h"
unsigned char hour=12;//小时位
unsigned char min=18;//分钟位  
unsigned char miao=0;   //秒位
unsigned char keyNumber;   //接收矩阵键盘的返回值
unsigned char Mode=0;  // :显示标志位void main()
{Timer0Init();LCD_Init();LCD_ShowNum(2,1,hour,2);while(1){ LCD_ShowNum(2,4,min,2);LCD_ShowNum(2,15,miao,2);}
}//定时器0中断函数模板
void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 = 0x18;		//设置定时初值TH0 = 0xFC;		//设置定时初值T0Count++;if(T0Count>=1000){T0Count=0;miao++;if(miao==60){min++;miao=0;}if(Mode==0){LCD_ShowChar(2,3,':');}Mode++;if(Mode>=2){LCD_ShowChar(2,3,' ');Mode=0;}}
}

刚开始效果还是可以,但是把显示放在定时器中断中,就会出现bug.

在我完成第二个要求的时候。

2.实现第二个要求: 

第二个要求有点多,我们细分为5个小要求来完成。

要有5个功能键,独立按键只有四个,所以我选择矩阵键盘按键,(当然,你也可以选择独立按键,按一次是这个功能,按两次是另外一个功能,可以设置一个符号位,通过按键改变符号位,从而根据符号位不同来选择想要功能)

所以我矩阵键盘按键模块再次调用过来

1)设定键:在计时模式时,按下此键时停止计时,进入设置状态,并切换到分钟的设置状态,再按一次切换到小时的设置状态,每按下一次完成时.分设置的切换,用点亮时.分个位的数码管小数点表示分或秒处于设置状态。在闹钟时间设定状态时,按下此键同样进入设置状态,完成分、秒设置的切换。(我把这个键用矩阵键盘S1表示)

看到计时,肯定要计数器中断模块,我再把计时器中断调用过来。当然了,这个题只让显示分,小时,没有秒,所以我们设置一个变量来控制秒,秒=60时,min加一,min>60时,hour加一。

产生一个新的问题:我的LCD_ShowNum(2,1,hour,2);放在while循环里时,为了更新显示。为啥min显示后面总会出现一个0,或者一个奇怪的数字,我明明规定hour是两位显示啊,产生一个新的bug希望有人能帮我找到问题,上面的那个代码我没有放在while,没有更新显示,也没有出现min后面多个0;之前写的时钟都没问题的,按理说这个也没问题的。(bug)

为了解决上述问题,我把LCD_ShowNum(2,1,hour,2);放在了定时器中断中。(继续接连出现bug)

由于前面的bug,我把hour放在定时器中断中,暂停后,hour也不会更新显示,矛盾了,所以我还是放到了while(1)循环里更新显示了,bug还需要大家帮我解决啊,不然,看起来好别扭,

好奇怪,明明之前是坏的,写完矩阵键盘控制突然又好了。bug消失了,我觉得是单片机内部问题,可能你们应该不会遇到。但是为了想解决这个花了好多时间。(但是bug时好时坏)。

按下此键无法计时,所以我们又要设置一个标志位。Start=0; // 0为开始计时,1暂停计时,按下按键,Start=1,实现暂停。

切换到分钟的设置状态,再按一次,切换到小时的设置状态,(所以我们继续设置标志位,1为小时键,0位分钟位)切换是不是要调时间,我们顺道把第(2)(3)个要求完成。

(2)递增键:在设置状态时,按一次递增键,被设置的分钟数字或时钟数字增1,持续按下数字自动增1。(完成)(S2键)

(3)递减键:在设置状态时,按一次递减键,被设置的分钟数字或时钟数字减1,持续按下数字自动增1。(完成)  (S3键)

(4)计时键:在设置状态或闹钟时间设定状态时,按下此键则单片机切换到计时的显示模式,按照新的时.分设置值进行计时。如果已经在计时状态则此键无效。(S4键)(完成)

按下此键,进入计时状态,在设置状态或(闹钟时间设定状态)时,闹钟计时状态我们先不管,我还没做,

在设置状态时,我们不是把时和分设置好了。按下计时键,则单片机切换到计时的显示模式,按照新的时.分设置值进行计时。(所以这个键就是开始计时,因为之前暂停了。)如果已经在计时状态则此键无效。是不是要在Start==1,才能生效。

(5)闹钟键:在计时模式时,按下此键则单片机切换到闹钟时间设定状态的显示模式。等待“设定键”、“递增键”、“递减键”来设定分钟和秒钟。

在计时模式时,才能按下此按键,所以Start==0才能生效。进入闹钟模式是不是要回来,第四个要求,按下计时键回来

(这一部分的思路就完全错了)后面自己就再也没设计了。

第二天的时候,自己就从新开始构思,1s闪,为啥不用标志位去变呢1.以及后面遇到的问题,自己都一步一步去思考,去解决,

代码遇到的错误,中午括号

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/469057.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《数电》理论笔记-第3章-常用组合逻辑电路及MSI组合电路模块的应用

一&#xff0c;编码器和译码器 1&#xff0c;编码器 编码:用由0和1组成的代码表示不同的事物。 编码器:实现编码功能的电路&#xff0c; 常见编码器:普通编码器、优先编码器、二进制编码器二-十进制编码器等等 1.1 三位二进制普通编码器和三位二进制优先编码器 1分58秒开始 …

洛谷_P1923 【深基9.例4】求第 k 小的数_python写法

哪位大佬可以出一下这个的题解&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;话说蓝桥杯可以用numpy库吗&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f; 这道题有一个很简单的思路就是排序完成之后再访问。 but有很大的问题&…

近十年金融资产收益率

通过掌握大类资产的历年收益率数据&#xff0c;做基于数据的投资&#xff0c;提高胜率和收益率。 下面是同花顺梳理的2014至2023大类金融资产收益率&#xff1a; 基于这个数据&#xff0c;我们再统计两项指标&#xff1a; 1. 每种资产在近十年的投资胜率&#xff08;收益率为…

哈希表 ?

哈希表 首先什么是 哈希表&#xff0c;哈希表&#xff08;英文名字为Hash table&#xff0c;国内也有一些算法书籍翻译为散列表&#xff0c;大家看到这两个名称知道都是指hash table就可以了&#xff09;。 哈希表是根据关键码的值而直接进行访问的数据结构。 这么这官方的解释…

每日一练——月落乌啼算钱

题目&#xff1a; 举例&#xff1a; 输入&#xff1a;6&#xff0c;输出&#xff1a;8.00 最开始看到这道题还有点蒙&#xff0c;但是看到他的公式想起了斐波那契数列 1,1,2,3,5,8...... 由前两个数相加得到第三个数&#xff0c;为An2An1An。 可以得出这个题目中所给的通项就…

Spark编程实验六:Spark机器学习库MLlib编程

目录 一、目的与要求 二、实验内容 三、实验步骤 1、数据导入 2、进行主成分分析&#xff08;PCA&#xff09; 3、训练分类模型并预测居民收入 4、超参数调优 四、结果分析与实验体会 一、目的与要求 1、通过实验掌握基本的MLLib编程方法&#xff1b; 2、掌握用MLLib…

《UE5_C++多人TPS完整教程》学习笔记3 ——《P4 测试多人游戏(Testing Mutiplayer)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P4 测试多人游戏&#xff08;Testing Mutiplayer&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&#xff08;也是译…

Java入门高频考查基础知识9(银盛15问万字参考答案)

JAVA刷题专栏&#xff1a;http://t.csdnimg.cn/9qscL 目录 一、Springcloud的工作原理 三、注册中心心跳是几秒 四、消费者是如何发现服务提供者的 五、多个消费者调⽤用同⼀接口&#xff0c;eruka默认的分配⽅式是什么 六、springboot常用注解&#xff0c;及其实现 七、…

【Java】零基础蓝桥杯算法学习——线性动态规划(一维dp)

线性dp——一维动态规划 1、考虑最后一步可以由哪些状态得到&#xff0c;推出转移方程 2、考虑当前状态与哪些参数有关系&#xff0c;定义几维数组来表示当前状态 3、计算时间复杂度&#xff0c;判断是否需要进行优化。 一维动态规划例题&#xff1a;最大上升子序列问题 Java参…

反序列化漏洞(一)Shiro漏洞CVE-2016-4437复现

★★免责声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将信息做其他用途&#xff0c;由Ta承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 1、前言 春节后第一篇&#xff0c;祝大家龙年一切顺利&…

第二十八回 施恩重霸孟州道 武松醉打蒋门神-可用于生产环境的Python Web框架:Pyramid

施恩给武松讲了他的烦心事&#xff0c;他在快活林的酒肉店被蒋门神霸占了。希望武松能帮他出气。施恩的父亲也从屏风后走出来&#xff0c;让施恩拜武松为兄长。 武松要去打蒋门神&#xff0c;跟施恩约好了“无三不过望”&#xff0c;望子就是酒旗&#xff0c;意思看到酒旗就要…

中国电子学会2023年12月份青少年软件编程Scratch图形化等级考试试卷一级真题(含答案)

2023-12 Scratch一级真题 分数&#xff1a;100 题数&#xff1a;37 测试时长&#xff1a;60min 一、单选题(共25题&#xff0c;共50分) 1.观察下列每个圆形中的四个数&#xff0c;找出规律&#xff0c;在括号里填上适当的数&#xff1f;&#xff08;C&#xff09;&#xf…