最近几天闲着没事干,刷动态的时候,看到了十三届的模拟题,然后就去搜了搜,题目来源@电子设计工坊,我是从博主@slow_walker看到的题目,原blog的链接:https://blog.csdn.net/boybs/article/details/123829667
先看题目吧:
刚看的时候,感觉还是很简单的,没有乱七八糟的显示模式切换,也就用到了eeprom和PCF8591,后来往下仔细看,发现了长按键,我心态直接崩了,虽然之前十二届第二批的时候,做过长按键,但是是在大佬的帮助下,才做出来的,现在要自己做,心里总是害怕,做了三天,到最后还是做出来了,跟之前的第十二届第二批其实是一个思路,利用定时器,使一个数字每1s自加一次,然后再去判断。 但是另外一点我没有想到的是,在题目中,要求按下S8不触发储存功能,这个我思考了好久,其实就是需要引入一个中间变量,把eeprom显示界面的数值,赋值给他就好了,先看源代码吧。
IIC.C
/*
程序说明: IIC总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台 8051,12MHz
日 期: 2011-8-9
*/
//总线引脚定义
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
void IIC_Delay(unsigned char i)
{
do{_nop_();}
while(i--);
}
//总线启动条件
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 0;
}
//总线停止条件
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 1;
IIC_Delay(DELAY_TIME);
}
//发送应答
void IIC_SendAck(bit ackbit)
{
SCL = 0;
SDA = ackbit; // 0:应答,1:非应答
IIC_Delay(DELAY_TIME);
SCL = 1;
IIC_Delay(DELAY_TIME);
SCL = 0;
SDA = 1;
IIC_Delay(DELAY_TIME);
}
//等待应答
bit IIC_WaitAck(void)
{
bit ackbit;
SCL = 1;
IIC_Delay(DELAY_TIME);
ackbit = SDA;
SCL = 0;
IIC_Delay(DELAY_TIME);
return ackbit;
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++)
{
SCL = 0;
IIC_Delay(DELAY_TIME);
if(byt & 0x80) SDA = 1;
else SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 1;
byt <<= 1;
IIC_Delay(DELAY_TIME);
}
SCL = 0;
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char i, da;
for(i=0; i<8; i++)
{
SCL = 1;
IIC_Delay(DELAY_TIME);
da <<= 1;
if(SDA) da |= 1;
SCL = 0;
IIC_Delay(DELAY_TIME);
}
return da;
}
IIC.H
void IIC_Start(void);
void IIC_Stop(void);
bit IIC_WaitAck(void);
void IIC_SendAck(bit ackbit);
void IIC_SendByte(unsigned char byt);
unsigned char IIC_RecByte(void);
MAIN.C
//矩阵按键配置
sbit R1=P3^0;//第一排初始化(如果跳线帽模式是BTN,则只有最左侧一列能用)
sbit R2=P3^1;//第二排初始化
sbit R3=P3^2;//第三排初始化
sbit R4=P3^3;//第四排初始化
sbit C1=P4^4;//第一列初始化
sbit C2=P4^2;//第二列初始化
sbit C3=P3^5;//第三列初始化
sbit C4=P3^4;//第四列初始化
0 1 2 3 4 5 6 7 8 9 - 全灭 .
unsigned char code shuzi[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0xbf,0xff,0x7f};
/// A b C d E F H L P U n
unsigned char code zimu[]={0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89,0xc7,0x8c,0xc1,0xc8};
0 1 2 3 4 5 6 7
unsigned char code weizhi[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00};
// 1 2 3 4 5 6 7 8 灭
unsigned char ledweizhi[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0xff};
uchar count=0;//计数数值
uchar count_z;//长按键判断值
int n;//定时器1的自加值
uchar num_re=0;//保存上一个值
uchar led_b;
uchar mode_led;
uchar temp_num;
void write_eeprom(unsigned char add,unsigned char date);
unsigned char read_eeprom(unsigned char add);
void ledlight(uchar x);
void Init_Keys()//配置矩阵键盘
{
R1=R2=R3=R4=1;
C1=C2=C3=C4=1;
}
void timer0() //定时模式
{
ET0=1;
EA=1;
TMOD &= 0xF0;
TH0 = (65535-50000)/256;//50000us=50ms
TL0 = (65535-50000)%256;
TF0 = 1;
TR0 = 1;
}
void Service_timer0() interrupt 1//定时器0,实现长按键功能
{
TH0 = (65535-50000)/256;//50000us=50ms
TL0 = (65535-50000)%256;
if(n==20)
{
n=0;
count_z++;
}
else n++;
}
//定时器1,定时1ms
void Timer1(void) //定时模式
{
TMOD &= 0x0F;
TL1 = (65535-20000)%256;
TH1 = (65535-20000)/256;
TF1 = 0;
TR1 = 1;
ET1 = 1;
}
void Timer1_Service() interrupt 3//定时器1的定时模式,控制led闪烁
{
uchar i;
i++;
if(i==10)
{
i=0;
led_b++;
if(mode_led==0)
{
mode_led=1;
}
else if(mode_led==1)
{
mode_led=0;
}
}
}
void led_blink()
{
if(mode_led==1)
{
ledlight(1);
}
if(mode_led==0)
{
P2=(P2&0X1f)|0x80;
P0=0xff;
}
}
//延时1ms
void delay_ms(int ms)
{
int q,w;
for(q = 0;q<ms;q++){
for(w=845;w>0;w--);
}
}
void ledlight(uchar x)
{
P2=(P2&0X1f)|0x80;
P0=ledweizhi[x];
}
///数码管数字显示
void shumaguan_shuzi(uchar a,uchar b)
{
delay_ms(1);
P2=(P2&0X1f)|0xC0;P0=weizhi[a];
P2=(P2&0X1f)|0xE0;P0=shuzi[b];
delay_ms(1);
//消隐
P2 = (P2 & 0x1f) | 0xc0;
P0 = 0x00;
P2 = P2 & 0x1f;
}
//数码管字母显示
void shumaguan_zimu(uchar a,uchar b)
{
delay_ms(1);
P2=(P2&0X1f)|0xC0;P0=weizhi[a];
P2=(P2&0X1f)|0xE0;P0=zimu[b];
delay_ms(1);
//消隐
P2 = (P2 & 0x1f) | 0xc0;
P0 = 0x00;
P2 = P2 & 0x1f;
}
void display_count()//计数显示
{
shumaguan_zimu(0,0);
shumaguan_shuzi(5,count/100);
shumaguan_shuzi(6,count%100/10);
shumaguan_shuzi(7,count%10);
ledlight(0);
temp_num=num_re;
}
void display_re()//显示eeprom读取的数据
{
shumaguan_zimu(0,6);
num_re=read_eeprom(0x00);
shumaguan_shuzi(5,num_re/100);
shumaguan_shuzi(6,num_re%100/10);
shumaguan_shuzi(7,num_re%10);
temp_num=num_re;
}
void write_eeprom(unsigned char add,unsigned char date)//写入eepeom数据,前面是地址,后面是数据
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_SendByte(date);
IIC_WaitAck();
IIC_Stop();
}
unsigned char read_eeprom(unsigned char add)//读eeprom,直接写出地址就能读,在read和write之间一定要间隔上delay
{
unsigned char temp;
EA = 0;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
temp = IIC_RecByte();
IIC_SendAck(1);
IIC_WaitAck();
IIC_Stop();
EA = 1;
return temp;
}
void pcf8591_dac(char dat)//dac读取的是16进制数值
{
EA=0;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x40);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
EA=1;
}
void Scan_S4()
{
R4=0;R1=1;R2=1;R3=1;
C2=1;C3=1;C4=1;
if(C1==0&&R4==0)
{
while(C1==0)display_count();
count++;
}
}
void Scan_S5()
{
R4=1;R1=1;R2=1;R3=0;
C2=1;C3=1;C4=1;
if(C1==0&&R3==0)
{
while(C1==0)display_count();
count--;
}
}
void Scan_S8()
{
R4=0;R1=1;R2=1;R3=1;
C1=1;C3=1;C4=1;
if(C2==0&&R4==0)
{
n=0;
count_z=0;
while(C2==0) display_count();
delay_ms(10);
write_eeprom(0x00,count);
delay_ms(10);
while(C2==0)shumaguan_shuzi(0,count_z);
if(count_z>=2)
{
count=0;
delay_ms(10);
write_eeprom(0x00,temp_num);
delay_ms(10);
}
}
}
void Scan_S9()
{
uchar temp=4;
R4=1;R1=1;R2=1;R3=0;
C1=1;C3=1;C4=1;
if(C2==0)
{
while(C2==0);
temp++;
}
if(temp%2==0)
{
display_count();
}
if(temp%2==1)
{
while(1)
{
display_re();
if(C2==0)
{
while(C2==0);
break;
}
}
}
}
void judge()//判断读取的数值大小
{
if(count%5==0)
{
pcf8591_dac(255);
}
else pcf8591_dac(51);
if(count>num_re)
{
TR1=1;
}
else if(count<=num_re)
{
TR1=0;
}
}
void main()
{
Init_Keys();
timer0();
Timer1();
while(1)
{
Scan_S4();
Scan_S5();
Scan_S8();
Scan_S9();
judge();
led_blink();
display_count();
}
}
还有4天比赛了,这几天不打算去做省赛题了,我打算先去看看客观题,客观题毕竟也占好多分。
|