【提分必看!】蓝桥杯单片机提分技巧(国一经验分享)

前言

本人在(2024年)第十五届蓝桥杯竞赛单片机赛道中取得了全国一等奖的成绩。本文我将会和读者们分享蓝桥杯单片机竞赛可能会用到的提分技巧,帮读者们叩开国一的大门!
官方资料获取(已整合):
蓝桥杯单片机资源包(含指导手册和考点大纲)
优质教程推荐:
蚂蚁工厂科技蓝桥杯单片机教程
小蜜蜂蓝桥杯单片机基础技能与进阶强化教程
其他相关文章:
【国一超全代码分享!】蓝桥杯单片机各模块代码整合

PCA可编程计数器阵列

IAP15F2K61S2单片机只有定时器0、定时器1和定时器2三个定时器,有时我们会遇到定时器资源不够用的情况:NE555频率测量占用了定时器0,超声波测距占用了定时器1,定时器2用作了串口波特率发生器。这时我们会发现没有定时器进行周期计数为我们的业务逻辑提供(周期)中断服务。为了解决这个问题,我们要启动单片机中的PCA模块。

这里简单介绍一下PCA:
PCA(可编程计数器阵列Programmable Counter Array)有5个16位的捕获/比较模块与之相连,由高字节(PCA0H)和低字节(PCA0L)组成。
在这里我们只需要知道:PCA可以充当16位重装载的“定时器”使用

PCA_Timer.c

// PCA初始化
void PCA_TimerInit(void)
{
	// 这些只能背!
	CMOD |= 0x01;//初始化为系统时钟12分频 允许CCON中的CF中断
	CCON &= 0x00;// CF=0;CR=0;

	CL=0x18;
	CH=0xFC;  // 这里的值根据需要的定时时间手动设置
	CR=1;// 开启计数
}

//中断回调函数
void PCA_isr() interrupt 7
{
	if(CF)
	{
		CF=0;// 需要手动(软件)清零溢出标志位
		CL=0x18;// 需要手动重装载,定时器是自动重装载
		CH=0xFC;// 需要手动重装载,定时器是自动重装载
		
		// 下面添加自己的代码
	}
}

PCA_Timer.h

#include "STC15F2K60S2.H"

void PCA_TimerInit(void);

按照以上操作,我们就可以把PCA当做定时器来用,这样就可以很大程度上解决编程过程中“定时器不够用”的问题。

按键状态检测

按键的底层代码参考:【国一超全代码分享!】蓝桥杯单片机各模块代码整合

// 声明四种状态
unsigned char Key_Value;  // 按键当前状态,0为低电平,1为高电平
unsigned char Key_Down;  // 下降沿
unsigned char Key_Up;  // 上升沿
unsigned char Key_Old;  // 按键的上一状态,0为低电平,1为高电平

//
Key_Value = Read_KBD();  // 读取按键当前状态(这里KBD对应矩阵键盘)
Key_Down = Key_Value&(Key_Old^Key_Value);
Key_Up = ~Key_Value&(Key_Old^Key_Value);
Key_Old = Key_Value;

两种计时按键

近两年赛题都会涉及到按键长短按的考点,下面提供一个写法给大家。

// 注意tick和flag,最好都创建独立的,避免冲突
// 按下按键超过时间,LED直接亮
// Key_Value:检测按键保持高电平或低电平
// Key_Up:检测按键上升沿(即按下到松开的那一瞬间)
if(Key_Value==4 && led1_flag==0)
{
	if(led1_tick++>2000)
	{
		led1_tick=0;
		led1_flag=1;
		ucLed^=0xF0;
	}
}
else
{
	if(led1_flag==0)  led1_tick=0;
	else if(led1_flag==1 && Key_Up==4)  led1_flag=0;
}

// 按下按键超过时间,松开了按键,LED才亮
if(Key_Value==5 && led2_flag==0)
{
	if(led2_tick++>2000)
	{
		led2_tick=0;
		led2_flag=1;
	}
}
else
{
	if(led2_flag==0)  led2_tick=0;
	else if(led2_flag==1 && Key_Up==5)  
	{
		led2_flag=0;
		ucLed^=0xF0;
	}
}

PWM输出逻辑

十三届国赛真题(如果没有记错的话)出了一次PWM输出的考点,要求某个引脚输出频率为1kHz,占空比为20%的PWM信号。之后大家在做到这道题的时候会发现,输出PWM信号并不难,但是输出PWM的代码一旦没写好,就很容易影响到其他模块(比如影响到温度读取或者时钟显示等)。以下是我的处理方法,通过这种处理能正常输出PWM信号,也可以不影响其他模块的正常使用。

if(pwm_flag==1)
{
	pp2_flag=0;
	if(pwm_tick<8)
	{
		if(pp1_flag==0)
		{
			pp1_flag=1;
			P0|=0x20;
			P2=P2&0x1F|0xA0;
			P2=P2&0x1F;
		}
	}
	else
	{
		if(pp1_flag==1)
		{
			pp1_flag=0;
			P0|=0x00;
			P2=P2&0x1F|0xA0;
			P2=P2&0x1F;
		}

	}
	if(++pwm_tick==10)  pwm_tick=0;
}
else if(pwm_flag==0)
{
	pp1_flag=0;
	if(pwm_tick<2)
	{
		if(pp2_flag==0)
		{
			pp2_flag=1;
			P0|=0x20;
			P2=P2&0x1F|0xA0;
			P2=P2&0x1F;
		}
	}
	else
	{
		if(pp2_flag==1)
		{
			pp2_flag=0;
			P0|=0x00;
			P2=P2&0x1F|0xA0;
			P2=P2&0x1F;
		}
	}
	if(++pwm_tick==10)  pwm_tick=0;
}

外部中断(以外中断0为例)

// 外部中断(这两句要写在main中)
IT0 = 0;                    //设置INT0的中断类型 (1:仅下降沿 0:上升沿和下降沿)
EX0 = 1;                    //使能INT0中断

//-----------------------------------------
//中断服务程序
void exint0() interrupt 0       //INT0中断入口 INT0对应的应该是按键S5
{
	// 下面写要执行的任务
    ucLed ^= 0xff;
}

数码管闪烁

sprintf(seg_string,"P1    %2d"(unsigned int)dist);
if(shan_tick<2)  // 200ms亮灭闪烁
{
	seg_string[6]=' ';
	seg_string[7]=' ';
}
if(++shan_tick==4)  shan_tick=0;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值