第十一届蓝桥杯嵌入式省赛题准备经历及源码详解

第十一届蓝桥杯嵌入式省赛题

准备经历

从今年的寒假疫情在家开始准备蓝桥杯,一边写驱动程序,一边准备考研,后来驱动成熟了,开始做各届的模拟题省赛题。因为由于考研的原因,到大四就没有那么长时间准备了,所以当得知比赛推迟举办的时候,其实心里是不开心的。后来第一次省赛疫情原因学校没有组织比赛,就只能参加第二次省赛了。想想一路走来,虽然过程曲折,但是还是获得了比较满意的结果。最重要的是对STM32的理解更深了。
在这里插入图片描述

比赛感受

比赛还是五小时,从上午九点到下午两点,(比软件类多一小时,呜呜呜呜),总结一句话,编程两小时,仿真三小时。
比赛完,食堂都没饭了,为了不打扰舍友考研休息,我在阳台吃着泡面聊天搜着客观题答案,搜完觉得省一应该差不多了。编程题决定你获不获奖,客观题决定你能不能拿省一。废话不多说上题。
第十一届嵌入式省赛题
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

功能分析

本次省赛用到的模块不是很多,不过都是属于经典要考的内容。LED灯点亮,KEY按键控制,定时器双通道输出PWM,ADC模拟电压。以及界面显示等。总体来说初始化函数不难写。

源码分析

声明:为比赛上交文件方便原因,我把初始化程序和功能函数全写在Main.c里,就为了最后不会漏交文件,但这不是一个好习惯,在平时做项目时候建议大家文件模块化,条理更加清晰。
变量定义

#include "stm32f10x.h"
#include "lcd.h"
#include "stdio.h"

#define KEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define KEY2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)
#define KEY3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)
#define KEY4 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2)

u32 TimingDelay = 0;

//****定时器变量******//
u16 TIM3_CH1_Fre;
u16 TIM3_CH1_Duty;
u8	TIM3_CH1_Flag=0;

u16 TIM3_CH2_Fre;
u16 TIM3_CH2_Duty;
u8	TIM3_CH2_Flag=0;
//*******************//

void Delay_Ms(u32 nTime);

void LED_Init(void);
void KEY_Init(void);
void ADC1_Init(void);
void PWM3_OUT(u16 Frequency1,u8 Duty1,u16 Frequency2,u8 Duty2);

void KEY_Read(void);
float ADC_Read(void);

u8 zhankong1=10;//占空比10
u8 zhankong2=10;//占空比10

u8 biankong1=10;
u8 biankong2=10;



u8 Set_Flag=0;//界面跳转标志
u8 Control_Flag;//模式跳转标志

//******中断标志变量*********//
u8 KEY_Flag=0;
u8 ADC_Flag=0;
u8 Display_Flag;
u8 LED_Flag=0;
u8 Time_Flag=0;
//**************************//

int ADC_PWM;

float temp;//电压值
u8 string[20];

模块初始化
初始化很常规了,注意PWM使用比较输出。

void LED_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin=0xff00;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOC,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOD,&GPIO_InitStructure);
	
	GPIOC->ODR=0xff00;
	GPIOD->ODR|=(1<<2);
	GPIOD->ODR&=~(1<<2);
}
void KEY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
}

void ADC1_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_ADC1,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  	ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  	ADC_InitStructure.ADC_NbrOfChannel = 1;
  	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_55Cycles5);
	ADC_Cmd(ADC1, ENABLE);
	ADC_ResetCalibration(ADC1);
  	while(ADC_GetResetCalibrationStatus(ADC1));
  	ADC_StartCalibration(ADC1);
  	while(ADC_GetCalibrationStatus(ADC1));
}

float ADC_Read(void)
{
	float temp;
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	Delay_Ms(5);
	temp=ADC_GetConversionValue(ADC1)*3.3/0xfff;
	return temp;
}

