【蓝桥杯嵌入式】蓝桥杯第15届嵌入式省赛代码讲解(文章末尾附送满分工程链接)

一,第15届嵌入式省赛原题
https://www.lanqiao.cn/courses/2786/learning/?id=2871328&compatibility=false

原题的具体内容前往官网查看https://www.lanqiao.cn/courses/2786/learning/?id=2871328&compatibility=false

二.CubeMax配置

1.所需要的引脚

(LCD屏幕的引脚不需要在CubeMax配置,官方提供的LCD的驱动里面包含对引脚的配置)

2、配置SYS-Debug_Serial Wire

3.配置RCC --> High Spee Clock(HSE)  -> Crystal/Ceramic Resonator

4. 配置时钟数

5.配置GPIO

6.配置NVIC

(这个不需要单独去配置的,在配置对应的外设的时候打开中断就可以了)


7.配置定时器

(1.)TIM2 --输入捕获模式.(2.)TIM3 -- 配置为输入捕获模式

(3.)TIM4--配置为普通模式,用于按键的延时

(4.)TIM7

三.代码部分

(1.)主函数

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lcd.h"
#include "LED.h"
#include "stdio.h"
#include "Interrupt.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
	extern double FRQ_A;
	extern double FRQ_B;
	extern double PRD_A;
	extern double PRD_B;
	
	extern double FRQ_A_cha;
	extern double FRQ_B_cha;
	
	uint32_t PD = 1000;
	uint32_t PH = 5000;
	int32_t PX = 0;
	
	extern struct keys key[4];
	uint8_t page = 0;
	uint8_t page_DATA_flg = 0;
	uint8_t page_PARA_flg = 0;
	uint8_t chose_PX_PH_PD = 0;
	
	uint8_t FPQ_A_PH_flg = 0;
	uint8_t FPQ_B_PH_flg = 0;
	
	
	uint16_t NDA = 0;
	uint16_t NDB = 0;
	uint16_t NHA = 0;
	uint16_t NHB = 0;
	
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void key_config(void);
void LCD_congif(void);
void Data_config(void);
void LED_config(void);


/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

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

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

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

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM7_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_TIM4_Init();
  /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim7);
	HAL_TIM_Base_Start_IT(&htim4);
	HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
	HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
	
	LCD_Init();
	LED_Show(0x00);
	
	LCD_Clear(Black);
	LCD_SetTextColor(White);
	LCD_SetBackColor(Black);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	 
	  key_config();
	  LCD_congif();
	  Data_config();
	  LED_config();

	}
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3;
  RCC_OscInitStruct.PLL.PLLN = 20;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
void key_config(void)
{
	//按键1
	if(key[0].key_dan_flg == 1)
	{
		key[0].key_dan_flg = 0;
		
		
		if(page_PARA_flg == 1)
		{
			if(chose_PX_PH_PD % 3 == 0)
				PD += 100;
			if(chose_PX_PH_PD % 3 == 1)
				PH += 100;
			if(chose_PX_PH_PD % 3 == 2)
				PX +=100;
		
		}
	}
	//按键2
	if(key[1].key_dan_flg == 1)
	{
		key[1].key_dan_flg = 0;

		if(page_PARA_flg == 1)
		{
			if(chose_PX_PH_PD % 3 == 0)
				PD -= 100;
			if(chose_PX_PH_PD % 3 == 1)
				PH -= 100;
			if(chose_PX_PH_PD % 3 == 2)
				PX -=100;
			
			
	  
			  
		}	
	}
	//按键3
	if(key[2].key_dan_flg == 1)
	{
		key[2].key_dan_flg = 0;
		
		if(page % 3 == 0)
		{
			page_DATA_flg += 1;
		}
		
		if(page_PARA_flg == 1)
		{
			chose_PX_PH_PD += 1;
		}
	
	

	}
	//按键4
	if(key[3].key_dan_flg == 1)
	{
		key[3].key_dan_flg = 0;
		
		page += 1;

	
		
	}
	
	//按键4长按
	if(key[2].key_long_flg == 1)
	{
		key[2].key_long_flg = 0;
		
		if(page % 3 == 2)
		{
			NDA = 0;
			NDB = 0;
			NHA = 0;
			NHB = 0;
		}
		
	}
}


