第十四届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)

news/2024/10/10 7:21:13/

一.题目分析

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


http://www.ppmy.cn/news/1536897.html

相关文章

人工智能机器视觉就业前景怎么样?

随着机器视觉技术的不断发展&#xff0c;机器视觉在各个领域的应用也越来越广泛。从智能家居到智能制造&#xff0c;从医疗健康到交通安全&#xff0c;机器视觉技术的应用正在改变我们的生活和工作方式。因此&#xff0c;机器视觉行业的前景也越来越受到关注。 一、机器视觉行业…

mysql学习教程,从入门到精通,SQL 创建索引(CREATE INDEX 语句)(35)

1、SQL 创建索引(CREATE INDEX 语句) 在SQL中&#xff0c;创建索引&#xff08;CREATE INDEX&#xff09;是一种用于提高数据库查询性能的方法。索引类似于书的目录&#xff0c;通过它可以更快地定位到表中的特定行。以下是一个创建索引的示例&#xff0c;以及对其各部分的解释…

ESP32利用WebServer进行设备配置

目标需求 利用esp32的WebServer功能&#xff0c;展示一个网页&#xff0c;对里面的参数进行配置&#xff0c;并以json文本格式保存到flash里面。 1、定义HTML const char index_html[] PROGMEM R"rawliteral( <!DOCTYPE html> <html lang"en"> …

JavaScript 网页设计案例与技巧

简单的 JavaScript 网页设计案例 展示了动态改变页面内容和样式的效果: 一、HTML 结构 <!DOCTYPE html> <!-- 这是文档类型声明,告知浏览器以 HTML5 标准解析页面 --> <html lang="en"> <!-- 整个网页的根元素,lang="en" 表示页…

爬虫学习实战

1.大学排名爬取&#xff08;简单&#xff09; # -*- coding: utf-8 -*- from selenium import webdriver from selenium.webdriver.common.by import By import timeurl https://daxue.911cha.com/ driver webdriver.Chrome() # 设置隐式等待&#xff0c;等待页面加载完成 d…

【hot100-java】二叉树中的最大路径和

二叉树篇 easy. /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

Run the FPGA VI 选项的作用

Run the FPGA VI 选项的作用是决定当主机 VI 运行时&#xff0c;FPGA VI 是否会自动运行。 具体作用&#xff1a; 勾选 “Run the FPGA VI”&#xff1a; 当主机 VI 执行时&#xff0c;如果 FPGA VI 没有正在运行&#xff0c;系统将自动启动并运行该 FPGA VI。 这可以确保 FPG…

【unity游戏开发】彻底理解AnimatorStateInfo,获取真实动画长度

前言 前置知识&#xff1a;设置参数后&#xff0c;下一个循环才会切换对应动画&#xff0c;所以在下一个循环获取真实的动画长度 AnimatorStateInfo是结构体&#xff01;值类型&#xff0c;要不断重复获取才是最新的 主要是自动设置trigger切换的动画自动切回上一个动画&#x…