【蓝桥杯|单片机组】| 第八届省赛题-基于单片机的电子钟程序设计与调试分析

2019-04-15 18:04发布

      第八届(17年)整套做下来给我的第一印象就是数码管的操作要求真的高(骚),其与14年的“简易温度采集与控制装置”的数码管操作类似,不过17年的多了一个“选中数码管实现一秒闪烁”的要求。思考了将近一两天的时间(原谅我脑子僵,估计真正比赛的时候就死翘翘了)独创了一个算法,我称之为“数码管同异步扫描”(该名借鉴了异步UART通信与同步IIC通信)废话不多说,直接上图,红圈部分对我来说是个难点。
unsigned char pcom; //选中的数码管标识符 unsigned char num[8]; //LedScan1()与jia间的桥梁 unsigned char jia; //控制数字增减
接下来是“同异步数码管扫描”的核心代码void LedScan() /*异步数码管扫描函数*/ { static unsigned char i; if((pcom==2)|(pcom==5)) pcom++; if((i!=pcom)) //扫描未选中的数码管 { P2&=0X1F; P2|=0XC0; P0=0x01< /*同步数码管扫描函数*/ { static unsigned char j=0; static unsigned char k=0; if(j==pcom) { if((pcom==2)|(pcom==5)) k=1; else k=0;P2&=0X1F; P2|=0XC0;P0=0x01< //扫描选中的数码管“同异步数码管扫描”的核心思想是:建立两个数码管扫描函数,一个扫描选中的数码管,另一个扫描未选中的数码管void InterruptTimer0() interrupt 1 { TH0=(65536 - ((11059200/12)/1000))/256; TL0=(65536 - ((11059200/12)/1000))%256; KeyScan(); LedScan(); //与pcom异步扫描 LedScan1(); //与pcom同步扫描 cnt++; if(cnt>=1000) { cnt=0; if(flag==0) { num[pcom]=LedChar[jia]; //与pcom同步数码管显示 flag=1; } else { num[pcom]=0xff; flag=0; } } LedBuff[pcom]=LedChar[jia]; //保存设置好的数据,1ms快刷,否则切换数码管的时候后一个数码管会保留前一个数码管的数字的 if(pcom==0){if(jia<3){if(jia==2){hourflag=1;g_time[5]=jia;}else{g_time[5]=jia;}}else if(jia==3){jia=0;g_time[5]=jia;}} //解决一下界面且换,进入二级菜单跳到左二数码管的问题,否则hourflag一直为0,判断不了小时的十位为2时,个位超2 if(pcom==1){if(hourflag==1){if(jia==4){jia=0;g_time[4]=jia;}else{g_time[4]=jia;}} else{g_time[4]=jia;}} if(pcom==3) { if(jia<6) g_time[3]=jia; if(jia==6) { jia=0; g_time[3]=jia; } } if(pcom==4){ g_time[2]=jia;} if(pcom==6){ if(jia<6){g_time[1]=jia;}else {jia=0;g_time[1]=jia;}} if(pcom==7){ g_time[0]=jia;} }

以下是完整代码

头文件

display.hunsigned char code LedChar[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf}; //数码管真值表 unsigned char LedBuff[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; unsigned char pcom=0; unsigned char num[8]={0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0}; //数码管切换 void LedScan() /*数码管动态刷新*/ { static unsigned char i; if((pcom==2)|(pcom==5)) pcom++; if((i!=pcom)) { P2&=0X1F; P2|=0XC0; P0=0x01<ds1302.h/* 程序说明: DS1302驱动程序 软件环境: Keil uVision 4.10 硬件环境: CT107单片机综合实训平台 8051,12MHz 日 期: 2011-8-9 */ #include sbit SCK=P1^7; sbit SDA=P2^3; sbit RST = P1^3; // DS1302复位 void Write_Ds1302_Byte(unsigned char temp) { unsigned char i; for (i=0;i<8;i++) { SCK=0; SDA=temp&0x01; temp>>=1; SCK=1; } } void Write_Ds1302( unsigned char address,unsigned char dat ) { RST=0; _nop_(); SCK=0; _nop_(); RST=1; _nop_(); Write_Ds1302_Byte(address); Write_Ds1302_Byte(dat); RST=0; } unsigned char Read_Ds1302 ( unsigned char address ) { unsigned char i,temp=0x00; RST=0; _nop_(); SCK=0; _nop_(); RST=1; _nop_(); Write_Ds1302_Byte(address); for (i=0;i<8;i++) { SCK=0; temp>>=1; if(SDA) temp|=0x80; SCK=1; } RST=0; _nop_(); RST=0; SCK=0; _nop_(); SCK=1; _nop_(); SDA=0; _nop_(); SDA=1; _nop_(); return (temp); } void delay(int n)/*延时函数*/ { char z=110; while(n--) for(z=0;z<110;z++); }

主程序

#include #include #include sfr P4=0XC0; sbit KO1=P3^0; sbit KO2=P3^1; sbit KO3=P3^2; sbit KO4=P3^3; sbit KI1=P3^4; sbit KI2=P3^5; sbit KI3=P4^2; sbit KI4=P4^4; unsigned char ModelSwitch=0; unsigned char FStair=0; //一级菜单标志位 unsigned char SStair=0; //二级菜单标志位 unsigned char KeyCodeMap[4][1]={0x07,0x06,0x05,0x04}; //按键真值表 unsigned char KeySta[4][1]={1,1,1,1}; //按键状态区 unsigned char jia=0; int flag200ms; unsigned char tbackup=0xaa; unsigned char y_time[3]; bit s7flag=0; bit s4start=0; bit flag=1; int cnt=0; bit hourflag=0; unsigned char g_time[6]={0,5,9,5,3,2}; void KeyAction(unsigned char keycode); void KeyDriver(); void set_time(); void show_ds1302(); void close_digital() { P2=(P2&0X1F); P2|=0XC0; P0=0X00; P2&=0X1F; } void main() { ConfigTimer0(); set_time(); while(1) { KeyDriver(); } } void show_ds1302() { LedBuff[0]=LedChar[y_time[2]/16]; LedBuff[1]=LedChar[y_time[2]%16]; LedBuff[2]=0xbf; LedBuff[3]=LedChar[y_time[1]/16]; LedBuff[4]=LedChar[y_time[1]%16]; LedBuff[5]=0xbf; LedBuff[6]=LedChar[y_time[0]/16]; LedBuff[7]=LedChar[y_time[0]%16]; } void set_time() /**/ { unsigned char i=0; Write_Ds1302(0x8e,0x00); Write_Ds1302(0x80,g_time[1]*16+g_time[0]); Write_Ds1302(0x82,g_time[3]*16+g_time[2]); Write_Ds1302(0x84,g_time[5]*16+g_time[4]); Write_Ds1302(0x8e,0x00); } void get_time() /**/ { char i=0; for(i=0;i<3;i++) { y_time[i]=Read_Ds1302(0x81+i*2); delay(30); } } void KeyScan() /*按键扫描,先从第二行开始扫描*/ { static unsigned char keyout=0; static unsigned char keybuf[4][1]={ //检测缓冲区 低四位为0即确定为按下 {0xff},{0xff},{0xff},{0xff} }; /*按下一个按键,需要16ms时间检测一个按键的状态*/ keybuf[keyout][0]=(keybuf[keyout][0]<<1)|KI4; if((keybuf[keyout][0] & 0x0f) ==0) KeySta[keyout][0]=0; else if((keybuf[keyout][0] & 0x0f)==0x0f) KeySta[keyout][0]=1; keyout++; if(keyout>=4) keyout=0; switch(keyout) /*行刷新,4ms一周期*/ { case 0 : KO4=1;KO1=0; break; case 1 : KO1=1;KO2=0; break; case 2 : KO2=1;KO3=0; break; case 3 : KO3=1;KO4=0; break; default:break; } } void KeyDriver() /*按键驱动*/ { unsigned char i; static unsigned char backup[4][1]={1,1,1,1}; for(i=0;i<4;i++) { if(backup[i][0]!=KeySta[i][0]) //按下 backup=1 弹起 backup=0 亮 backup=1 按下 backup=1 不亮 { backup[i][0]=KeySta[i][0]; //放前面才能一按下,就检测到0,变换也是先变换 if(backup[i][0]==0) { KeyAction(KeyCodeMap[i][0]); } } } } void KeyAction(unsigned char keycode) { if(keycode==0x07) { FStair=1; if(s7flag==1) pcom++; else s7flag=1; if(pcom<8) { jia=0; } if(pcom==8) { pcom=0; FStair=0;close_digital(); set_time();s7flag=0; } } if(keycode==0x05) { if(jia<10) jia++; if(jia==10) jia=0; } if(keycode==0x04) { if(jia>0) jia--; } } void InterruptTimer0() interrupt 1 { TH0=(65536 - ((11059200/12)/1000))/256; TL0=(65536 - ((11059200/12)/1000))%256; KeyScan(); if(FStair==1) //一级菜单 { LedScan(); //与pcom异步扫描 LedScan1(); //与pcom同步扫描 cnt++; if(cnt>=1000) { cnt=0; if(flag==0) { num[pcom]=LedChar[jia]; //与pcom同步数码管显示 flag=1; } else { num[pcom]=0xff; flag=0; } } LedBuff[pcom]=LedChar[jia]; //保存设置好的数据,1ms快刷,否则切换数码管的时候后一个数码管会保留前一个数码管的数字的 if(pcom==0){if(jia<3){if(jia==2){hourflag=1;g_time[5]=jia;}else{g_time[5]=jia;}}else if(jia==3){jia=0;g_time[5]=jia;}} //解决一下界面且换,进入二级菜单跳到左二数码管的问题,否则hourflag一直为0,判断不了小时的十位为2时,个位超2 if(pcom==1){if(hourflag==1){if(jia==4){jia=0;g_time[4]=jia;}else{g_time[4]=jia;}} else{g_time[4]=jia;}} if(pcom==3) { if(jia<6) g_time[3]=jia; if(jia==6) { jia=0; g_time[3]=jia; } } if(pcom==4){ g_time[2]=jia;} if(pcom==6){ if(jia<6){g_time[1]=jia;}else {jia=0;g_time[1]=jia;}} if(pcom==7){ g_time[0]=jia;} } else if(FStair==0) //一级菜单 { ds1302scan(); flag200ms++; if(flag200ms>=400) { flag200ms=0; get_time(); if(tbackup!=y_time[0]%16) { tbackup=y_time[0]%16; show_ds1302(); } } } } 最后来张马斯克的“重型猎鹰”来激励自己,“梦想总是值得我们不畏艰险地去追寻“。