void LCD_congif(void)
{
	//DATA界面
	if(page % 3 == 0)
	{
		char arr[32] = {" "};
		sprintf(arr,"        DATA     ");
		LCD_DisplayStringLine(Line1,(uint8_t *)arr);
		sprintf(arr,"                       ");
		LCD_DisplayStringLine(Line5,(uint8_t *)arr);
		sprintf(arr,"                       ");
		LCD_DisplayStringLine(Line6,(uint8_t *)arr);
		
		//显示频率
		if(page_DATA_flg % 2 == 0)
		{
			if(FRQ_A >= 0 && FRQ_A <= 1000)
			{
				sprintf(arr,"     A=%.0fHz     ",FRQ_A);
				LCD_DisplayStringLine(Line3,(uint8_t *)arr);
			}
			if(FRQ_A > 1000)
			{
				sprintf(arr,"     A=%.2fKHz     ",FRQ_A / 1000);
				LCD_DisplayStringLine(Line3,(uint8_t *)arr);			
			}
			if(FRQ_B >= 0 && FRQ_B <= 1000)
			{
				sprintf(arr,"     B=%.0fKHz     ",FRQ_B);
				LCD_DisplayStringLine(Line4,(uint8_t *)arr);			
			}
			if(FRQ_B > 1000)
			{
				sprintf(arr,"     B=%.2fKHz     ",FRQ_B / 1000);
				LCD_DisplayStringLine(Line4,(uint8_t *)arr);			
			}
			
			
			if(FRQ_A < 0)
			{
				sprintf(arr,"     A=NULL     ");
				LCD_DisplayStringLine(Line3,(uint8_t *)arr);	
			}
			if(FRQ_B < 0)
			{
				sprintf(arr,"     B=NULL     ");
				LCD_DisplayStringLine(Line4,(uint8_t *)arr);	
			}

		}
		//显示周期
		if(page_DATA_flg % 2 == 1)
		{
			sprintf(arr,"                       ");
			LCD_DisplayStringLine(Line6,(uint8_t *)arr);
		
			if(FRQ_A >= 0)
			{
				if(PRD_A <= 1000 )
				{
					sprintf(arr,"     A=%.0fuS     ",PRD_A);
					LCD_DisplayStringLine(Line3,(uint8_t *)arr);
				}
				if(PRD_A > 1000 )
				{
					sprintf(arr,"     A=%.2fmS     ",PRD_A / 1000);
					LCD_DisplayStringLine(Line3,(uint8_t *)arr);			
				}
			}
			if(FRQ_B >= 0)
			{
				if(PRD_B <= 1000 )
				{
					sprintf(arr,"     B=%.0fuS     ",PRD_B);
					LCD_DisplayStringLine(Line4,(uint8_t *)arr);			
				}
				if(PRD_B > 1000 )
				{
					sprintf(arr,"     B=%.2fmS     ",PRD_B / 1000);
					LCD_DisplayStringLine(Line4,(uint8_t *)arr);			
				}
			}
			
			if(FRQ_A < 0)
			{
				sprintf(arr,"     A=NULL     ");
				LCD_DisplayStringLine(Line3,(uint8_t *)arr);	
			}
			if(FRQ_B < 0)
			{
				sprintf(arr,"     B=NULL     ");
				LCD_DisplayStringLine(Line4,(uint8_t *)arr);	
			}

		}
	
		
	}
	else
	{
		page_DATA_flg = 0;
	}
	
	
	//PARA界面
	if(page % 3 == 1)
	{
		page_PARA_flg = 1;
		
		char arr[32] = {" "};
		sprintf(arr,"        PARA      ");
		LCD_DisplayStringLine(Line1,(uint8_t *)arr);	
		
		sprintf(arr,"     PD=%dHz      ",PD);
		LCD_DisplayStringLine(Line3,(uint8_t *)arr);			
		
		sprintf(arr,"     PH=%dHz       ",PH);
		LCD_DisplayStringLine(Line4,(uint8_t *)arr);			
		  
		sprintf(arr,"     PX=%dHz       ",PX);
		LCD_DisplayStringLine(Line5,(uint8_t *)arr);	
	
	
	}
	else
	{
		page_PARA_flg = 0;
		chose_PX_PH_PD = 0;
	}
	
	//RECD界面
	if(page % 3 == 2)
	{
		char arr[32] = {" "};
		sprintf(arr,"        RECD      ");
		LCD_DisplayStringLine(Line1,(uint8_t *)arr);	
		
		sprintf(arr,"     NDA=%d      ",NDA);
		LCD_DisplayStringLine(Line3,(uint8_t *)arr);			
		
		
		sprintf(arr,"     NDB=%d      ",NDB);
		LCD_DisplayStringLine(Line4,(uint8_t *)arr);			
		
		sprintf(arr,"     NHA=%d       ",NHA);
		LCD_DisplayStringLine(Line5,(uint8_t *)arr);			
		  
		sprintf(arr,"     NHB=%d       ",NHB);
		LCD_DisplayStringLine(Line6,(uint8_t *)arr);	
	
	}

}

