一.题目分析

(1).题目

 (2).题目分析

1.PWM输出分析

模式切换时,占空比要不变, 在五秒之内就要变化成目标频率,同时要求频率的步进值要小于200hz

为了使步进值小于200hz,那么在五秒的时间之内,每次变换200hz,则要变换大于20次,但要取整数,只能让次数等于25次,因此符合要求的是在五秒时间之内,每次变换160hz,计算如下

因此最终是每200ms/160hz/次

2.按键功能分析 

a. B1完成界面的切换

b. B2, 数据界面下,切换低高频模式,5秒内不可再次触发。在参数界面按下切换R和K,退出参数界面就生效。

c. B3调整参数加1

d. B4在参数界面调整参数减1。在数据界面,长按B4,锁定占空比不受R37电位器输出电压的控制,短按B4,解锁R37输出电压对占空比的控制。

长短按的判断方式

当按键按下,开始计时,松开按键时,判断这一过程持续了多久,小于两秒是短按,大于两秒是长按。

 3.统计功能分析 

高频低频输出模式下的最大速度分开统计,保持时间不足2秒的速度值不纳入统计:

定义两个数值,当前速度(Vn)和之前速度(Vf),每读一次速度值就记录到当前速度,同时将上一次的速度保存到之前速度值里,当读到当前速度和之前速度相等时,开始计时,当两秒达到,就把当前的数值保存到最大值里,然后重复之前的操作,并且不断更新最大值,最终找到真正的最大值 

 4.pwm输出功能分析 

分析电压值和占空比的线性关系

(3).逻辑导图

二.CubeMX配置

由于蓝桥杯使用的板子都是STM32G431RBT6,配置都是相同的,模板已经在第六届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)-CSDN博客配置完成,大家可以前往学习

三.相关代码实现

(1)MAIN

1.全局变量声明

#include "main.h"
#include "RCC\bsp_rcc.h"
#include "KEY_LED\bsp_key_led.h"
#include "LCD\bsp_lcd.h"
#include "ADC\bsp_adc.h"
#include "TIM\bsp_tim.h"

//***全局变量声明区
//*减速变量
__IO uint32_t uwTick_Key_Set_Point = 0;//控制Key_Proc的执行速度
__IO uint32_t uwTick_Led_Set_Point = 0;//控制Led_Proc的执行速度
__IO uint32_t uwTick_Lcd_Set_Point = 0;//控制Lcd_Proc的执行速度
//__IO uint32_t uwTick_Usart_Set_Point = 0;//控制Usart_Proc的执行速度

//*按键扫描专用变量
uint8_t ucKey_Val, unKey_Down, ucKey_Up, ucKey_Old;

//*LED专用变量
uint8_t ucLed = 0x01;

//*LCD显示专用变量
uint8_t Lcd_Disp_String[21];//最多显示20个字符

//*pwm相关变量
uint16_t PWM_T_Count;

//**自定义变量区
float R37_Voltage;
uint8_t Duty_hundredfold;
uint8_t Duty_Change_Lock;

uint8_t R_Ctrl = 1;
uint8_t R_Show = 1;
uint8_t K_Ctrl = 1;
uint8_t K_Show = 1;

uint32_t Freq;
float V;
float V_Storage[5];
float V_Index;
float V_Max_High_Freq_Out;
float V_Max_Low_Freq_Out;

uint8_t Out_Freq_Mode;

uint8_t Screen_Disp;


__IO uint32_t uwTick_Long_Short_Key_Point = 0;
uint8_t Long_Short_Key_Down_Flag;

uint8_t Out_Freq_Change_State;//0-没开启,1-低到高,2-高到低
uint8_t Out_Freq_Change_Times;
uint8_t High_Low_Freq_Change_N;
uint16_t Out_Freq = 4000;
//***子函数声明区
void Key_Proc(void);
void Led_Proc(void);
void Lcd_Proc(void);
void Usart_Proc(void);

2.系统主函数

int main(void)
{

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

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

	/*bsp资源的初始化*/
	KEY_LED_Init();
	
	LCD_Init();
	LCD_Clear(Black);
  LCD_SetBackColor(Black);
  LCD_SetTextColor(White);	
  ADC2_Init();

    PWM_OUTPUT_TIM2_Init();
    F_TEST_TIM3_Init();

	/*外设使用基本配置*/
		
	//*输入捕获PWM启动
	HAL_TIM_Base_Start(&htim3);  /* 启动定时器 */
  HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);		
		
    HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);	//PA1
		
		__HAL_TIM_SET_AUTORELOAD(&htim2, (uint16_t)((1000000.0/Out_Freq)-1));
	
		
		
  while (1)
  {
		Key_Proc();
		Led_Proc();
		Lcd_Proc();
//		Usart_Proc();
		
		
		
  }

}

3.按键扫描子函数

a. 逻辑框图

b. 程序源码

