第十三届蓝桥杯赛前的一点总结

Posted 是七喜呀!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十三届蓝桥杯赛前的一点总结相关的知识,希望对你有一定的参考价值。

比赛最主要的实现功能,需要关注各个部分之间的逻辑!

赛前的一点总结

LED

整个工程中LED和数码管,按键部分其实是最主要的部分,往年省赛涉及部分也是相对较多的。

  • 点亮L1
sbit L1 = P0^0;
void led_1()

	P2 = (P2 & 0x1f) | 0x80;
		L1 = 0;

  • L1隔0.1s闪烁
#define uchar unsigned char

sbit L1 = P0^0
bit flag_L1;
void Timer0Init(void);		//50毫秒@12.000MHz

void led_1()

	if (flag_L1)
	
		P2 = (P2 & 0x1f) | 0x80;
		L1 = 0;
	
	else 
	
		P2 = (P2 & 0x1f) | 0x80;
		L1 = 1;
	
	


void timer0() interrupt 1

	static uchar i1;
	if (++i1 == 2)
	
		i1 = 0;
		flag_L1 = !flag_L1;
	

void Timer0Init(void)		//50毫秒@12.000MHz

	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xB0;		//设置定时初值
	TH0 = 0x3C;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	
	ET0 = 1;
	EA = 1;


数码管

  • 注意消隐和小数点处理
#define uchar unsigned char
uchar tab[] = 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff  
//0 ~ 9 数码管熄灭
void Delay1ms();		//1ms@12.000MHz,延时1ms用于给足数码管足够显示时间
void dsp_smg_bit1(uchar pos, val, sta)

	P2 = (P2 & 0x1f) | 0x80;
	P0 = 1 << (pos - 1);
	
	P2 = (P2 & 0x1f) | 0x80;
	if (sta)//小数点
		P0 = tab[val] & 0x7f;
	else
		P0 = tab[val];

	Delay1ms();//给足显示时间
	P0 = 0xff;//消隐
	P2 &= 0x1f;

独立按键

  • 先调到BTN模式

正常处理按键

sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;

void key_handle()
	
	if (!S7)
	
		delay_k(15);//灵敏度更高就消抖时间短一些
		if (!S)
		
			whlie(!S)
				display();
			
			ps:这部分处理按键
		
	
	//跟S7实现一样
	if (!S6)
	....
	if (!S5)
		....
	if (!S4)
		....


长按键功能–规定秒数

  • S7长按时间超过1s判断为长按键,否则为短按
sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
#define uint unsigned int
bit pre_flag;//长按键标志,0为判断时间结束,1为判断开始
uint pre_cnt;//计算按下去多久
//这里利用定时器 定时1ms进入中断(ps:当然你也可以定时其他的时间)
void Timer0Init(void)		//1毫秒@12.000MHz

	...

//中断服务函数
void timer0() interrupt 1

	if (pre_flag)//开始判断
	
		pre_cnt++;
	

void key_handle()
	
	if (!S7)
	
		delay_k(15);//灵敏度更高就消抖时间短一些
		if (!S7)
		
			pre_flag = 1;
			whlie(!S7)
				display();
			pre_flag = 0;
		
			if (pre_cnt > 1000)//大于1s
				...长按键操作
			else 
				...短按键操作

			//还有一点重要的是,清零!
			pre_cnt = 0;
		
	
	//跟S7实现一样
	if (!S6)
	....
	if (!S5)
		....
	if (!S4)
		....

长按键功能–不规定秒数

if (!S7)
	
		delay_k(15);//灵敏度更高就消抖时间短一些
		if (!S7)
		
			if (1 == jm)
			
				...界面1的操作
			
			if (2 == jm)//界面2操作长按为显示其他内容,短按或者按完不按处于其他界面
			
				while(!S7)//长按为显示其他内容
					dsp_other();
			
			whlie(!S7)/短按或者按完不按处于其他界面
				display();
		
	

矩阵按键

  • 模式选择KBD

