第八届(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();
}
}
}
}
最后来张马斯克的“重型猎鹰”来激励自己,“梦想总是值得我们不畏艰险地去追寻“。