void Data_config(void)
{
	  if(PD < 100)
		PD = 1000;
	  if(PD > 1000)
		  PD = 100;
	 
	  if(PH < 1000)
		  PH = 10000;
	  if(PH > 10000)
		  PH = 1000;	  
	  

	  if(PX < -1000)
		  PX = 1000;
	  if(PX > 1000)
		  PX = -1000;
	  
	  
	  if(FRQ_A >= PH && FPQ_A_PH_flg == 0)
	  {
			NHA += 1;
		  FPQ_A_PH_flg = 1;
	  }
	  if(FRQ_A < PH )
		  FPQ_A_PH_flg = 0;
	  
	  if(FRQ_B >= PH && FPQ_B_PH_flg == 0)
	  {
			NHB += 1;
		  FPQ_B_PH_flg = 1;
	  }
	  if(FRQ_B < PH )
		  FPQ_B_PH_flg = 0; 
}

void LED_config(void)
{
	if((page % 3 == 0 ) && (FRQ_A > PH) && (FRQ_B > PH) && (NDA  >= 3 || NDB >= 3))
	{
		LED_Show(0x87);
	}
	else if((page % 3 == 0 ) && (FRQ_A > PH) && (FRQ_B > PH))
	{
		LED_Show(0x07);
	}
	else if((page % 3 == 0 ) && (FRQ_A > PH) && (NDA  >= 3 || NDB >= 3))
	{
		LED_Show(0x83);
	}
	else if((page % 3 == 0 ) && (FRQ_B > PH) && (NDA  >= 3 || NDB >= 3)) 
	{
		LED_Show(0x85);
	}
	else if((FRQ_A > PH) && (FRQ_B > PH) && (NDA  >= 3 || NDB >= 3))
	{
		LED_Show(0x86);
	}
	else if((page % 3 == 0 ) && (FRQ_A > PH))
	{
		LED_Show(0x03);
	}
	else if((page % 3 == 0 ) && (FRQ_B > PH))
	{
		LED_Show(0x05);
	}
	else if((page % 3 == 0 ) && (NDA  >= 3 || NDB >= 3))
	{
		LED_Show(0x81);
	}
	else if((FRQ_A > PH) && (FRQ_B > PH))
	{
		LED_Show(0x06);
	}
	else if((FRQ_A > PH) && (NDA  >= 3 || NDB >= 3))
	{
		LED_Show(0x82);
	}
	else if((FRQ_B > PH) && (NDA  >= 3 || NDB >= 3))
	{
		LED_Show(0x84);
	}
	else if(page % 3 == 0 )
	{
		LED_Show(0x01);
	}
	else if(FRQ_A > PH)
	{
		LED_Show(0x02);
	}
	else if(FRQ_B > PH)
	{
		LED_Show(0x04);
	}
	else if(NDA  >= 3 || NDB >= 3)
	{
		LED_Show(0x80);
	}
	else 
	{
		LED_Show(0x00);
	}
}



/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

(2.)中断回调函数

#include "stm32g4xx_hal.h"
#include "Interrupt.h"

struct keys key[4]={0,0,0,0,0};

