51实现闹钟

您所在的位置:网站首页 数码迷彩设计流程图 51实现闹钟

51实现闹钟

2024-01-11 21:32| 来源: 网络整理| 查看: 265

51实现闹钟 前言目标:所需元件:原理图软件部分:工程目录程序流程图软件代码:

前言

第一次写博客,使用CSDN也好几年了,第一次作为创作者的身份去写博客,以前都是在印象里面做做笔记这样的,今天把我这次51实验的程序作为博客生涯的第一篇吧,加油。

目标:

通过51单片机设计一个简单的闹钟,具体为:可以实现基本时钟功能,按键还能切换日期,和闹钟,且能自由设置。后续添加支持新建闹钟,理论支持无限添加新的闹钟。

所需元件:

硬件部分:51单片机、数码管、蜂鸣器。

原理图

实验板原理图 以上就是我们的硬件组成,关于基本的硬件原理、工作流程等相信大家耳熟能详,我这里不在赘述,而我们用到的k1-显示切换,k2-选中调整,k3按键加,k4-按键减。

软件部分:

基本的工程创建我就不介绍了,下面是工程目录结构,主要包含两个目录一个存放源文件,一个存放工具类文件,工具类文件夹里面是我在写其他的程序的时候,抽离出来的一些公共的方法,声明在头文件中,而头文件无需导入,只要在软件中指定其路径即可使用。

工程目录

工程目录

程序流程图

程序流程图 关于工程设计的基本思想,在我们的流程图中得到体现,读者可以仔细研磨,这对后面讲解代码部分有帮助,而我们的代码讲解也会按照流程图顺序来介绍。

软件代码:

1、 定时器初始化。使用两个定时器,T0和T1都用到了,这在之前本来是不需要的,但是后来发现了一点问题,先说现象:当我按下按键进行模式选择的时候或者其他的按键的时候,发现秒钟不准了,一按按键,速度就不正常了,原因:后来发现我在按键扫描的软件防抖的时候,用的和我们系统一样的定时器,那就有问题了,后来发现了,然后换成使用两个定时器,一个作为系统时钟,一个是软防抖的,代码就不贴了,比较简单,读者可自行编写。 2、选择默认显示的参数。这里本来不需要单独作为一个流程的,但是如果是这样,后面的现象都解释不清楚,那他很简单了,定义两个一维数组,用来存放我们的时间和日期,然后定义一个二维数组存放闹钟,还有一个数组指针。在我们需要显示的时候把我们的指针指向谁,然后把指针传递给我们数码管显示,也就是说我们不直接操作我们定义的任何一个数组,而是间接的通过指针来访问(本来指针是直接访问)。

u16 Time[3] = {10 , 23 , 0 }; u16 Date[3] = {20 , 12 , 1 }; u16 AlarmClock[3] = {10 , 23 ,10}; u16 *TimOrDatOrClock; sbit beef = P1^5;

3、按键判断。按键判断我这里为了严谨,使用的上升沿检测,按键按下数值不变,手松开按键,才视为一次按键事件,具体如下:

/*做到上升沿检测*/ u8 key_scan(void) { u8 status = null; status =(Serial_Key & 0x0f) ; if(status != 0x0f){ wait_ms(14); if((Serial_Key & 0x0f) == 0x0f) return status; } return null; }

注意:Serial_Key 我定义的是P3 口,因为P3口用到了串口和按键,这在原理图中可见,读者可返回参看。 4、检测闹钟时间是否到了。没有其他的,判断当前的时间是不是和闹钟的时间相等就可以做到,具体如下: 简单介绍:定义一个变量为3,当我们小时一致是减去1,再判断分钟一致时减去1,最后是秒,当我们的所有的全部一致时,我们的stat 应该是0。如果我们的stat是0的话应该和我们的is_beef 取反是一致的,is_beef 是我们用来标识蜂鸣器是不是在响,当我们有多个闹钟的时候,且时间在十秒之内,那就不会重复执行,tim是我们用来展示闹钟响铃的时间的,这里可以注意下,后面会讲到我们是如何用它来做一个逐渐急促的闹钟声的。 5、数码管显示。这个是我们比较重点的部分,因为我在这部分花费的时间是最多的,不是很难,但是结合控制闪烁,显示切换和其他一些要考虑的东西,那就显得十分繁琐了,基本思想我们清楚显示中有一部分不变,作为横杠的分割部分,下面直接看代码展示:

void is_Colck() { u8 stat = 3; for(i = 0; i u8 status = 8; u8 j , i ; if(k >= 1) k--; for( j = 0 ; j j = 350; Dis_chip_Sel = chip_sele[status- i-1]; if(i == 2 || i == 5) DISP = num[10]; else //不是分割部分 { if( IS != 0 )//没有任何值被选中 { if(i == (IS-2) || i == (IS-3))//判断是否选中当前值 if(k CarryBit(Time ,2,2,2); switch(key_scan()) { case Key_Mode: //调整 IS += 3; if(IS >= 10) IS = 0; break; case Key_: //按键减 Decide(0); break; case Key_Add: Decide(1); if(IS == 0) ; break; case Key_TXD: Change(Tor); Tor ++; if(IS == 0) ; } // if( !Tor ) TimOrDatOrClock = Time; else TimOrDatOrClock = Date; Disp_Vue_Plus( TimOrDatOrClock ); //Tor is_Colck(); } }

分析:用一个switch接收到我们得到的按键,分别是四个按键,我们把我们需要和硬件定义的值做了封装,便于后期更改,养成来良好的代码习惯很重要,这一点读者需要学习,这在以后的任何的开发中是十分常见的,定义在后面放出图片方便对比观看。 之前介绍到模式按键是对IS加3的操作,想一想我们之前将数码管的部分,想不起来?我来给读者复述一下:本来 IS 是 0 的,0 减去 2 和减去 3 不会对任何数码管选中;然后按下了一次,IS 为 3,判断 IS - 2 和 IS - 3 的值那就是 1和 0 了对应得数组下标的值的数码管就相当于选中,这个IS变量十分关键,贯穿了我们整个工程,后面我们判断是否有按键按下了(选中了),当前选中的是哪一个(通过 IS 减 1 或 2 得到),十分重要,需要理解。 Key_ 表示的是我们按键减按下执行的部分,这里使用的不是函数,而是宏定义(Decide(0))万物皆可宏定义,感兴趣的读者可以查阅资料。 细心的读者,应该发现我后面有一句if(IS == 0)未作任何处理,判断的就是有没有任何按键按下,有没有选中的值,判断的原因方便我们做后续功能拓展,比如说,我们没有按下模式,直接按下加或者减键那这个状态是不是富余出来的了,好的利用起来,在我们的程序流程图中已经做好了功能定义,但是作者未能有时间去实现,有精力的读者朋友可以帮我完善,欢迎改进、和我讨论。

#define Serial_Key P3 //把串口和按键定义出来 #define Key_Mode 0x0e #define Key_TXD 0x0d #define Key_ 0x0b #define Key_Add 0x07 #define Dis_chip_Sel P2

还有我们宏定义部分:

#define Decide(OV) for( i = 0; i < 3; i++) \ if(OV){ \ if(IS == ((i+1)*3)) \ TimOrDatOrClock[i]++; \ }else { \ if(IS == ((i+1)*3) && TimOrDatOrClock[i] > 0) \ TimOrDatOrClock[i]--; \ }

定义很简单,IS判断也作为了我们重要判断的依据之一,总的代码会循环3次表示全部判断一次,加和减的部分基本一致,需要注意的是语法:”\”宏定义不能分行用它来表示该行是不分段的,注意” \”后面不能有任何符号,空格也不行,否则会报错,逻辑简单,就不具体分析了,代码就代表我的思路。

最后是我们的模式切换按键了,分别显示时间、日期和闹钟

#define Change(EX) switch(EX) { \ case 1: TimOrDatOrClock = AlarmClock; break; \ case 2: TimOrDatOrClock = Time; break; \ case 3: TimOrDatOrClock = Date; break; \ default: EX = 0; }

EX为我们定义的一个值,每次按下加1,到3归0 ;

2-1 闹钟时间判断部分。之前讲到怎么判断闹钟时间到了,这次我们讲一下当我们时间到了的时候,怎么实现蜂鸣器做有急促的响声,代码如下:

void is_Colck() { u8 stat = 3; for(i = 0; i Tim_s(); //定时器赋予初值 times++; if( times == 20) //一秒时间 { times = 0; Time[2] ++; } if(tim u8 j = 0; if((MaxHeiBit | MaxConBit | MaxLowBit) == null) { //还没实现以后有时间 ha } else { for( j = 2 ; j > 0 ; j--) if(arr[j] >= 60) { arr[j] = 0; arr[j-1]++; } }

注意的是有一点:传入的参数,我开始的想法是做成一个模板,我解释一下,读者就明白了

参数作用*arr需要做检测的主体MaxHeiBit最高位的最大值, 例如:小时的最大位是 12MaxConBit次高位的最大值,例如:分钟的最大位是 60MaxLowBit低位的最大值, 例如:秒钟的最大位是 60

这样可以在主函数用一个变量做12小时制和24小时制的切换,遗憾的是我没有实现它。 现象: 闹钟 本次图片拍摄于,在我开始写这篇博客之前,显示的是日期;

本篇博客就到这里,有什么问题、疑问,欢迎在下方评论区留言讨论。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3