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

发布于:2024-10-09 ⋅ 阅读:(12) ⋅ 点赞:(0)

一.题目分析

(1).题目

 (2).题目分析

1.按键功能分析

a.B1界面切换

b.B2每次按下R加2

c.B3每次按下R减2

d.LED控制按键

2.信号输出功能分析

a.PA7信号输出-----信号的输出就需要使用到输入捕获和输出比较功能

b.输出信号的频率为输入信号频率的R分频

c.输出信号占空比和检测到的R37成正比

        (当前电压值/3.3V)*周期 = 占空比

 (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的执行速度

//*按键扫描专用变量
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;
//*主逻辑使用变量
uint8_t Disp_Screen_Num;//0-数据,1-参数
uint8_t R_Freq = 4;//分频值,初试为4
uint16_t ADC_Voltage_X100;
uint16_t Frq;
uint8_t LED_Func = 1;//1-启用,0-禁用
uint32_t AUTORELOAD_Num;
uint32_t COMPARE_Num;


//***子函数声明区
void Key_Proc(void);
void Led_Proc(void);
void Lcd_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_INPUT_TIM2_Init();
	PWM_OUTPUT_TIM17_Init();
		
	//*输入捕获PWM启动
	HAL_TIM_Base_Start(&htim2);  /* 启动定时器 */
  HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);		

	//PA7黄色
	__HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, 500);//没有波形输出
	__HAL_TIM_SET_AUTORELOAD(&htim17, 4999);	//200HZ
  HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);		//PA7

  while (1)
  {
		Key_Proc();
		Led_Proc();
		Lcd_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;
	
	if(unKey_Down == 1)//完成界面的切换
	{
		Disp_Screen_Num ^= 0x01;
		LCD_Clear(Black);		
		if(Disp_Screen_Num == 0x00)//数据界面LD1点亮
		{
			ucLed &= (~0x03);
			ucLed |= 0x01;			
		}
		else if(Disp_Screen_Num == 0x01)//参数界面LD2点亮
		{
			ucLed &= (~0x03);		
			ucLed |= 0x02;				
		}			
	}
	if(Disp_Screen_Num == 0x01)//在参数设置界面的时候,才可以加减
	{
    if(unKey_Down == 2)//+2功能
		{
			R_Freq += 2;
			if(R_Freq > 10)
				R_Freq = 10;
		}	
		
    if(unKey_Down == 3)//-2功能
		{
			R_Freq -= 2;
			if(R_Freq < 2)
				R_Freq = 2;
		}	
	}
	
    if(unKey_Down == 4)//LED启用和停用功能
		{	
			LED_Func ^= 0x01;
		}

}

4.LED扫描子函数

a. 程序源码

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

	if(LED_Func == 0x01)
		LED_Disp(ucLed);
	else if(LED_Func == 0x00)
		LED_Disp(0x00);		
}

5.LCD扫描子函数

a. 逻辑框图

b. 程序源码

void Lcd_Proc(void)
{
	if((uwTick -  uwTick_Lcd_Set_Point)<100)	return;//减速函数
		uwTick_Lcd_Set_Point = uwTick;
		ADC_Voltage_X100 = ((((float)getADC2())/4096)*330);
		Frq = (1000000/PWM_T_Count);

		//控制LED灯的变化
		if((ADC_Voltage_X100<100)||(ADC_Voltage_X100>=300))
		{
			ucLed |= 0x04;
		}
		else 
			ucLed &= (~0x04);			

		if((Frq<1000)||(Frq>=5000))
		{
			ucLed |= 0x08;
		}
		else 
			ucLed &= (~0x08);	

		
		//控制输出PWM的变化
		//AUTORELOAD_Num = 6289;	
		AUTORELOAD_Num = (1000000.0/(Frq/R_Freq));
		COMPARE_Num = (((330-ADC_Voltage_X100)/330.0)*AUTORELOAD_Num);	//求助各位大佬?究竟为什么?如果您告诉我,我以您的名义,补充录制一段,单独解释这个地方。
		
		
		//完成频率的设置
		__HAL_TIM_SET_AUTORELOAD(&htim17, AUTORELOAD_Num);			
					
    //完成占空比的设置
		__HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, COMPARE_Num);

		if(Disp_Screen_Num == 0)//显示数据
		{
				sprintf((char *)Lcd_Disp_String, "       Data      ");		
				LCD_DisplayStringLine(Line1, Lcd_Disp_String);	
			
				sprintf((char *)Lcd_Disp_String, "   FRQ:%dHz        ",(unsigned int)Frq);
				LCD_DisplayStringLine(Line3, Lcd_Disp_String);				
			
				sprintf((char *)Lcd_Disp_String, "   R37:%4.2fV      ",(ADC_Voltage_X100*0.01));
				LCD_DisplayStringLine(Line5, Lcd_Disp_String);				
		}
		else if(Disp_Screen_Num == 1)//显示参数
		{
				sprintf((char *)Lcd_Disp_String, "       Para      ");		
				LCD_DisplayStringLine(Line1, Lcd_Disp_String);	
			
				sprintf((char *)Lcd_Disp_String, "      R:%2d",(unsigned int)R_Freq);
				LCD_DisplayStringLine(Line3, Lcd_Disp_String);				
		}
}

5.输入捕获PWM中断回调

a. 程序源码

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

(2)BSP

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