赞
踩
上篇文末提到可以优化的地方包括加入闹钟,了解无源蜂鸣器的工作原理后,就着手扩展闹钟设置功能了,同时按键按下加入蜂鸣器的提示音。由于上篇的篇幅过长了,所以决定单独写一篇这个闹钟模块。
普中的板子上的是无源蜂鸣器,BZ连接在了步进电机OUT5,ULN2003D逻辑框图如下
对于蜂鸣器驱动需要输入振荡脉冲,ULN2003D作用为继电器驱动,在这里我们只需要考虑输入取反输出即可,因此蜂鸣器连接对应51寄存器地址为P2_5(图和板子不一样)
sbit Buzzer = P2^5; //类型声明蜂鸣器地址
循环体内使Buzzer每隔250us取反,一个周期为0.5ms,即2000HZ,循环执行次数决定持续时间,期间接收按键键码,只要键码不为0,即有任意独立按键按下,跳出循环,声音停止
- #include <REGX52.H>
- #include"Delay.h"
- #include"Key.h"
-
- sbit Buzzer = P2^5; //类型声明蜂鸣器地址
- unsigned int i; //计数
-
- /**
- * @brief 蜂鸣器以2000HZ的时间响x250us
- * @param xms 蜂鸣器响的时间
- * @retval 无
- */
- void Buzzer_Time(unsigned int x250us)
- {
- unsigned KeyNumber;
- for(i=0;i<x250us;i++)
- {
- KeyNumber = Key();
- Buzzer = !Buzzer; //振荡输入
- Delay10us(25); //高低电平维持时间为250us,一个周期就是0.5ms
- if(KeyNumber)break;
- }
-
- }
封装好之后可以用于按键提示音和闹钟
定义Clock_Sel为闹钟设置模式下的时间位索引,定义数组存放设置闹钟的时分秒
- //存放设置的脑钟时间
- char Clock[] = {0,0,0};
- //定义键码、设置时间位索引、设置时间闪烁标志、模式(显示时间/设置时间),闹钟设置时间位索引
- unsigned char KeyNum, TimeSet_Sel, TimeSetFlag, Mode, Clock_Sel;
按下1键让Mode在0、1、2之间循环,为了保持原有设置时间功能(从设置时间模式切换到模式0时写入修改后的时间),将模式2作为设置时间模式,模式1为新增的设置闹钟时间。每次切换到闹钟模式时,闹钟时间位索引清0,固定从时开始设置,并且将LCD清空第一行显示“Clock:”
- if(KeyNum == 1)
- {
- Buzzer_Time(100); //蜂鸣器按键提示音
- if(Mode == 0)
- {
- Mode = 1; //切换至设置闹钟模式
- LCD_Init();
- Delay(100);
- Clock_Sel = 0; //每次切换到设置闹钟索引清0
- }
- else if(Mode == 1 )
- {
- Mode = 2; //切换至设置时间模式
- TimeSet_Sel = 0; //每次切换到设置时间模式索引清0,固定从“年”开始闪烁
- }
- else if(Mode == 2)
- {
- Mode = 0; //切换回显示时间模式
- DS1302_SetTime(); //将已修改的时间数据写入芯片
- }
- }
- switch(Mode) //显示当前工作模式
- {
- case 0: LCD_ShowString(2,12,"Show ");break;
- case 1: LCD_ShowString(2,12,"Clock ");break;
- case 2: LCD_ShowString(2,12,"Set ");break;
- }
当Mode == 1时,执行设置闹钟模式代码
思路可以说是完全照搬了上一篇的设置时间函数,都是按2键索引++,3键当前时间位++,4键当前时间位--,越界判断和校正从之前的函数里截取了时分秒的部分,闪烁设置也是一样的,按键提示音在整个程序所有地方都加上了,没什么好说的直接贴代码
- void SetClock(void)
- {
- LCD_ShowString(1,1,"Clock:");
- LCD_ShowNum(1,13,Clock_Sel,2);
- if(KeyNum == 2) //2号按键选择设置的时间位
- {
- Buzzer_Time(100); //蜂鸣器按键提示音
- Clock_Sel++;
- Clock_Sel %= 3; //索引在0~1
- }
- if(KeyNum == 3) //3号按键使当前时间位+1
- {
- Buzzer_Time(100); //蜂鸣器按键提示音
- Clock[Clock_Sel]++;
- if(Clock[0]>23)Clock[0] = 0; //小时越界判断
- if(Clock[1]>59)Clock[1] = 0; //分越界判断
- if(Clock[2]>59)Clock[2] = 0; //秒越界判断
- }
- if(KeyNum == 4) //4号键使当前时间位-1
- {
- Buzzer_Time(100); //蜂鸣器按键提示音
- Clock[Clock_Sel]--;
- if(Clock[0]<0)Clock[0] = 23; //小时越界判断
- if(Clock[1]<0)Clock[1] = 59; //分越界判断
- if(Clock[2]<0)Clock[2] = 59; //秒越界判断
- }
- LCD_ShowChar(2,3,':');
- LCD_ShowChar(2,6,':');
- if(Clock_Sel == 0 && TimeSetFlag ==1)
- LCD_ShowString(2,1," ");
- else
- LCD_ShowNum(2,1,Clock[0],2); //显示时
-
- if(Clock_Sel == 1 && TimeSetFlag ==1)
- LCD_ShowString(2,4," ");
- else
- LCD_ShowNum(2,4,Clock[1],2); //显示分
- if(Clock_Sel == 2 && TimeSetFlag ==1)
- LCD_ShowString(2,7," ");
- else
- LCD_ShowNum(2,7,Clock[2],2); //显示秒
- }
为了防止闹钟响个不停,所以设置闹钟的时间位要设计到秒才行,或者默认为0,并且只在模式0,也就是正常显示实时时间的模式下才会响,就不会出现,在设置闹钟的时候数字1位1位的加,“路过”闹钟时间结果响个几秒的尴尬
- if(Mode == 0) //模式0,显示时间
- {
- DS1302_ReadTime();
- TranserShowStr_Day(DS1302_Time[6]); //将数字转化为对应字符串显示
- ShowTime(); //显示年月日时分秒
- if(DS1302_Time[3] == Clock[0]&&DS1302_Time[4] == Clock[1]&&DS1302_Time[5] == Clock[2]) //到时间蜂鸣器响5s
- Buzzer_Time(24000);
- }
其实遇到的问题挺多的,但很多已经没什么印象了说明不怎么重要
1、关于进入闹钟模式清空屏幕,因为残留的显示数据不会消失,所以必须手动先清空,一开始我把LCD初始化函数写在了Clock_Set函数里,结果闪个不停,并且,时间位闪烁完全看不出来,后来意识到在while循环里只要Mode还等于1,就会不停的清空屏幕,因此闪个不停。但是其实一开始我并没有把模式切换写的那么详细,更喜欢之前的风格,Mode++,然后对3取余反复循环,这样写还要在写一步由模式0切换到1的判断,很麻烦,于是换了
2、由于很多代码都是用的前面的,,中间出了不少差错,还是不够细心..
基于51单片机的可调时钟的闹钟设置和效果演示
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。