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

      第八届(17年)整套做下来给我的第一印象就是数码管的操作要求真的高(骚),其与14年的“简易温度采集与控制装置”的数码管操作类似,不过17年的多了一个“选中数码管实现一秒闪烁”的要求。思考了将近一两天的时间(原谅我脑子僵,估计真正比赛的时候就死翘翘了)独创了一个算法,我称之为“数码管同异步扫描”(该名借鉴了异步UART通信与同步IIC通信)

废话不多说,直接上图,红圈部分对我来说是个难点。

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

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.h

unsigned 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();
	  }


	}


}

}







最后来张马斯克的“重型猎鹰”来激励自己,“梦想总是值得我们不畏艰险地去追寻“。


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

你可能感兴趣的:(蓝桥杯,单片机)