void PWM3_OUT(u16 Frequency1,u8 Duty1,u16 Frequency2,u8 Duty2)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_TimeBaseInitStructure.TIM_Period=0xffff;
	TIM_TimeBaseInitStructure.TIM_Prescaler=71;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=0x0;
	TIM_TimeBaseInitStructure.TIM_CounterMode=0x0;
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
	
	
	
	
	TIM3_CH1_Fre=1000000/Frequency1;
	TIM3_CH1_Duty=TIM3_CH1_Fre*Duty1/100;
	
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
	TIM_OCInitStructure.TIM_Pulse=TIM3_CH1_Fre;
	
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	
	TIM_OC1Init(TIM3,&TIM_OCInitStructure);
	
	TIM3_CH2_Fre=1000000/Frequency2;
	TIM3_CH2_Duty=TIM3_CH2_Fre*Duty2/100;
	
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
	TIM_OCInitStructure.TIM_Pulse=TIM3_CH2_Fre;
	
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	
	TIM_OC2Init(TIM3,&TIM_OCInitStructure);
	
	
	TIM_Cmd(TIM3,ENABLE);	
	TIM_ITConfig(TIM3,TIM_IT_CC1|TIM_IT_CC2,ENABLE);
	
	
	
}

按键控制部分
这个按键程序进行了消抖处理。

void KEY_Read(void)
{
	static u8 KEY1_Num=0,KEY2_Num=0,KEY3_Num=0,KEY4_Num=0;
	
	if(KEY1==0)
	{
		KEY1_Num++;
		if(KEY1_Num==1)
		{
			Set_Flag^=1;
			LCD_ClearLine(Line1);
			LCD_ClearLine(Line3);
			LCD_ClearLine(Line5);
		}
	}else{
		KEY1_Num=0;
	}
	if(KEY2==0)
	{
		KEY2_Num++;
		if(KEY2_Num==1)
		{
			if(Set_Flag==1)
			{
				biankong1+=10;//PA6占空比手动模式+10
				if(biankong1>90)
				{
					biankong1=10;
				}
			}
		}
	}else{
		KEY2_Num=0;
	}
	if(KEY3==0)
	{
		KEY3_Num++;
		if(KEY3_Num==1)
		{
			if(Set_Flag==1)
			{
				biankong2+=10;//PA7占空比手动模式+10
				if(biankong2>90)
				{
					biankong2=10;
				}
			}
		}
	}else{
		KEY3_Num=0;
	}
	if(KEY4==0)
	{
		KEY4_Num++;
		if(KEY4_Num==1)
		{
			if(Control_Flag==0)
			{
				Control_Flag=1;
			}else if(Control_Flag==1)
			{
				Control_Flag=0;
			}
		}
	}else{
		KEY4_Num=0;
	}
}

中断函数

#include "stm32f10x_it.h"

extern u32 TimingDelay;
extern u8 KEY_Flag;
extern u8 ADC_Flag;
extern u8 Display_Flag;
extern u8 LED_Flag;
extern u8 Time_Flag;
void SysTick_Handler(void)
{
	static u8 Key_Num=0;
	static u16 ADC_Num=0;
	static u8 Display_Num=0;
	static u16 LED_Num=0;
	static u16 Time_Num=0;
	TimingDelay--;
	
	if(++Key_Num==50)
	{
		Key_Num=0;
		KEY_Flag=1;
	}
	if(++ADC_Num==50)
	{
		ADC_Num=0;
		ADC_Flag=1;
	}
	if(++Display_Num==50)
	{	
		Display_Num=0;
		Display_Flag=1;
	
	}
	if(++LED_Num==1000)
	{
		LED_Num=900;
		LED_Flag=1;
	}
	if(++Time_Num==500)
	{
		Time_Num=0;
		Time_Flag=1;
	}
}