//***按键扫描子函数
void Key_Proc(void)
{
	if((uwTick -  uwTick_Key_Set_Point)<50)	return;//减速函数
		uwTick_Key_Set_Point = uwTick;

	ucKey_Val = Key_Scan();
	unKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val); 
	ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);	
	ucKey_Old = ucKey_Val;
	
	//********B1***********//
	if(unKey_Down == 1)//界面轮换
	{
		if(Screen_Disp == 0x00)
		{
			Screen_Disp = 0x10;
			ucLed &= (~0x01);		
			
		}
		else if((Screen_Disp&0xF0) == 0x10)
		{
			Screen_Disp = 0x20;
			
			R_Ctrl = R_Show;//退出生效
			K_Ctrl = K_Show;	
			
		}
		else if(Screen_Disp == 0x20)
		{
			Screen_Disp = 0x00;
			ucLed |= 0x01;			
		}
    LCD_Clear(Black);
	}
	
	//********B2***********//	
	if(unKey_Down == 2)//区分界面调整R和K,或者,高低频切换
	{
		if((Screen_Disp&0xF0) == 0x10)//参数界面
		{
			Screen_Disp ^= 0x01;
		}
		
		if(Screen_Disp == 0x00)//数据界面
		{
//			Out_Freq_Mode ^= 0x01;
			if(Out_Freq_Mode == 0)//如果此时是低频模式,进入低到高变化模式
				Out_Freq_Change_State	= 1;
			else//如果此时是高频模式,进入高到低变化模式
				Out_Freq_Change_State	= 2;				
			
			V_Storage[0] = 0;
			V_Storage[1] = 0;			
			V_Storage[2] = 0;			
			V_Storage[3] = 0;			
			V_Storage[4] = 0;
			
			
		}		
		
		
	
	}	
	
	//*******B3************//
	if(unKey_Down == 3)// 
	{
		
		if(Screen_Disp== 0x10)//参数界面,调整+R
		{
			if( ++R_Show == 11 ) 
				R_Show = 1;
		}
		else if(Screen_Disp== 0x11)//参数界面,调整+K
		{
			if( ++K_Show == 11 ) 
				K_Show = 1;			
		}		
		
		
	}		
	
	
	
	//*******B4************//	
	if(unKey_Down == 4)// 
	{
		if(Screen_Disp== 0x10)//参数界面,调整-R
		{
			if( --R_Show == 0 ) 
				R_Show = 10;			
		}
		else if(Screen_Disp== 0x11)//参数界面,调整-K
		{
			if( --K_Show == 0 ) 
				K_Show = 10;						
		}		
	}		
	
	
	if(Screen_Disp== 0x00)//数据界面
	{	
		if(unKey_Down == 4)
		{
			uwTick_Long_Short_Key_Point = uwTick;
//			Long_Short_Key_Down_Flag = 1;
		}
		if(ucKey_Up == 4)
		{		
			if((uwTick - uwTick_Long_Short_Key_Point)>2000)//长按生效
			{
				Duty_Change_Lock = 1;
				ucLed |= 0x04;					
			}
			else//短按生效
			{
				Duty_Change_Lock = 0;		
				ucLed &= (~0x04);						
			}		
		}
	}
}

4.LED扫描子函数

a. 逻辑导图

b. 程序源码

void Led_Proc(void)
{
	if((uwTick -  uwTick_Led_Set_Point)<200)	return;//减速函数
		uwTick_Led_Set_Point = uwTick;

	
	
	//实现PWM输出
	if(Out_Freq_Change_State == 1)//低到高变化状态
	{
			Out_Freq += 160;
			__HAL_TIM_SET_AUTORELOAD(&htim2, (uint16_t)((1000000.0/Out_Freq)-1));			
			__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, (uint32_t)((1000000.0/Out_Freq)*0.01*Duty_hundredfold));		
		
			Out_Freq_Change_Times++;
			if(Out_Freq_Change_Times == 25)
			{
				Out_Freq_Change_State = 0;
				Out_Freq_Change_Times = 0;
				Out_Freq_Mode = 1;
				High_Low_Freq_Change_N++;
			}
	}
	else if(Out_Freq_Change_State == 2)//高到低变化状态
	{
			Out_Freq -= 160;
			__HAL_TIM_SET_AUTORELOAD(&htim2, (uint16_t)((1000000.0/Out_Freq)-1));			
			__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, (uint32_t)((1000000.0/Out_Freq)*0.01*Duty_hundredfold));					

			Out_Freq_Change_Times++;
			if(Out_Freq_Change_Times == 25)
			{
				Out_Freq_Change_State = 0;
				Out_Freq_Change_Times = 0;
				Out_Freq_Mode= 0;
				High_Low_Freq_Change_N++;				
			}		
	}
}

5.LCD扫描子函数

a. 逻辑导图

b. 程序源码

