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