void TIM3_IRQHandler(void)
{
	u16 capture1;
	u16 capture2;
	if(TIM_GetITStatus(TIM3,TIM_IT_CC1)==1)
	{
		TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);
		capture1=TIM_GetCapture1(TIM3);
		if(TIM3_CH1_Flag==1)
		{
			TIM_SetCompare1(TIM3,capture1+TIM3_CH1_Duty);
		}
		if(TIM3_CH1_Flag==0)
		{
			TIM_SetCompare1(TIM3,capture1+TIM3_CH1_Fre-TIM3_CH1_Duty);
		}
		TIM3_CH1_Flag^=1;
	}
	
	if(TIM_GetITStatus(TIM3,TIM_IT_CC2)==1)
	{
		TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);
		capture2=TIM_GetCapture2(TIM3);
		if(TIM3_CH2_Flag==1)
		{
			TIM_SetCompare2(TIM3,capture2+TIM3_CH2_Duty);
		}
		if(TIM3_CH2_Flag==0)
		{
			TIM_SetCompare2(TIM3,capture2+TIM3_CH2_Fre-TIM3_CH2_Duty);
		}
		TIM3_CH2_Flag^=1;
	}


}

主程序

//Main Body
int main(void)
{

	STM3210B_LCD_Init();
	LCD_Clear(Black);
	LCD_SetBackColor(Black);
	LCD_SetTextColor(White);
	SysTick_Config(SystemCoreClock/1000);
	LED_Init();
	KEY_Init();
	ADC1_Init();
	PWM3_OUT(10000,zhankong1,5000,zhankong2);

	
	
	while(1)
	{
		if(Display_Flag)
		{
			if(Set_Flag==0)
			{
				sprintf((char*)string,"      Data");
				LCD_DisplayStringLine(Line1,string);
				sprintf((char*)string,"    V:%.2fV",temp);
				LCD_DisplayStringLine(Line3,string);
				if(Control_Flag==0)
				{
					sprintf((char*)string,"    Mode:AUTO");
				}else if(Control_Flag==1)
				{
					sprintf((char*)string,"    Mode:MANU");
				}
				LCD_DisplayStringLine(Line5,string);
			}
			if(Set_Flag==1)
			{
				sprintf((char*)string,"      Para");
				LCD_DisplayStringLine(Line1,string);
				sprintf((char*)string,"    PA6:%d%%",biankong1);
				LCD_DisplayStringLine(Line3,string);
				sprintf((char*)string,"    PA7:%d%%",biankong2);
				LCD_DisplayStringLine(Line5,string);
			}
			
		}
		if(ADC_Flag)
		{
			ADC_Flag=0;
			temp=ADC_Read();
			ADC_PWM=temp/3.3*100;	//	得到自动模式下的PWM占空比


		}
		if(Time_Flag)
		{
			Time_Flag=0;
			if(Control_Flag==0)
			{
				PWM3_OUT(10000,ADC_PWM,5000,ADC_PWM);
				if(temp==3.30)
				{
					PWM3_OUT(10000,100,5000,100);
				}
				if(temp==0)
				{
					PWM3_OUT(10000,0,5000,0);
				}
			}else if(Control_Flag==1)
			{
				PWM3_OUT(10000,biankong1,5000,biankong2);
			}
		}
		if(KEY_Flag)
		{
			KEY_Flag=0;
			KEY_Read();
		}
		if(LED_Flag)
		{
			LED_Flag=0;
			if(Control_Flag==0)
			{
				GPIOC->ODR^=(1<<8);
				GPIOC->ODR|=(1<<9);
				GPIOD->ODR|=(1<<2);
				GPIOD->ODR&=~(1<<2);
			}else if(Control_Flag==1)
			{
				GPIOC->ODR|=(1<<8);
				GPIOC->ODR^=(1<<9);
				GPIOD->ODR|=(1<<2);
				GPIOD->ODR&=~(1<<2);
			}

		}
		
	}
}

赛后总结

总的来说本次省赛题目考的模块相对来说不难,没有考到I2C问题,也没考到输入捕获。具体I2C细节处理请看我的另一篇文章I2C细节设置。所以想拿奖不难,想拿省一的小伙伴们需要加油把客观题练好叭。最后特别感谢一位CSDN博主嵌入式飞哥感谢他写的那么棒的博客,清晰地代码风格帮助了我蓝桥杯比赛的学习。

  • 13
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

草莓味的徐大力

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值