【蓝桥杯嵌入式】STM32G431——十四届第一场省赛真题及程序设计代码详解


前言

临近比赛了,最后在写一篇最新的真题来巩固复习一下比赛用的知识,同时也希望最后几天能帮助到小伙伴们,一起努力在比赛中取得好名次。废话不多说,来看真题。

一、题目介绍

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、重难点介绍

1.重难点分析

这届的试题还是有点难度的,主要考查了PWM和定时器的输入捕获,重点在定时器的使用和高低频的切换斜率图得出占空比的数学公式,有点容易让人头脑混乱。但是抓住了其中的本质,还是能够解决的。

三、题解

1、相关定义:

char view=0;
char led=0;
char led2_flag=0;
char fre_flag=0;
char M='L';
float max_h,max_l=0;//
float volt=0.0;
float v=0.0;
uint32_t f=0;
uint8_t lock=0;
uint8_t Num=0;
uint8_t H_flag,L_flag=0;
uint8_t R=1,K=1;
uint8_t R_flag=1,K_flag=0;
uint8_t text[20];
uint16_t P=100;
extern struct keys key[4];
void led_pro();
void lcd_pro(void);
void key_pro(void);

2、LED显示以及处理函数:

void LED_Disp(char dsLED)
{
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);//让所有GPIOC置高电平,灯泡熄灭。
	HAL_GPIO_WritePin(GPIOC,dsLED<<8,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}

void led_pro()
{
	if(view==0)
	{
		led|=1;
	}
	else if(view==1||view==2)
	{
		led&=~1;
	}
	if(fre_flag==1&&led2_flag==1)
	{
		led^=2;
	}
	else if(fre_flag==0)
	{
		led&=~(1<<1);
	}
	if(lock==1)
	{
		led|=1<<2;
	}
	else if(lock==0)
	{
		led&=~(1<<2);
	}
}

3、按键扫描以及处理函数:

//定义
struct keys key[4]={0,0,0};
struct keys
{
	char judge_sta;
	bool key_sta;
	bool single_flag;
	bool long_flag;
	uint8_t key_time;
};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM16)
	{
		key[0].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
		key[1].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
		key[2].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
		key[3].key_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
		
		for(int i=0;i<4;i++)
		{
		switch (key[i].judge_sta)
		{
			case 0:
			{
				if(key[i].key_sta==0)
				{
				key[i].judge_sta=1;
				key[i].key_time=0;	
				} 
			}
			break;
			case 1:
			{
			if(key[i].key_sta==0)
			{
			key[i].judge_sta=2;
			
			}
			}
			break;
			case 2:
			{
				if(key[i].key_sta==1)
				{
				key[i].judge_sta=0;
				if(key[i].key_time<200)
				{
				key[i].single_flag=1;
				}
				}
				else{
				key[i].key_time++;
				if(key[i].key_time>200)
				{
				key[i].long_flag=1;
				}				
				} 
			}
			break;
		}
		}
	}
}

//处理函数
void key_pro(void)
{
	if(key[0].single_flag==1)
	{
		view++;
		if(view>2)
		{
			view=0;
		}
		LCD_Clear(Black);
		key[0].single_flag=0;
	}
	if(key[1].single_flag==1)
	{
		if(view==0&&fre_flag==0)
		{
			fre_flag=1;
			Num++;
		}
		if(view==1)
		{
			if(R_flag==1)
			{
				R_flag=0;
				K_flag=1;
			}
			else
			{
				R_flag=1;
				K_flag=0;
			}	
		}
		key[1].single_flag=0;	
	}
	if(key[2].single_flag==1)
	{
		if(R_flag==1)
		{
			R++;
			if(R>10)
			{
				R=1;
			}
		}
		if(K_flag==1)
		{
			K++;
			if(K>10)
			{
				K=1;
			}
		}
		key[2].single_flag=0;
	}
	if(key[3].single_flag==1)
	{
		if(view==0)
		{
			lock=0;
		}
		if(view==1)
		{
			if(R_flag==1)
			{
				R--;
				if(R<1)
				{
					R=10;
				}
			}
			if(K_flag==1)
			{
				K--;
				if(K==0)
				{
					K=10;
				}
			}
		}
		key[3].single_flag=0;
	}
	if(key[3].long_flag==1)
	{
		lock=1;
		key[3].long_flag=0;
		
	}
}

4、LCD处理函数:

void lcd_pro(void)
{
	if(view==0)
	{
		sprintf((char *)text,"        DATA");
		LCD_DisplayStringLine(Line2,text);
		sprintf((char *)text,"     M=%c",M);
		LCD_DisplayStringLine(Line4,text);
		sprintf((char *)text,"     P=%d%%",P);
		LCD_DisplayStringLine(Line5,text);
		sprintf((char *)text,"     V=%.1f",v);
		LCD_DisplayStringLine(Line6,text);
		sprintf((char *)text,"     V=%d",f);
		LCD_DisplayStringLine(Line8,text);
		
	}
	if(view==1)
	{
		sprintf((char *)text,"        PARA");
		LCD_DisplayStringLine(Line2,text);
		sprintf((char *)text,"     R=%d ",R);
		LCD_DisplayStringLine(Line4,text);
		sprintf((char *)text,"     K=%d ",K);
		LCD_DisplayStringLine(Line5,text);	
	}
	//´¦ÓÚͳ¼Æ½çÃæÊ±
		if(view==2)
	{
		sprintf((char *)text,"        RECT");
		LCD_DisplayStringLine(Line2,text);
		sprintf((char *)text,"     N=%d",Num);
		LCD_DisplayStringLine(Line4,text);
		sprintf((char *)text,"     MH=%.1f",max_h);
		LCD_DisplayStringLine(Line5,text);
		sprintf((char *)text,"     ML=%.1f",max_l);
		LCD_DisplayStringLine(Line6,text);			
	}
}

5、PWM捕获以及高低频切换处理函数:

//定义
uint8_t led2_cnt=0;
uint32_t fre_cnt=0;//切换低频到高频的计数值 记到500就是5秒
uint16_t fre=999;//频率为4khz的重装值
uint32_t ccrval=0;//定时器输入捕获值

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM17)
	{
		ccrval=HAL_TIM_ReadCapturedValue(&htim17,TIM_CHANNEL_1);
		//用于计数器清零 为下次捕获做好准备
		__HAL_TIM_SetCounter(&htim17,0);
		f=(80000000/80)/(ccrval+1);
		//为这个重新开启定时器输入捕获
		HAL_TIM_IC_Start(&htim17,TIM_CHANNEL_1);
	}
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM3)
	{
		if(fre_flag == 1)   //高低频模式切换,5秒钟内保证占空比不变,频率每10ms加减一
		{                   //500次刚好完成高低频模式切换需要改变的自动重装载值
			if(fre_cnt++>500)
			{
				fre_flag = 0;
				fre_cnt = 0;
				if(M == 'L')
						M = 'H';
					else 
						M = 'L';
			}
			else
			{
				if(M == 'L')
				{
					fre--;
					__HAL_TIM_SET_AUTORELOAD(&htim2,fre);
				}
				else
				{
					fre++;
					__HAL_TIM_SET_AUTORELOAD(&htim2,fre);
				}
			}
			if(led2_cnt++>10)
			{
				led2_flag=1;
				led2_cnt=0;
			}
		}
	}
}

6、获取ADC函数:

//通过adc值来获取电压值 使R37调整电位器
float getADC(ADC_HandleTypeDef *pin)
{
	uint16_t adc;
	HAL_ADC_Start(pin);
	adc = HAL_ADC_GetValue(pin);
	return adc*3.3/4096;
}

7、主函数:

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_TIM4_Init();
  MX_ADC2_Init();
  MX_TIM17_Init();
  MX_TIM16_Init();
  /* USER CODE BEGIN 2 */
	LED_Disp(0x00);
	LCD_Init();
	LCD_Clear(Black);
	LCD_SetBackColor(Black);
	LCD_SetTextColor(White);
	HAL_TIM_Base_Start_IT(&htim16);
	HAL_TIM_Base_Start_IT(&htim3);
	HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
	HAL_TIM_IC_Start_IT(&htim17,TIM_CHANNEL_1);
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		
		volt=getADC(&hadc2);
		v=(f*2*R*3.14f)/(100*K);
		led_pro();
		key_pro();
		lcd_pro();
		InferDuty();
		InferFre();
		LED_Disp(led);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

总结

最后题目就讲解到这里了,因为这次事件比较赶,没有像以往一样写注释和更深入分析了,希望小伙伴们多多见谅,如果有需要的话可以看看最后的源码,最后祝愿小伙伴们在后天的比赛都能取得理想的名次。

源码:

链接:https://pan.baidu.com/s/1PobayhziKU4czu9uCa6oMA?pwd=3rkb
提取码:3rkb
–来自百度网盘超级会员V3的分享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

嵌入式-小博

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

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

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

打赏作者

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

抵扣说明:

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

余额充值