蓝桥杯单片机第十三届省赛模拟冲刺02——源码及设计思路

最近几天闲着没事干,刷动态的时候,看到了十三届的模拟题,然后就去搜了搜,题目来源@电子设计工坊,我是从博主@slow_walker看到的题目,原blog的链接:https://blog.csdn.net/boybs/article/details/123829667

先看题目吧:
蓝桥杯单片机第十三届省赛模拟冲刺02——源码及设计思路_第1张图片

蓝桥杯单片机第十三届省赛模拟冲刺02——源码及设计思路_第2张图片
蓝桥杯单片机第十三届省赛模拟冲刺02——源码及设计思路_第3张图片

刚看的时候,感觉还是很简单的,没有乱七八糟的显示模式切换,也就用到了eeprom和PCF8591,后来往下仔细看,发现了长按键,我心态直接崩了,虽然之前十二届第二批的时候,做过长按键,但是是在大佬的帮助下,才做出来的,现在要自己做,心里总是害怕,做了三天,到最后还是做出来了,跟之前的第十二届第二批其实是一个思路,利用定时器,使一个数字每1s自加一次,然后再去判断。
但是另外一点我没有想到的是,在题目中,要求按下S8不触发储存功能,这个我思考了好久,其实就是需要引入一个中间变量,把eeprom显示界面的数值,赋值给他就好了,先看源代码吧。

IIC.C

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include "reg52.h"
#include "intrins.h"

#define DELAY_TIME 5

#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

//总线引脚定义
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

#ifndef _IIC_H
#define _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); 

#endif

MAIN.C

#include
#include
#include

#define uchar unsigned char 

//矩阵按键配置
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天比赛了,这几天不打算去做省赛题了,我打算先去看看客观题,客观题毕竟也占好多分。

你可能感兴趣的:(蓝桥杯单片机学习,单片机,蓝桥杯,嵌入式硬件)