# 杂谈 # 经过几个小时的奋战,我终于又把蓝桥杯的第八届省赛的题给做出来了!开心! 不过呢我已经做出来几天了,只是一直没有贴在博客里。今天刚好无聊我就贴上来了! 话不多说,我们进入正题 # 题目 # 我们先来看下题目吧。 ## 一、基本要求 ## 1.1 使用 CT107D 单片机竞赛板,完成“电子钟”功能的程序设计与调试; 1.2 设计与调试过程中,可参考组委会提供的“资源数据包”; 1.3 Keil 工程文件以准考证号命名,完成设计后,提交完整、可编译的 Keil工程文件到服务器。 ## 二、硬件框图 ## ![1.png][1] ## 三、功能描述 ## ### 3.1 初始化 ### 1)关闭蜂鸣器、继电器等无关外设; 2)设备初始化时钟为 23 时 59 分 50 秒,闹钟提醒时间 0 时 0 分 0 秒。 ### 3.2 显示功能 ### ![34AEBB75-0277-4AC1-A70D-1676606408C2.png][2] ### 3.3 按键功能 ### 1)按键 S7 定义为“时钟设置”按键,通过该按键可切换选择待调整的时、分、秒,当前选择的显示单元以 1 秒为间隔亮灭,时、分、秒的调整需注意数据边界属性。 ![2F354A3E-197C-4F36-B8EA-E8E4972E4C58.png][3] 2)按键 S6 定义为“闹钟设置”按键,通过该按键可进入闹钟时间设置功能,数码管显示当前设定的闹钟时间。 3)按键 S5 定义为“加”按键,在“时钟设置”或“闹钟设置”状态下,每次按下该按键当前选择的单元(时、分或秒)增加 1 个单位。 4)按键 S4 定义为“减”按键,在“时钟设置”或“闹钟设置”状态下,每次按下该按键当前选择的单元(时、分或秒)减少 1 个单位。 5)按键功能说明:按键 S4、S5 的“加”、“减”功能只在“时钟设置”或“闹钟设置”状态下有效;在 “时钟显示”状态下,按下 S4 按键,显示温度数据,松开按键,返回“时钟显示”界面。 ### 3.4 闹钟提示功能 ### 1)指示灯 L1 以 0.2 秒为间隔闪烁,持续 5 秒钟; 2)闹钟提示状态下,按下任意按键,关闭闪烁提示功能。 # 思路 # 在这里我大致说一下我的思路。 ## 1、初始化 ## 这个很简单的。时间显示23:59:50 这里时间芯片用的DS13B02,这款芯片我就不用多说了,大家都知道怎么个用法。 时钟的初始化我们需要把23:59:50先写入DS18B20,然后才能正常的从所设置的时间开始显示。 然后就是闹钟的初始化,我们这里直接在定义闹钟的变量的时候就直接给他赋值为0。 ## 2、温度显示 ## 我们在这里用到的温度芯片是DS18B20,关于这款芯片我就不多说了,请大家看我的下面这篇文章。 蓝桥杯-单片机经验分享-18B20 前言经过几天对107D开发版上的18B20的琢磨,终于在今天顺利的让他正确的显示了温度。下面写一些在这过程中遇到的... ## 3、按键检测 ## 按键识别我这里用到的是状态机扫描。关于状态机扫描的话大家也可以参考我下面这篇文章 基于51单片机的4x4矩阵键盘的状态机消抖 前言首先,我先给大家说一下按键抖动的原因和原理是什么。原因通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时... ## 4、数码管显示 ## 数码管显示,我相信在座各位都掌握得如火纯情了。我也就不多说了! # 难点汇总 # 在这里我分享一下我在设计、和码代码的过程中所遇到的难点。 ## 1、状态机扫描 ## 由于我也很少用状态机扫描来搞键盘,都是最近才用起来的,用过几次就感觉领悟了其中的奥秘了。下面我说一下几个注意事项。 ### Step.1 ### 我们在判断状态的时候一定要判断完!不要写到一半就开跑了。并且,该清零的时候就要清零。 ### Step.2 ### 把键盘的程序放定时器中断里,每隔10ms执行一次。 ## 2、温度读取 ## 对于温度的读取。这个真的是玄学问题。在我单独弄他的时候,必须把中断关了才能让他执行,不然温度读取不了,但是我放在这个大程序里却不用关中断都没问题!真的是玄学问题! #### 问题应该只有以上这些了,下面我就贴出来代码。有不懂得可以给我留言哟!#### # 代码分享 # ``` #include #include #include #include #include #define uint unsigned int #define uchar unsigned char #define smg_wei XBYTE[0xc000] #define smg_duan XBYTE[0xe000] #define buzz XBYTE[0xa000] #define LED XBYTE[0x8000] sbit S4 = P3^3; sbit S5 = P3^2; sbit S6 = P3^1; sbit S7 = P3^0; //数码管段码存储 uchar code duan[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff}; //数码管位码存储 uchar code wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //数码管显示缓存 uchar smg_count[]={0xff,0xff,0xbf,0xff,0xff,0xbf,0xff,0xff}; //时间缓存 uchar time_count[]={0x23,0x59,0x50}; //温度缓存 uchar team_count[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc6}; //调整时间数字缓存 uchar set_time_count[]={0x00,0x00,0x00}; uchar flag_S7 = 0,g = 0,flag_set_time = 0,flag_S6 = 0,i = 0; uint flag_time = 0; bit flag_alarm = 0; uint flag_LED_time = 0; uchar flag_LED1 = 0,flag1_alarm = 0; //延迟1ms程序 void Delay1ms(uint t) //@12.000MHz { unsigned char i, j; while(t--) { i = 12; j = 169; do { while (--j); } while (--i); } } //定时器初始化程序 void Timer0Init(void) //1毫秒@12.000MHz { AUXR |= 0x80; //定时器时钟1T模式 TMOD &= 0xF0; //设置定时器模式 TL0 = 0x20; //设置定时初值 TH0 = 0xD1; //设置定时初值 TF0 = 0; //清除TF0标志 //TR0 = 1; //定时器0开始计时 ET0 = 1; //开启定时器0中断 EA = 1; //打开总中断 } //数码管显示 void smg_display() { static uchar i = 0; smg_duan = 0xff; smg_wei = wei[i]; smg_duan = *(smg_count + i); if(++i == 8) i = 0; } //时间取值 void read_time() { uchar *p; p = read_ds1302(); smg_count[0] = duan[(time_count[0] = *p)>>4]; smg_count[1] = duan[time_count[0]&0x0f]; smg_count[3] = duan[(time_count[1] = *(p + 1))>>4]; smg_count[4] = duan[time_count[1]&0x0f]; smg_count[6] = duan[(time_count[2] = *(p + 2))>>4]; smg_count[7] = duan[time_count[2]&0x0f]; smg_count[2] = smg_count[5] = 0xbf; } //读取当前温度值以及处理 uint flag_team = 0; void read_team() { static uchar team; if(flag_team >= 100) { //TR0 = 0; team = rd_temperature(); //TR0 = 1; flag_team = 0; } smg_count[0] = smg_count[1] = smg_count[2] = smg_count[3] = smg_count[4] = 0xff; smg_count[7] = team_count[7]; if(team == 85 || team == 0) { smg_count[5] = 0xbf; smg_count[6] = 0xbf; return; } smg_count[5] = team_count[5] = duan[team/10]; smg_count[6] = team_count[6] = duan[team%10]; //strcpy(smg_count,team_count); } //键盘处理程序 uchar flag2_but = 0; void button() { if(flag_alarm == 0) { static uchar flag1_but = 0; uchar x = P3; x = x & 0x0f; switch(flag1_but) { case 0: if(x != 0x0f) { flag1_but = 1; } else { //P3 = 0xff; flag1_but = 0; } break; case 1: if(x != 0x0f) { switch(x) { case 0x07: switch(flag_S7) //时钟设置 { case 1: if(flag_S7) { if(time_count[0] == 0x00) { time_count[0] = 0x24; } time_count[0]--; if((time_count[0]&0x0f) == 0x0f) { time_count[0] &= 0xf0; time_count[0] |= 0x09; } } break; case 2: if(time_count[1] == 0x00) { time_count[1] = 0x60; } time_count[1]--; if((time_count[1]&0x0f) == 0x0f) { time_count[1] &= 0xf0; time_count[1] |= 0x09; } break; case 3: if(time_count[2] == 0x00) { time_count[2] = 0x60; } time_count[2]--; if((time_count[2]&0x0f) == 0x0f) { time_count[2] &= 0xf0; time_count[2] |= 0x09; } } switch(flag_S6) //闹钟设置键盘处理 { case 1: if(flag_S6) { if(set_time_count[0] == 0x00) { set_time_count[0] = 0x24; } set_time_count[0]--; if((set_time_count[0]&0x0f) == 0x0f) { set_time_count[0] &= 0xf0; set_time_count[0] |= 0x09; } } break; case 2: if(set_time_count[1] == 0x00) { set_time_count[1] = 0x60; } set_time_count[1]--; if((set_time_count[1]&0x0f) == 0x0f) { set_time_count[1] &= 0xf0; set_time_count[1] |= 0x09; } break; case 3: if(set_time_count[2] == 0x00) { set_time_count[2] = 0x60; } set_time_count[2]--; if((set_time_count[1]&0x0f) == 0x0f) { set_time_count[2] &= 0xf0; set_time_count[2] |= 0x09; } } g = 4;break; case 0x0b: switch(flag_S7) { case 1: time_count[0]++; if((time_count[0]&0x0f) >= 0x0a) { time_count[0] += 0x10; time_count[0] &= 0xf0; } if(time_count[0] == 0x24) time_count[0] = 0x00; break; case 2: time_count[1]++; if((time_count[1]&0x0f) >= 0x0a) { time_count[1] += 0x10; time_count[1] &= 0xf0; } if(time_count[1] == 0x60) time_count[1] = 0x00; break; case 3: time_count[2]++; if((time_count[2]&0x0f) >= 0x0a) { time_count[2] += 0x10; time_count[2] &= 0xf0; } if(time_count[2] == 0x60) time_count[2] = 0x00; } switch(flag_S6) { case 1: set_time_count[0]++; if((set_time_count[0]&0x0f) >= 0x0a) { set_time_count[0] += 0x10; set_time_count[0] &= 0xf0; } if(set_time_count[0] == 0x24) set_time_count[0] = 0x00; break; case 2: set_time_count[1]++; if((set_time_count[1]&0x0f) >= 0x0a) { set_time_count[1] += 0x10; set_time_count[1] &= 0xf0; } if(set_time_count[1] == 0x60) set_time_count[1] = 0x00; break; case 3: set_time_count[2]++; if((set_time_count[2]&0x0f) >= 0x0a) { set_time_count[2] += 0x10; set_time_count[2] &= 0xf0; } if(set_time_count[2] == 0x60) set_time_count[2] = 0x00; } g = 5;break; case 0x0d: if(flag_S7 == 0) { g = 6; flag_S6++; } break; case 0x0e:if(flag_S6 == 0) { g = 7; flag_S7++; } break; default:g = 0;break; } flag1_but = 2; } else {flag1_but = 0;break;} case 2: if(x == 0x0f) { flag1_but = 0; } break; } } //flag2_but = 0; } //数码管闪烁以及调整时间 void tiao_time() { static uchar cc1 = 0,cc2 = 0; switch(flag_S7) { case 1: if(flag_time <= 1000) { smg_count[0] = 0xff; smg_count[1] = 0xff; } if(flag_time > 1000 && flag_time < 2000) { smg_count[0] = duan[time_count[0]>>4]; smg_count[1] = duan[time_count[0]&0x0f]; } if(flag_time > 2000) flag_time = 0; break; case 2: if(cc1 == 0) { smg_count[0] = duan[time_count[0]>>4]; smg_count[1] = duan[time_count[0]&0x0f]; cc1++; } if(flag_time <= 1000) { smg_count[3] = 0xff; smg_count[4] = 0xff; } if(flag_time > 1000 && flag_time < 2000) { smg_count[3] = duan[time_count[1]>>4]; smg_count[4] = duan[time_count[1]&0x0f]; } if(flag_time > 2000) flag_time = 0; break; case 3: if(cc2 == 0) { smg_count[3] = duan[time_count[1]>>4]; smg_count[4] = duan[time_count[1]&0x0f]; cc2++; } if(flag_time <= 1000) { smg_count[6] = 0xff; smg_count[7] = 0xff; } if(flag_time > 1000 && flag_time < 2000) { smg_count[6] = duan[time_count[2]>>4]; smg_count[7] = duan[time_count[2]&0x0f]; } if(flag_time > 2000) flag_time = 0; break; default: set2_ds1302(time_count[0],time_count[1],time_count[2]); cc1 = cc2 = 0; flag_S7 = 0; } } //进入闹钟程序时闪烁程序 void set_tiao_time() { static uchar cc1 = 0,cc2 = 0; switch(flag_S6) { case 1: if(flag_time <= 1000) { smg_count[0] = 0xff; smg_count[1] = 0xff; } if(flag_time > 1000 && flag_time < 2000) { smg_count[0] = duan[set_time_count[0]>>4]; smg_count[1] = duan[set_time_count[0]&0x0f]; } if(flag_time > 2000) flag_time = 0; break; case 2: if(cc1 == 0) { smg_count[0] = duan[set_time_count[0]>>4]; smg_count[1] = duan[set_time_count[0]&0x0f]; cc1++; } if(flag_time <= 1000) { smg_count[3] = 0xff; smg_count[4] = 0xff; } if(flag_time > 1000 && flag_time < 2000) { smg_count[3] = duan[set_time_count[1]>>4]; smg_count[4] = duan[set_time_count[1]&0x0f]; } if(flag_time > 2000) flag_time = 0; break; case 3: if(cc2 == 0) { smg_count[3] = duan[set_time_count[1]>>4]; smg_count[4] = duan[set_time_count[1]&0x0f]; cc2++; } if(flag_time <= 1000) { smg_count[6] = 0xff; smg_count[7] = 0xff; } if(flag_time > 1000 && flag_time < 2000) { smg_count[6] = duan[set_time_count[2]>>4]; smg_count[7] = duan[set_time_count[2]&0x0f]; } if(flag_time > 2000) flag_time = 0; break; default: //set2_ds1302(time_count[0],time_count[1],time_count[2]); flag_set_time = 0; g = 0; i = 0; cc1 = cc2 = 0; flag_S6 = 0; } } //设置闹钟程序 void alarm_clock() { if(i == 0) { smg_count[0] = duan[set_time_count[0]>>4]; smg_count[1] = duan[set_time_count[0]&0x0f]; smg_count[3] = duan[set_time_count[1]>>4]; smg_count[4] = duan[set_time_count[1]&0x0f]; smg_count[6] = duan[set_time_count[2]>>4]; smg_count[7] = duan[set_time_count[2]&0x0f]; smg_count[2] = smg_count[5] = 0xbf; i++; } set_tiao_time(); } void main() { Timer0Init(); buzz = 0x00; LED = 0xff; set_ds1302(23,59,50); P3 = 0xff; TR0 = 1; while(1) { if(flag_S7 == 0) read_time(); if((set_time_count[0] == time_count[0]) && (set_time_count[1] == time_count[1]) && (set_time_count[2] == time_count[2])) { flag_alarm = 1; flag1_alarm = time_count[2]; } // if(flag_alarm == 1) // { // if((S4 == 0) || (S5 == 0) || (S6 == 0) || (S7 == 0)) // { // flag_alarm = 0; // flag_LED1 = 0; // flag_LED_time = 0; // LED = 0xff; // } // } if(flag_S7 != 0) tiao_time(); while(g == 4 && S4 == 0 && flag_S7 == 0) read_team(); while(g == 6) { flag_set_time = 1; while(flag_set_time) alarm_clock(); } if((flag_alarm == 1) && (flag_LED_time <= 5000)) //(flag_alarm == 1) && ( { if(flag_LED1 <= 20) { LED = 0xfe; } else { LED = 0xff; } } } } //定时器0中断服务函数 void timer0() interrupt 1 { static uchar flag_but = 0; flag_but++; flag_team++; flag_time++; if(flag_alarm == 1) { flag_LED1++; flag_LED_time++; if(flag_LED1 >= 41) { flag_LED1 = 0; } P3 |= 0x0f; if((flag_LED_time >= 5000) || ((P3 &0x0f) != 0x0f)) { flag_alarm = 0; flag_LED1 = 0; flag_LED_time = 0; LED = 0xff; } } if(flag_but == 10) { P3 |= 0x0f; button(); flag_but = 0; } smg_display(); } ``` # 总结 # OK,分享得差不多了,来做个总结吧。这个程序我觉得是我个人一次质的飞跃。为什么呢? 因为这个程序我没有一处用到了延迟程序,这大大得提升了程序的可读性和有效代码的量。这是我很开的一件事。 # 最后,感谢观看。。。。。# 卿枫影院 [1]: https://www.qingfengblog.com/usr/uploads/2020/03/2874033445.png [2]: https://www.qingfengblog.com/usr/uploads/2020/03/517160800.png [3]: https://www.qingfengblog.com/usr/uploads/2020/03/143928055.png Last modification:March 5, 2020 © Reprint prohibited Support Appreciate the author AliPayWeChat Like 0 如果觉得我的文章对你有用,请随意赞赏