4 * 4 矩阵按键

#define uchar unsigned char

void key_scanf()

	uchar i;
	P44 = P42 = P35 = P34 = 1;//初始化列线拉高
	for (i = 0; i < 4; i++)
	
		P3 |= 0x0f;//行初始化拉高,列线不变
		P3 &= ~(1 << i);//从上往下依次拉低行线
		
		if (!P44)//该行第一个键
			
			delay_k(20);
			if (!P44)
			
				while(!P44)
				
					display();
				
			
			key_val = 4 * i + 1;
			break;
		
		
		剩下三个键类似
	

void key_handle()

	key_scanf();
	通过key_val做出按键处理


2 * 2 矩阵按键

  1. 与4 * 4类似,对应初始化某两条列线先拉高。
  2. 需要for循环就控制i的初始值,不需要就除了需要判断的那一行拉低,另一行拉高,判断拉低的行的两个按键,对应哪一列为低
四个按键对应于左下角四个键s5 s4 s9 s8
void key_handle()

	P32 = P44 = P42 = 1;
	P33 = 0;
	if (!P44)//s4
	
		delay_k(20);
		if (!P44)
		
			while(!P44)
				display();
			
			对应处理按键操作
		
	

斜按键操作

P34 = 1;
	P33 = 0, P30 = 1, P31 = 1, P32 = 1;//其他行默认低电平,所以我们将其拉高
	if(!P34)//s17
	
		delay_k(10);
		if(!P34)
		
			if (2 == jm)
			
				if (--para_temp < 10)//参数操作 + 参数检查
					para_temp = 10;
			
			if (1 == jm)
			
				while(!P34)//s17的长按键操作
				
					rd_time();
					dsp_min_sec();
				
			
			while(!P34)
			
				display();
					
		
	

NE555频率测量

①NE555频率测量,要把跳线帽接在P34和SIGNAL上,使用完之后记得把跳线帽摘下来,不然就会影响矩阵按键,因为矩阵按键第4列也接在P34上
②改变Rb3可以改变输出的频率值

uint cnt_freq, curr_freq;

void timer0() interrupt 1

	cnt_freq++;

void timer1() interrupt 3

	static uchar i1 = 0;
	if (++i1 == 20)//1s
	
		i1 = 0;
		curr_freq = cnt_freq;
		cnt_freq = 0;
	

void sys_init()

	TMOD = 0x04;		//设置定时器模式,定时器0--计数器模式,定时器1--定时器模式
	TL0 = 0xff;
	TH0 = 0xff;//来一个脉冲就溢出计数一次
	TR0 = 1;
	//50ms
	TL1 = 0xB0;		//设置定时初值
	TH1 = 0x3C;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	
	ET0 = 1;
	ET1 = 1;
	EA = 1;



ADC

通过pcf8591读数据,省赛中一般不会太搞人心态的,记住下方模板即可。

  • 从pcf8591读数据
#define uchar unsigned char
uchar rd_pcf8591(uchar addr)

	uchar da;
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	
	IIC_SendByte(addr);
	IIC_WaitAck();
	
	IIC_Start();
	IIC_SendByte(0x91);
	IIC_WaitAck();
	
	da = IIC_RecByte();
	IIC_SendAck(1);
	IIC_Stop();
	return da;

需要注意的是,由于pcf8591读取电压读取的为上一次的值,当我们连续从某多个通道读取数据时,每次调用时我们需要读取两次,这样才能保证数据的正确性。

#define uchar unsigned char
float v_val;
uchar rd_pcf8591(uchar addr)

	uchar da;
	uchar i;
	for (i = 0; i < 2; i++)
	
		IIC_Start();
		IIC_SendByte(0x90);
		IIC_WaitAck();
		
		IIC_SendByte(addr);
		IIC_WaitAck();
		
		IIC_Start();
		IIC_SendByte(0x91);
		IIC_WaitAck();
		
		da = IIC_RecByte();
		IIC_SendAck(1);
		IIC_Stop();
		
	return da;

