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

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

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 (!S7)
		{
			whlie(!S7)
				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)//s16
	{
		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);
	while(!DQ);
	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( unsigned char address,unsigned char dat )     
{
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1; 	_nop_();  
 	Write_Ds1302(address);
 	dat = dat / 10 * 16 + dat % 10;	
 	Write_Ds1302(dat);		
 	RST=0; 
}
  • main.c中初始化与读取时间
uchar init_time[] = {45, 59, 23};
uchar time[3] = { 0};
void time_init()
{
	Write_Ds1302_Byte(0x8e, 0);
	Write_Ds1302_Byte(0x80, init_time[0]);
	Write_Ds1302_Byte(0x82, init_time[1]);
	Write_Ds1302_Byte(0x84, init_time[2]);
	Write_Ds1302_Byte(0x8e, 80);//注意这个地方写80,而不是0x80,因为我们在底层代码中完成十进制转BCD码操作
}
void rd_time()
{
	time[0] = Read_Ds1302_Byte(0x81);
	time[1] = Read_Ds1302_Byte(0x83);
	time[2] = Read_Ds1302_Byte(0x85);
}

数据处理

在C语言中,浮点数 可以直接跟uint,uchar直接比较,在C语言内部会将这些类型都给强制类型转换为 同一类型。

float curr_temp = 25.6;
uchar temp_para = 25;
if (curr_temp > temp_para )
{
	对应处理操作
}
else 
{
	对应处理操作
}

头文件修改

官方给iic.h、onewire.h、ds1302.h中使用的时C51的头件"reg52.h",我们需修改为对应的15系列头文件"STC15F2K60S2.h",这样才可以使用一些特殊位寄存器。

底层代码修改

需修改驱动代码onewire.c中单总线延时函数,官方给我们是STC89C52RC系列,15系列的单片机速度比51快8~12倍,需要修改对应的延时函数。修改如下:

void Delay_OneWire(unsigned int t)
{
	char i;
	while(t--)
	for (i = 0; i < 12; i++);
}

最后祝大家都能取得理想的成绩!!!

  • 13
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
以下是一份可能的蓝桥杯赛前训练计划: 1. 熟悉考试内容和题型:了解蓝桥杯考试的内容和题型,包括编程语言、数据结构与算法、计算机基础知识和实践能力等方面的内容,并准备相关资料和练习题目。 2. 制定学习计划:根据自己的水平和时间安排,制定一份具体的学习计划,包括每天的学习目标、练习时间和计划完成时间等,以保证充分利用时间进行学习和练习。 3. 提高编程能力:进行编程练习,提高编程能力,特别是数据结构和算法的实践能力。可以参加在线编程竞赛、练习题目和刷题等方式来提高编程能力。 4. 提高计算机基础知识:学习计算机基础知识,包括计算机组成原理、操作系统、计算机网络、数据库等方面的知识,以提高程序的效率和优化能力。 5. 实践能力:进行实践练习,包括操作系统和网络配置、数据库设计和开发、Web开发等方面的实践,以提高实践能力和解决问题的能力。 6. 团队协作:参加团队协作项目,锻炼团队合作和沟通能力,同时学习项目管理和软件开发流程等相关知识。 7. 模拟考试:进行模拟考试,以检验自己的学习成果和考试准备情况,同时找出自己的弱点和不足,加以改进和提高。 8. 调整状态:保持良好的身体状态和心态,保证充足的睡眠和饮食,调整好心态,保持积极向上的心态。 以上是一份可能的蓝桥杯赛前训练计划,具体的训练计划需要根据个人情况和水平来制定。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值