double FRQ_A = 0.0;
uint32_t count_tim2 = 0;
double FRQ_B = 0.0;
uint32_t count_tim3 = 0;
double PRD_A = 0.0;
double PRD_B = 0.0;

extern int32_t PX;
extern uint32_t PD;

extern uint16_t NDA;
extern uint16_t NDB;


double FRQ_A_MAX = 0.0;
double FRQ_B_MAX = 0.0;
double FRQ_A_MIN = 0.0;
double FRQ_B_MIN = 0.0;

double FRQ_A_cha = 0.0;
double FRQ_B_cha = 0.0;	

uint32_t time_count = 0;

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM7)
	{
		key[0].key_start=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
		key[1].key_start=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
		key[2].key_start=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
		key[3].key_start=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
		
		for(uint8_t i=0;i<4;i++)
		{
			switch(key[i].key_jude)
			{
				case 0:
				{
					if(key[i].key_start == 0) //低电平按下
					{
						key[i].key_time = 0;
						key[i].key_jude = 1;
					}
				
				}
				break;
				
				case 1:
				{
					if(key[i].key_start == 0)
						key[i].key_jude = 2;
					else
						key[i].key_jude =0;
					
				}
				break;
				
				case 2:
				{
					if(key[i].key_start == 1)
					{
						if(key[i].key_time < 100)
						{
							key[i].key_dan_flg = 1;
						}
						key[i].key_jude = 0;
					}
					else
					{
						key[i].key_time += 1;
						if(key[i].key_time >= 100)
						{
							key[i].key_long_flg = 1;
							
							
							key[i].key_jude = 0;
						}
							
					}
					
				}
				break;
			}
		}
	}
	
	
	
	
	//0.1秒进一次中断
	if(htim->Instance==TIM4)
	{
		time_count ++;
		
	
		if(FRQ_A_MAX < FRQ_A)
			FRQ_A_MAX = FRQ_A;
		
		if(FRQ_A_MIN > FRQ_A || FRQ_A_MIN == 0)
			FRQ_A_MIN = FRQ_A;
			
		if(FRQ_B_MAX < FRQ_B)
			FRQ_B_MAX = FRQ_B;
			
		if(FRQ_B_MIN > FRQ_B || FRQ_B_MIN == 0)
			FRQ_B_MIN = FRQ_B;	
		
		//每3秒获取一个频率的最大值和最小值
		if(time_count % 30 == 0)
		{
			FRQ_A_cha = FRQ_A_MAX - FRQ_A_MIN;
			FRQ_B_cha = FRQ_B_MAX - FRQ_B_MIN;	
			
			if(FRQ_A_cha > PD)
				NDA += 1;
			if(FRQ_B_cha > PD)
				NDB += 1;
		
			FRQ_A_MAX = 0;
			FRQ_A_MIN = 0;
			FRQ_B_MAX = 0;
			FRQ_B_MIN = 0;
			time_count = 0;
		}
			
	}
}




void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM2)
	{
		count_tim2 = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
		__HAL_TIM_SET_COUNTER(htim,0);
		FRQ_A = (80000000 / 80.0 ) / count_tim2 + PX;
		PRD_A = 1 * 1000000.0 / FRQ_A ;
		HAL_TIM_IC_Start_IT(htim,TIM_CHANNEL_1);
	
	}
	
	if(htim->Instance == TIM3)
	{
		count_tim3 = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
		__HAL_TIM_SET_COUNTER(htim,0);
		FRQ_B = (80000000 / 80.0 ) / count_tim3 + PX;
		PRD_B = 1 * 1000000.0 / FRQ_B;
		HAL_TIM_IC_Start_IT(htim,TIM_CHANNEL_1);

	}

}





(3)LED的驱动

#include "stm32g4xx_hal.h"
#include "LED.h"

void LED_Disp(uint8_t dsLED)
{
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC,dsLED << 8,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}

四.源码工程链接

 

 

通过网盘分享的文件:LanQian_Cup15_2.zip
链接: https://pan.baidu.com/s/1s6LzBOLn9GXps8-dSWU1iA?pwd=sw46 提取码: sw46

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值