微信搜索:ReCclay,即可免费阅读博主蓝桥系列所有文章,后台回复“代码”即可获取蓝桥所有备赛代码!关注博主公众号,还可拥有加入博主粉丝群实时沟通技术难题、免费下载CSDN资源等多项福利,还在等什么呢?快快扫码关注,学习才不会迷路。
这里再向各位同学推荐一个CSDN博主 ReRrain 的蓝桥备赛博客,博主秉持初学者思路,向你讲述自己蓝桥备赛的心路历程,娓娓道来蓝桥备赛经验,个人觉得非常不错,值得细细品读。
文章目录
导读:《蓝桥杯单片机组》专栏文章是博主2018年参加蓝桥杯的单片机组比赛所做的学习笔记,在当年的比赛中,博主是获得了省赛一等奖,国赛二等奖的成绩。成绩虽谈不上最好,但至少问心无愧。如今2021年回头再看该系列文章,仍然感触颇多。为了能更好地帮助到单片机初学者,今年特地抽出时间对当年的文章逻辑和结构进行重构,以达到初学者快速上手的目的。需要指出的是,由于本人水平有限,如有错误还请读者指出,非常感谢。那么,接下来让我们一起开始愉快的学习吧。
不积跬步无以至千里,不积小流无以成江海。
经过前面的基础模块学习和实战小项目训练,相信你已经信心满满,摩拳擦掌跃跃欲试了!今天我们就拿第八届的蓝桥省赛题目《电子钟》来进行训练。话不多说,详细介绍请看下文。
前言
资料获取:
一、题目要求
-
初始化
1)关闭蜂鸣器、继电器等无关外设;
2)设备初始化时钟为 23 时 59 分 50 秒,闹钟提醒时间 0 时 0 分 0 秒。 -
时间显示格式(时钟和闹钟)
-
温度显示格式
-
时钟设置
按键 S7 定义为“时钟设置”按键,通过该按键可切换选择待调整的
时、分、秒,当前选择的显示单元以 1 秒为间隔亮灭,时、分、秒
的调整需注意数据边界属性。(有一点没提到,就是进入设置时钟设置模式后,数码管时间不再实时刷新,只需要调节的时候刷新!)
-
闹钟设置
按键 S6 定义为“闹钟设置”按键,通过该按键可进入闹钟时间设置
功能,数码管显示当前设定的闹钟时间。
-
按键 S5 定义为“加”按键,在“时钟设置”或“闹钟设置”状态下,
每次按下该按键当前选择的单元(时、分或秒)增加 1 个单位。 -
按键 S4 定义为“减”按键,在“时钟设置”或“闹钟设置”状态下,
每次按下该按键当前选择的单元(时、分或秒)减少 1 个单位。 -
按键 S4、S5 的“加”、“减”功能只在“时钟设置”或“闹钟设置”
状态下有效; -
在 “时钟显示”状态下,按下 S4 按键,显示温度数据,松开按键,
返回“时钟显示”界面。 -
闹钟提示功能
- 指示灯 L1 以 0.2 秒为间隔闪烁,持续 5 秒钟;
- 闹钟提示状态下,按下任意按键,关闭闪烁提示功能。
二、思路提炼
- 模块划分
- 数码管、按键、DS18B20、DS1302、一个LED
- 模式划分
- 时钟显示
- 时钟设置
- 闹钟设置
- 界面划分
- 时钟显示界面
- 时钟/闹钟设置界面
- 温度显示界面
- 细节实现注意
- S5/S4的作用
只在时钟设置或者闹钟设置的界面有效
- 在时钟显示界面
按下S4进入温度显示界面
,松开S4恢复时钟显示界面 - 时钟设置或者闹钟设置界面的光标
1s为间隔闪烁
- 闹钟定时到,
L1以0.2s为间隔闪烁,闪烁5s停止
闹钟定时到,按下任意键可以终止LED闪烁,即关闭闹钟提示
- S4,S5, 切换
时 -> 分 -> 秒 -> 时钟
显示
- S5/S4的作用
三、程序过程重现
上面已经分析了题目的具体要求,以及实现思路和细节注意。下面就让我们再来具体重现这个过程!!!
毫无疑问,顶层代码的正确使用前提是底层得确保无误!比赛的前2个半小时左右都是在实现底层的细节,顶层的验证也不能全部写完再进行,而是边写边验证。就上面的五个模块中(其实最后一个“LED”单独归为一个模块有点夸张了,但是鄙以为却真真切切的体现模块化编程的思想)数码管和按键的底层不涉及时序,较简单可以先行书写!
3.1、数码管和按键
这两底层代码可在KeyAction(u8 keycode)
+ShowNumber(u32 dat)
两个合起来同时验证一下底层的正确性!必须确保无误!
3.2、DS1302及time相关
接下来就是DS1302
的底层.c .h
的编写了,别忘了config
中定义相关的IO口,完了之后也同样需要校验是否正确!
在主函数中验证,
注意结构体的访问方法,这里只能用点运算符
!
RefreshTime
是在time.c
中封装的函数,同时也封装了一个ShowLedNumber
的函数,用来刷新显示时间到数码管!(注意,这里按照比赛常用的时间格式要求书写!)
确保无误后,再进行下一步!
3.3、毫无疑问下一步就改来到了最后一个底层DS18B20
编写完成底层后然后就行验证了,
Refresh18B20
同样定义到了time.c
中
刷新温度到数码管!!
3.4、上层逻辑
所有的底层工作完毕后,就是上层的**“组装”**了。当然不会是简单的拼接,还需要深入的逻辑!
模式划分,三种:时钟显示,时钟设置,闹钟设置!
这里就可以作为系统的三种状态,同时这三种状态,在某一个时刻肯定只有一个成立,所以设置一个枚举变量
会是个不错的选择!
enum eSystemSta{//分别对应 时钟显示模式,时钟该设置模式,闹钟设置模式
E_NORMAL, E_SET_TIME, E_STE_ALARM
};
这个模式的工作做好之后,下面就是具体的细节实现了!
看一下轮廓。
3.5、几个实现的细节地方
3.5.1、闹钟定时并可以任意键取消
void AlarmMonitor()
{
static u8 AlarmCnt=0;
static bit staLED=0;
if((AlarmHour==buffTime.hour) && (AlarmMin==buffTime.min) && (AlarmSec==buffTime.sec))//定时监控
{
flagAlarm = 1;
}
if(flagAlarm)
{
AlarmCnt++;
if(!staMute)
{
if(staLED==0)
{
staLED = 1;
P2 = (P2&0x1F)|0x80;
P0 = 0xFE;
P2 = P2&0x1F;
}
else
{
staLED = 0;
P2 = (P2&0x1F)|0x80;
P0 = 0xFF;
P2 = P2&0x1F;
}
}
if(AlarmCnt >= 25)
{
AlarmCnt = 0;
flagAlarm = 0;
P2 = (P2&0x1F)|0x80;
P0 = 0xFF;
P2 = P2&0x1F;
}
}
}
以及KeyAction()
里面的
if((flagAlarm==1) && (SystemSta==E_NORMAL))//时钟显示模式下,任意按键按下,都可以停止闹钟
{
staMute = 1;
P2 = (P2&0x1F)|0x80;//确保停止响铃的时候灯是灭的!
P0 = 0xFF;
P2 = P2&0x1F;
}
注意这里是设置了两重保障,flagAlarm
以及staMute
…在KeyAction()里面操作的只是staMute,只是不再闪灯了而已。如果一重保障,无法做到按下按键立即停止闹铃,不知道为什么。。。
3.5.2、BCD码的加减
以上就是本次省赛实战的全部训练内容了,感觉如何呢?欢迎评论区留言!
结语:以上就是本篇文章的全部内容啦,希望大家可以多多支持我的原创文章。如有错误,请及时指正,非常感谢。
微信搜索:ReCclay,即可免费阅读博主蓝桥系列所有文章,后台回复“代码”即可获取蓝桥所有备赛代码!关注博主公众号,还可拥有加入博主粉丝群实时沟通技术难题、免费下载CSDN资源等多项福利,还在等什么呢?快快扫码关注,学习才不会迷路。