51实现闹钟 |
您所在的位置:网站首页 › 数码迷彩设计流程图 › 51实现闹钟 |
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 |