//255.0是小数,整个表达式被强制类型转换为浮点数,最后赋值给浮点数v_val
v_val = rd_pcf8591(0x03) * 5 / 255.0;

DAC

切换成为DAC输出模式,允许 DAC, 使用ADC 通道 0,最后注意需要延时5ms

void dac_pcf8591(uchar da)

	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();

	IIC_SendByte(0x40);  //DAC输出模式,允许 DAC, ADC 通道 0
	IIC_WaitAck();

	IIC_SendByte(da);
	IIC_WaitAck();
	IIC_Stop();
	Delay5ms();

eeprom

省赛中一般就是对eeprom进行读写,也都是固定的代码模块,需要留意的是,为了保证一个完整的写入周期,我们需要延时5ms

  • 写eeprom
#define uchar unsigned char
#define uint unsigned int

void write_eeprom(uchar addr, da)

	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	
	IIC_SendByte(addr);
	IIC_WaitAck();
	
	IIC_SendByte(da);
	IIC_WaitAck();
	IIC_Stop();
	Delay5ms();
	
  • 读eeprom
#define uchar unsigned char
#define uint unsigned int
uchar rd_eeprom(uchar addr)	

	uchar da;
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	
	IIC_SendByte(addr);
	IIC_WaitAck();
	
	IIC_Start();
	IIC_SendByte(0xa1);
	IIC_WaitAck();
	
	da = IIC_RecByte();
	IIC_SendAck(1);
	IIC_Stop();
	
	return da;

DS18B20

省赛中一般对温度进行保留小数或者读取整数的操作,也是几乎固定的模板

  • 读取整数
#define uchar unsigned char
uchar rd_temp()

	uchar l, h, t;
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);

	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	
	l = Read_DS18B20();
	h = Read_DS18B20();
	
	t = (h << 4);
	t |= (l >> 4);
	
	return t;

  • 读取带小数的温度
#define uchar unsigned char
#define uint unsigned int
float rd_temp()

	uchar l, h;
	uint t;
	float temp;
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);

	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	
	l = Read_DS18B20();
	h = Read_DS18B20();
	
	t = (h & 0x0f);
	t <<= 8;
	t |= l;
	temp = t * 0.0625;
	
	return temp;


DS1302

省赛中一般仅仅使用秒、分、时,使用过程中主要就是需要注意,由于ds1302芯片存储的数据是BCD码,所以我们要进行BCD码与十进制之间的转换,例如0x16 的BCD码为16,十进制为1 * 16 + 6 = 32。
我个人是将这两者之间的转换放到官方给的底层代码中完成的,这样做的好处就是,我们在main.c中,只需要使用十进制,表示时间即可。

  • 读时间
unsigned char Read_Ds1302_Byte ( unsigned char address )

 	unsigned char i,temp=0x00;
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1;	_nop_();
 	Write_Ds1302(address);
 	for (i=0;i<8;i++) 	
 			
		SCK=0;
		temp>>=1;	
 		if(SDA)
 		temp|=0x80;	
 		SCK=1;
	 
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
	SCK=1;	_nop_();
	SDA=0;	_nop_();
	SDA=1;	_nop_();
	temp = temp / 16 * 10 + temp % 16;
	return (temp);			

  • 写时间
void Write_Ds1302_Byte( uns

以上是关于第十三届蓝桥杯赛前的一点总结的主要内容,如果未能解决你的问题,请参考以下文章

第十三届蓝桥杯赛前的一点总结

《蓝桥杯真题》:2021单片机省赛第二场(第十二届第二场)暨第十三届蓝桥杯赛前模拟试题

《蓝桥杯真题》:2021单片机省赛第二场暨第十三届蓝桥杯赛前模拟试题

第十三届蓝桥杯大赛软件赛省赛 C/C++ 大学 B 组思考+总结

第十三届蓝桥杯 个人经历回顾及经验总结

第十三届蓝桥杯C++ B组 赛后总结&不完全题解