一.题目分析
(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 ");elsesprintf((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博客里面有详细的讲解,大家可前往此链接学习