void Lcd_Proc(void)
{
	if((uwTick -  uwTick_Lcd_Set_Point)<100)	return;//减速函数
		uwTick_Lcd_Set_Point = uwTick;
//****数据采集区域
		//采集电压
		R37_Voltage = ((((float)getADC2())/4096)*3.3);
		
		//测算占空比
		if(Duty_Change_Lock == 0)//解锁状态
		{
			if(R37_Voltage <= 1)
				Duty_hundredfold = 10;
			else if(R37_Voltage >= 3)
				Duty_hundredfold = 85;
			else 
				Duty_hundredfold = (uint8_t)(R37_Voltage*37.5 - 27.5);
			
			__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, (uint32_t)((1000000.0/Out_Freq)*0.01*Duty_hundredfold));					
	  }

	
		
		//测量频率
		Freq = (uint32_t)(1000000.0/PWM_T_Count);
		
		//测算速度
		V = ((Freq * 0.0628 * R_Ctrl) / (float)K_Ctrl);
		V_Index++;
		if(V_Index == 5)
		{
			V_Index = 0;
				
			V_Storage[0] = V_Storage[1];
			V_Storage[1] = V_Storage[2];			
			V_Storage[2] = V_Storage[3];			
			V_Storage[3] = V_Storage[4];			
			V_Storage[4] = V;
			
			if((V_Storage[0] == V)&&(V_Storage[1] == V)&&(V_Storage[2] == V)&&(V_Storage[3] == V)&&(V_Storage[4] == V))//表示出现了有效速度
			{
				if(Out_Freq_Mode == 0)//低频模式
				{
					if(V >= V_Max_Low_Freq_Out )
					{
						V_Max_Low_Freq_Out = V;
					}
				}
				else//高频模式
				{
					if(V >= V_Max_High_Freq_Out )
					{
						V_Max_High_Freq_Out = V;
					}				
				}
			}
		}
		
		
//	sprintf((char *)Lcd_Disp_String, "R37_Vol:%6.3fV",R37_Voltage);
//	LCD_DisplayStringLine(Line8, Lcd_Disp_String);			
//	sprintf((char *)Lcd_Disp_String, "R39P:%05dHz",(unsigned int)(Freq));
//	LCD_DisplayStringLine(Line9, Lcd_Disp_String);			
		
//****数据显示区域
		if(Screen_Disp == 0x00)
		{
			sprintf((char *)Lcd_Disp_String, "        DATA        ");
			LCD_DisplayStringLine(Line1, Lcd_Disp_String);			
		
			if(Out_Freq_Mode == 0)
				sprintf((char *)Lcd_Disp_String, "     M=L  ");
			else
				sprintf((char *)Lcd_Disp_String, "     M=H  ");			
			LCD_DisplayStringLine(Line3, Lcd_Disp_String);	
			
			sprintf((char *)Lcd_Disp_String, "     P=%02d%%  ",(uint32_t)Duty_hundredfold);
			LCD_DisplayStringLine(Line4, Lcd_Disp_String);				
			
			sprintf((char *)Lcd_Disp_String, "     V=%.1f        ",V);
			LCD_DisplayStringLine(Line5, Lcd_Disp_String);				
		
		}
	  if((Screen_Disp&0xF0) == 0x10)
		{
			sprintf((char *)Lcd_Disp_String, "        PARA        ");
			LCD_DisplayStringLine(Line1, Lcd_Disp_String);		

			sprintf((char *)Lcd_Disp_String, "     R=%-d  ",(uint32_t)R_Show);
			LCD_DisplayStringLine(Line3, Lcd_Disp_String);	
			
			sprintf((char *)Lcd_Disp_String, "     K=%-d  ",(uint32_t)K_Show);
			LCD_DisplayStringLine(Line4, Lcd_Disp_String);	
			
		}
		if(Screen_Disp == 0x20)
		{
			sprintf((char *)Lcd_Disp_String, "        RECD        ");
			LCD_DisplayStringLine(Line1, Lcd_Disp_String);				
		
			sprintf((char *)Lcd_Disp_String, "     N=%-d   ",(uint32_t)High_Low_Freq_Change_N);
			LCD_DisplayStringLine(Line3, Lcd_Disp_String);				
			
			sprintf((char *)Lcd_Disp_String, "     MH=%.1f   ",V_Max_High_Freq_Out);
			LCD_DisplayStringLine(Line4, Lcd_Disp_String);						
			
			sprintf((char *)Lcd_Disp_String, "     ML=%.1f   ",V_Max_Low_Freq_Out);
			LCD_DisplayStringLine(Line5, Lcd_Disp_String);				
		}
 
		if(Out_Freq_Change_State != 0)
			ucLed ^= 0x02;
		else 
			ucLed &= (~0x02);				

		LED_Disp(ucLed);	

}

6. 输入捕获PWM中断回调

a. 程序源码

//输入捕获PWM中断回调
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	  if(htim->Instance==TIM3)
  {
				if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
			{
				PWM_T_Count =  HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2)+1;
			}
	}	
}

(2)BSP

第六届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)-CSDN博客里面有详细的讲解,大家可前往此链接学习

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