笔者参加了2025年的第16届蓝桥杯的嵌入式赛道,拿了个省一

在此分享一下做题步骤,全凭考完剩下的记忆,如有错误敬请体谅(早知道带个U盘进去)

第十六届嵌入式省赛真题

CT117E_M4平台的原理图如下

可以看到系统框图如下

对应的连接如下:

模拟信号A对应R37 对应PB15引脚为ADC2的IN15

模拟信号B对应R38 对应PB12引脚为ADC1的IN11

按键连接如图

脉冲单元输入为PA15 为TIM2的Channel1

结合原理图可知采集到的频率受R40调节

PWM输出对应PA7 为TIM3的Channel2

LED的连接如图

LCD的连接如图

结合原理图在cubemx中进行配置

  1. 选择对应的芯片

  2. 时钟的配置

  3. ADC的配置

    ADC1 模拟输入B
    ADC2 模拟输入A
  4. 按键输入的配置

  5. 脉冲单元输入的配置

  6. PWM输出的配置

  7. LED引脚的配置

  8. LCD引脚的配置

到此,我们的引脚配置就完毕了,接下来先生成代码编译看看

点击GENERATE CODE生成代码

KEIL的配置

DAP Link的配置,选择DAPLINK并勾选下载完运行

将LCD驱动文件拖进去,并在项目管理器中添加

项目所需的头文件

/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "lcd.h"
/* USER CODE END Includes */

屏幕和LED的测试

  /* USER CODE BEGIN 2 */
	uint16_t i;
	// close all leds
	HAL_GPIO_WritePin(LED_Ctrl_GPIO_Port,LED_Ctrl_Pin,GPIO_PIN_SET);
	for(i=0;i<8;i++){
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8 << i,GPIO_PIN_SET);
	}
	HAL_GPIO_WritePin(LED_Ctrl_GPIO_Port,LED_Ctrl_Pin,GPIO_PIN_RESET);
	
	LCD_Init();
	LCD_SetBackColor(Black);
	LCD_SetTextColor(White);
	LCD_Clear(Black);
	LCD_DisplayStringLine(Line1,(unsigned char *)"Hello World");
  /* USER CODE END 2 */

效果如图,请忽略我有问题屏幕的白线

对应功能的实现

ADC采样的设计

PS:设ADC采样到的值为x,分辨率为n,则实际电压v为

v = 3300 \cdot \frac{x}{2^n} mV

uint16_t R37_voltage = 0 , R38_voltage;
void get_adc_value(){
	uint16_t temp;
	HAL_ADC_Start(&hadc1);
	HAL_ADC_PollForConversion(&hadc1,20);
	temp = HAL_ADC_GetValue(&hadc1);
	R38_voltage = (3300 * temp) / 4096;
	
	HAL_ADC_Start(&hadc2);
	HAL_ADC_PollForConversion(&hadc2,20);
	temp = HAL_ADC_GetValue(&hadc2);
	R37_voltage = (3300 * temp) / 4096;
	
	HAL_ADC_Stop(&hadc1);
	HAL_ADC_Stop(&hadc2);
}

测试一下

频率采集的实现

首先在cubeKMX开启TIM2的中断

然后开始编写频率的采集

从我们的设定可以知道计数脉冲为f_{CNT}=\frac{80MHz}{PSC+1}=1MHz

可以知道采集的频率CCR从0到CCR1的时间为T_{CCR1} \ =CCR1\cdot T_{CNT}=\frac{CCR1}{f_{CNT}}

于是乎,采集到频率为fre=\frac{1}{T_{CCR1}}=\frac{f_{CNT}}{CCR1},采集完后对定时器清零

在中断回调函数中实现

// 输入频率的捕获
unsigned int fre = 0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
	uint16_t ccr1;
	// 判断定时器和通道是否符合
	if(htim->Instance == TIM2 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){
		ccr1 = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
		fre = (int)1e6 / ccr1;
		__HAL_TIM_SetCounter(htim,0);
	}
}

在main函数中开启中断

HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);

测试一下

接下来就是按键的监听

按键监听的实现

此处我们配合10ms的定时器来实现状态机,定义函数为key_scan()

对应的结构体和数组

typedef struct KEY{
	uint8_t sate;// 状态机状态
	uint8_t pin_sate;// 引脚电平是否有效,低电平为1
	
	uint8_t single_click_flag; // 短按
	uint8_t long_click_flag; // 长按
	
	uint16_t press_count; // 按下计数
	uint16_t release_count; // 松开计数
	
}KEY;

KEY keys[4];

在main中对所有参数清零

for(i=0;i<4;i++){
	keys[i].sate = 0;
	keys[i].pin_sate = 0;
	keys[i].press_count = 0;
	keys[i].release_count = 0;
	keys[i].single_click_flag  = 0;
	keys[i].long_click_flag = 0;
}
	

key_scan()函数的实现

void key_scan(){
	uint8_t i;
	// 获取引脚状态
	keys[0].pin_sate = HAL_GPIO_ReadPin(B1_GPIO_Port,B1_Pin) == GPIO_PIN_RESET ? 1 : 0;
	keys[1].pin_sate = HAL_GPIO_ReadPin(B2_GPIO_Port,B2_Pin) == GPIO_PIN_RESET ? 1 : 0;
	keys[2].pin_sate = HAL_GPIO_ReadPin(B3_GPIO_Port,B3_Pin) == GPIO_PIN_RESET ? 1 : 0;
	keys[3].pin_sate = HAL_GPIO_ReadPin(B4_GPIO_Port,B4_Pin) == GPIO_PIN_RESET ? 1 : 0;
	
	for(i=0;i<4;i++){
		switch(keys[i].sate){
			case 0:
				// 按下开始计数
				if(keys[i].pin_sate){
					keys[i].press_count++;
				}
				// 松开时判断是否进入下一个状态
				if(!keys[i].pin_sate){
					if(keys[i].press_count > 3){
						keys[i].sate = 1;
					}else{
						keys[i].press_count = 0;
					}
				} 
				break;
			case 1:
				// 松开的消抖
				if(!keys[i].pin_sate){
					keys[i].release_count++;
				}
				if(keys[i].release_count > 3){
					keys[i].sate =2;
				}
				break;
			case 2:
				// 给出对应的flag
			if(keys[i].press_count > 200){ // 超过2s为长按
					keys[i].long_click_flag = 1;
				}
				keys[i].single_click_flag = 1;
				keys[i].press_count = 0;
				keys[i].release_count = 0;
				break;
			default:
				keys[i].sate = 0;
				break;
		}
	}
}

定义对应的定时器TIM1开启10ms的中断回调扫描按键

在main中开启定时器

HAL_TIM_Base_Start_IT(&htim1);

在中断中扫描按键

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
	// 10ms
	if(htim->Instance == TIM1){
		key_scan();
	}
}

接下来实现切换页面

屏幕显示的实现

改写一下TIM1的中断来计时运行时间

uint32_t runtime = 0; // 运行的时间
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
	// 10ms
	if(htim->Instance == TIM1){
		key_scan();
		runtime +=10;
	}
}

定义page来决定页面,LCD_show()函数用来显示


// PWM界面对应的参数
unsigned int CF = 2000; // 输出PWM频率
uint16_t CD = 80; // 输出PWM的占空比
unsigned int *DF = &fre; // 捕获的频率
uint8_t st_status = 0; // 0 为解锁,1为锁定

// RECD界面对应的参数
unsigned int CF_err = 0;
uint16_t CD_err = 0;
unsigned int DF_err = 0;
unsigned int XF  = 0;
uint64_t runtime_err = 0;

// PARA界面对应的参数
uint16_t DS = 1;
uint16_t DR = 80;
unsigned int FS = 100;
unsigned int FR = 2000;

uint8_t page = 2;

char str[30];
void LCD_show(){
	sprintf(str,"                              ");
	switch(page){
		case 0:
			//           12345678901234567890
			sprintf(str,"       PWM          ");
			LCD_DisplayStringLine(Line1,(unsigned char *)str);
			sprintf(str,"   CF=%dHz          ",CF);
			LCD_DisplayStringLine(Line3,(unsigned char *)str);
			sprintf(str,"   CD=%d%%          ",CD);
			LCD_DisplayStringLine(Line4,(unsigned char *)str);
			sprintf(str,"   DF=%dHz          ",*DF);
			LCD_DisplayStringLine(Line5,(unsigned char *)str);
			sprintf(str,"   ST=%s            ",!st_status ? "UNLOCK":"LOCK");
			LCD_DisplayStringLine(Line6,(unsigned char *)str);
		    unsigned int sec = runtime / 1000;
			unsigned int min = sec / 60;
			unsigned int hour  = min / 60;
		    sec = sec - 60*min;
			min = min - min / 60;
			sprintf(str,"   %02dH%02dM%02dS",hour,min,sec);
		  LCD_DisplayStringLine(Line7,(unsigned char *)str);
			break;
		case 1:
			sprintf(str,"       RECD          ");
			LCD_DisplayStringLine(Line1,(unsigned char *)str);
			sprintf(str,"   CF=%dHz          ",CF_err);
			LCD_DisplayStringLine(Line3,(unsigned char *)str);
			sprintf(str,"   CD=%d%%          ",CD_err);
			LCD_DisplayStringLine(Line4,(unsigned char *)str);
			sprintf(str,"   DF=%dHz          ",DF_err);
			LCD_DisplayStringLine(Line5,(unsigned char *)str);
			sprintf(str,"   XF=%dHz            ",XF);
			LCD_DisplayStringLine(Line6,(unsigned char *)str);
		  sec = runtime_err / 1000;
			min = sec / 60;
			hour  = min / 60;
		  sec = sec - 60*min;
			min = min - min / 60;
			sprintf(str,"   %02dH%02dM%02dS",hour,min,sec);
		  LCD_DisplayStringLine(Line7,(unsigned char *)str);
			break;
		case 2:
			sprintf(str,"       PARA          ");
			LCD_DisplayStringLine(Line1,(unsigned char *)str);
			sprintf(str,"   DS=%d%%          ",DS);
			LCD_DisplayStringLine(Line3,(unsigned char *)str);
			sprintf(str,"   DR=%d%%          ",DR);
			LCD_DisplayStringLine(Line4,(unsigned char *)str);
			sprintf(str,"   FS=%dHz          ",FS);
			LCD_DisplayStringLine(Line5,(unsigned char *)str);
			sprintf(str,"   FR=%dHz            ",FR);
			LCD_DisplayStringLine(Line6,(unsigned char *)str);
			break;
	}

对应显示效果如下

按键功能的实现

void key_proc(){
	// 页面的切换
	if(keys[0].single_click_flag){
		if(page < 2)
			page ++;
		else 
			page = 0;
		LCD_Clear(Black);
		
		// 默认修改DR
		if(page == 2)
			para_choose_index = 0;
		
		keys[0].single_click_flag  = 0;
		keys[0].long_click_flag = 0;
		keys[0].sate = 0;
	}
	// 参数切换以及计时清零,锁定切换
	if(keys[1].single_click_flag){
		if(page == 0 && keys[1].long_click_flag){
			runtime = 0;
		}else if(page == 0){
			st_status = !st_status;
		}
		if(page == 2 ){
			if(para_choose_index < 3)
				para_choose_index ++;
			else
				para_choose_index = 0;
		}
		keys[1].single_click_flag  = 0;
		keys[1].long_click_flag = 0;
		keys[1].sate = 0;
	}
	// 参数加
	if(keys[2].single_click_flag){
			if(page == 2){
				switch(para_choose_index){
					case 0:
						if(DS + 1 < DR)
							DS +=1;
						break;
					case 1:
						if(DR + 10 <= 100)
							DR += 10;
						break;
					case 2:
						if(FS + 100 < FR)
							FS += 100;
						break;
					case 3:
						FR += 1000;
						break;
				default:
						para_choose_index = 0;
			}
		}
		keys[2].single_click_flag  = 0;
		keys[2].long_click_flag = 0;
		keys[2].sate = 0;
	}
	// 参数减
	if(keys[3].single_click_flag){
			if(page == 2){
				switch(para_choose_index){
					case 0:
						if(DS - 1 >= 1)
							DS -=1;
						break;
					case 1:
						if(DR - 10 >= 10)
							DR -= 10;
						break;
					case 2:
						if(FS - 100 >= 100)
							FS -= 100;
						break;
					case 3:
						if(FR - 1000 >= 1000)
							FR -= 1000;
						break;
				default:
						para_choose_index = 0;
			}
		}
		keys[3].single_click_flag  = 0;
		keys[3].long_click_flag = 0;
		keys[3].sate = 0;
	}
}

PWM输出的实现

我们只需要修改TIM3的自动重新装载值ARR就可以实现pwm频率的修改,修改CCR2也就可以修改输出的占空比

f_{out}=\frac{80 \cdot 10 ^ 6 Hz}{(ARR + 1)(PSC+1)} \\ \Rightarrow ARR = \frac{80\cdot 10 ^6}{f_{out}(PSC+1)} - 1\\let \ PSC + 1 = 80 \\ \Rightarrow ARR=\frac{1 \cdot 10^6}{f_{out}}

CCR2 = duty \cdot ARR

// 在main中开启pwm输出
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
pwm输出控制函数
void pwm_out(){
	uint16_t arr = (int)1e6 / CF - 1;
	uint16_t comp = (arr * CD) / 100;
	__HAL_TIM_SET_AUTORELOAD(&htim3,arr);
	__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,comp);
}

测试一下,默认f_{out}=2kHz,duty=80\%

使用逻辑分析仪采集,可以看到我们的思路是没有问题的

电位器控制输出频率以及占空比

可以看到把电压0~3300mV划分为了n份,那每一份的电压V_{step}

n_1 = \frac{DR-10\%}{DS}\\ \Rightarrow \ V_{step1}=\frac{3300mV}{n_1} \\ n_2 = \frac{FR-1000Hz}{FS} \\ \Rightarrow \ V_{step2}=\frac{3300mV}{n_2}

根据采集到的电压就可以反推出n

n=\frac{V_{sample}}{V_{step]}}

然后改写pwm输出控制函数

void pwm_out(){
	uint16_t n = 0;
	// 计算出对应的V_step
	uint16_t V_setp1 = 	(3300*DS)/(DR - 10 ) , V_setp2 = (3300*FS)/(FR -1000);
	// 计算出实际输出占空比
	CD = 10 + (DS * R37_voltage) / V_setp1;
	// 计算出实际输出的频率
	CF = 1000 + (FS * R38_voltage) / V_setp2;
	
	// 计算出所需的ARR和CCR2
	uint16_t arr = (int)1e6 / CF - 1;
	uint16_t comp = (arr * CD) / 100;
	
	__HAL_TIM_SET_AUTORELOAD(&htim3,arr);
	__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,comp);
}

随便设定个值测试一下,屏幕显示如图

逻辑分析仪采集到的结果与之接近

异常捕获的实现

要求如图,持续异常不更新

实现代码如下

uint8_t error_hold = 0;
void error_proc(){
  int32_t	t = (int32_t)fre - (int32_t)CF;
	if(t < 0)
		t = -t;
	if(t < 1000)
		error_hold = 0;
	if(!error_hold){
		if(t > 1000){
			error_hold  = 1;
			CF_err = CF;
			CD_err = CD;
			DF_err = fre;
			XF = t;
			runtime_err  = runtime;
		}
	}
}

LED显示的实现

实现代码如下

void leds(){
	uint16_t i;
	// close all leds
	HAL_GPIO_WritePin(LED_Ctrl_GPIO_Port,LED_Ctrl_Pin,GPIO_PIN_SET);
	for(i=0;i<8;i++){
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8 << i,GPIO_PIN_SET);
	}
	
	if(page == 0)
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8 << 0,GPIO_PIN_RESET);
	
	if(st_status)
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8 << 1,GPIO_PIN_RESET);
	
	if(error_hold)
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8 << 2,GPIO_PIN_RESET);
	
	HAL_GPIO_WritePin(LED_Ctrl_GPIO_Port,LED_Ctrl_Pin,GPIO_PIN_RESET);
	
}

锁定功能的实现

也就是st_status=1时,PWM输出不受电位器电压所影响

原先while(1)循环处代码为:

 while (1)
  {
		leds();
		get_adc_value();
		LCD_show();
		key_proc();
		pwm_out();
		error_proc();
		HAL_Delay(50);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

修改为

 /* USER CODE BEGIN WHILE */
  
  while (1)
  {
		leds();
		get_adc_value();
		LCD_show();
		key_proc();
		error_proc();
		if(!st_status)
			pwm_out();
		HAL_Delay(50);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

到此所有功能我们都实现了,所有代码如下

/* 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"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lcd.h"
#include <stdio.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 ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;

TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_ADC2_Init(void);
static void MX_TIM2_Init(void);
static void MX_TIM3_Init(void);
static void MX_TIM1_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

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

typedef struct KEY{
	uint8_t sate;// 状态机状态
	uint8_t pin_sate;// 引脚电平是否有效,低电平为1
	
	uint8_t single_click_flag; // 短按
	uint8_t long_click_flag; // 长按
	
	uint16_t press_count; // 按下计数
	uint16_t release_count; // 松开计数
	
}KEY;

KEY keys[4];
// 电位器电压的获取
uint16_t R37_voltage = 0 , R38_voltage;
void get_adc_value(){
	uint16_t temp;
	HAL_ADC_Start(&hadc1);
	HAL_ADC_PollForConversion(&hadc1,20);
	temp = HAL_ADC_GetValue(&hadc1);
	R38_voltage = (3300 * temp) / 4096;
	
	HAL_ADC_Start(&hadc2);
	HAL_ADC_PollForConversion(&hadc2,20);
	temp = HAL_ADC_GetValue(&hadc2);
	R37_voltage = (3300 * temp) / 4096;
	
	HAL_ADC_Stop(&hadc1);
	HAL_ADC_Stop(&hadc2);
}

// 输入频率的捕获
unsigned int fre = 0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
	uint16_t ccr1;
	// 判断定时器和通道是否符合
	if(htim->Instance == TIM2 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){
		ccr1 = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
		fre = (int)1e6 / ccr1;
		__HAL_TIM_SetCounter(htim,0);
	}
}

void key_scan(){
	uint8_t i;
	// 获取引脚状态
	keys[0].pin_sate = HAL_GPIO_ReadPin(B1_GPIO_Port,B1_Pin) == GPIO_PIN_RESET ? 1 : 0;
	keys[1].pin_sate = HAL_GPIO_ReadPin(B2_GPIO_Port,B2_Pin) == GPIO_PIN_RESET ? 1 : 0;
	keys[2].pin_sate = HAL_GPIO_ReadPin(B3_GPIO_Port,B3_Pin) == GPIO_PIN_RESET ? 1 : 0;
	keys[3].pin_sate = HAL_GPIO_ReadPin(B4_GPIO_Port,B4_Pin) == GPIO_PIN_RESET ? 1 : 0;
	for(i=0;i<4;i++){
		switch(keys[i].sate){
			case 0:
				// 按下开始计数
				if(keys[i].pin_sate){
					keys[i].press_count++;
				}
				// 松开时判断是否进入下一个状态
				if(!keys[i].pin_sate){
					if(keys[i].press_count > 3){
						keys[i].sate = 1;
					}else{
						keys[i].press_count = 0;
					}
				} 
			
				break;
			case 1:
				// 松开的消抖
				if(!keys[i].pin_sate){
					keys[i].release_count++;
				}
				if(keys[i].release_count > 3){
					keys[i].sate =2;
				}
				break;
			case 2:
				// 给出对应的flag
			if(keys[i].press_count > 200){ // 超过2s为长按
					keys[i].long_click_flag = 1;
				}
				keys[i].single_click_flag = 1;
				keys[i].press_count = 0;
				keys[i].release_count = 0;
				break;
			default:
				keys[i].sate = 0;
				break;
		}
	}
}

uint32_t runtime = 0; // 运行的时间
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
	// 10ms
	if(htim->Instance == TIM1){
		key_scan();
		runtime +=10;
	}
}

// PWM界面对应的参数
unsigned int CF = 2000; // 输出PWM频率
uint16_t CD = 80; // 输出PWM的占空比
unsigned int *DF = &fre; // 捕获的频率
uint8_t st_status = 0; // 0 为解锁,1为锁定

// RECD界面对应的参数
unsigned int CF_err = 0;
uint16_t CD_err = 0;
unsigned int DF_err = 0;
unsigned int XF  = 0;
uint64_t runtime_err = 0;

// PARA界面对应的参数
uint16_t DS = 1;
uint16_t DR = 80;
unsigned int FS = 100;
unsigned int FR = 2000;

uint8_t page = 0;
char str[30];
void LCD_show(){
	sprintf(str,"                              ");
	switch(page){
		case 0:
			//           12345678901234567890
			sprintf(str,"       PWM          ");
			LCD_DisplayStringLine(Line1,(unsigned char *)str);
			sprintf(str,"   CF=%dHz          ",CF);
			LCD_DisplayStringLine(Line3,(unsigned char *)str);
			sprintf(str,"   CD=%d%%          ",CD);
			LCD_DisplayStringLine(Line4,(unsigned char *)str);
			sprintf(str,"   DF=%dHz          ",*DF);
			LCD_DisplayStringLine(Line5,(unsigned char *)str);
			sprintf(str,"   ST=%s            ",!st_status ? "UNLOCK":"LOCK");
			LCD_DisplayStringLine(Line6,(unsigned char *)str);
		  unsigned int sec = runtime / 1000;
			unsigned int min = sec / 60;
			unsigned int hour  = min / 60;
		  sec = sec - 60*min;
			min = min - min / 60;
			sprintf(str,"   %02dH%02dM%02dS",hour,min,sec);
		  LCD_DisplayStringLine(Line7,(unsigned char *)str);
			break;
		case 1:
			sprintf(str,"       RECD          ");
			LCD_DisplayStringLine(Line1,(unsigned char *)str);
			sprintf(str,"   CF=%dHz          ",CF_err);
			LCD_DisplayStringLine(Line3,(unsigned char *)str);
			sprintf(str,"   CD=%d%%          ",CD_err);
			LCD_DisplayStringLine(Line4,(unsigned char *)str);
			sprintf(str,"   DF=%dHz          ",DF_err);
			LCD_DisplayStringLine(Line5,(unsigned char *)str);
			sprintf(str,"   XF=%dHz            ",XF);
			LCD_DisplayStringLine(Line6,(unsigned char *)str);
		  sec = runtime_err / 1000;
			min = sec / 60;
			hour  = min / 60;
		  sec = sec - 60*min;
			min = min - min / 60;
			sprintf(str,"   %02dH%02dM%02dS",hour,min,sec);
		  LCD_DisplayStringLine(Line7,(unsigned char *)str);
			break;
		case 2:
			sprintf(str,"       PARA          ");
			LCD_DisplayStringLine(Line1,(unsigned char *)str);
			sprintf(str,"   DS=%d%%          ",DS);
			LCD_DisplayStringLine(Line3,(unsigned char *)str);
			sprintf(str,"   DR=%d%%          ",DR);
			LCD_DisplayStringLine(Line4,(unsigned char *)str);
			sprintf(str,"   FS=%dHz          ",FS);
			LCD_DisplayStringLine(Line5,(unsigned char *)str);
			sprintf(str,"   FR=%dHz            ",FR);
			LCD_DisplayStringLine(Line6,(unsigned char *)str);
			break;
	}
}

uint8_t para_choose_index = 0;
void key_proc(){
	// 页面的切换
	if(keys[0].single_click_flag){
		if(page < 2)
			page ++;
		else 
			page = 0;
		LCD_Clear(Black);
		
		// 默认修改DR
		if(page == 2)
			para_choose_index = 0;
		
		keys[0].single_click_flag  = 0;
		keys[0].long_click_flag = 0;
		keys[0].sate = 0;
	}
	// 参数切换以及计时清零,锁定切换
	if(keys[1].single_click_flag){
		if(page == 0 && keys[1].long_click_flag){
			runtime = 0;
		}else if(page == 0){
			st_status = !st_status;
		}
		if(page == 2 ){
			if(para_choose_index < 3)
				para_choose_index ++;
			else
				para_choose_index = 0;
		}
		keys[1].single_click_flag  = 0;
		keys[1].long_click_flag = 0;
		keys[1].sate = 0;
	}
	// 参数加
	if(keys[2].single_click_flag){
			if(page == 2){
				switch(para_choose_index){
					case 0:
						if(DS + 1 < DR)
							DS +=1;
						break;
					case 1:
						if(DR + 10 <= 100)
							DR += 10;
						break;
					case 2:
						if(FS + 100 < FR)
							FS += 100;
						break;
					case 3:
						FR += 1000;
						break;
				default:
						para_choose_index = 0;
			}
		}
		keys[2].single_click_flag  = 0;
		keys[2].long_click_flag = 0;
		keys[2].sate = 0;
	}
	// 参数减
	if(keys[3].single_click_flag){
			if(page == 2){
				switch(para_choose_index){
					case 0:
						if(DS - 1 >= 1)
							DS -=1;
						break;
					case 1:
						if(DR - 10 >= 10)
							DR -= 10;
						break;
					case 2:
						if(FS - 100 >= 100)
							FS -= 100;
						break;
					case 3:
						if(FR - 1000 >= 1000)
							FR -= 1000;
						break;
				default:
						para_choose_index = 0;
			}
		}
		keys[3].single_click_flag  = 0;
		keys[3].long_click_flag = 0;
		keys[3].sate = 0;
	}
}

void pwm_out(){
	uint16_t n = 0;
	// 计算出对应的V_step
	uint16_t V_setp1 = 	(3300*DS)/(DR - 10 ) , V_setp2 = (3300*FS)/(FR -1000);
	// 计算出实际输出占空比
	CD = 10 + (DS * R37_voltage) / V_setp1;
	// 计算出实际输出的频率
	CF = 1000 + (FS * R38_voltage) / V_setp2;
	
	// 计算出所需的ARR和CCR2
	uint16_t arr = (int)1e6 / CF - 1;
	uint16_t comp = (arr * CD) / 100;
	
	__HAL_TIM_SET_AUTORELOAD(&htim3,arr);
	__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,comp);
}

uint8_t error_hold = 0;
void error_proc(){
  int32_t	t = (int32_t)fre - (int32_t)CF;
	if(t < 0)
		t = -t;
	if(t < 1000)
		error_hold = 0;
	if(!error_hold){
		if(t > 1000){
			error_hold  = 1;
			CF_err = CF;
			CD_err = CD;
			DF_err = fre;
			XF = t;
			runtime_err  = runtime;
		}
	}
}

void leds(){
	uint16_t i;
	// close all leds
	HAL_GPIO_WritePin(LED_Ctrl_GPIO_Port,LED_Ctrl_Pin,GPIO_PIN_SET);
	for(i=0;i<8;i++){
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8 << i,GPIO_PIN_SET);
	}
	
	if(page == 0)
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8 << 0,GPIO_PIN_RESET);
	
	if(st_status)
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8 << 1,GPIO_PIN_RESET);
	
	if(error_hold)
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8 << 2,GPIO_PIN_RESET);
	
	HAL_GPIO_WritePin(LED_Ctrl_GPIO_Port,LED_Ctrl_Pin,GPIO_PIN_RESET);
	
}
/* 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_ADC1_Init();
  MX_ADC2_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */
	uint16_t i;
	// close all leds
	HAL_GPIO_WritePin(LED_Ctrl_GPIO_Port,LED_Ctrl_Pin,GPIO_PIN_SET);
	for(i=0;i<8;i++){
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8 << i,GPIO_PIN_SET);
	}
	HAL_GPIO_WritePin(LED_Ctrl_GPIO_Port,LED_Ctrl_Pin,GPIO_PIN_RESET);
	
	for(i=0;i<4;i++){
		keys[i].sate = 0;
		keys[i].pin_sate = 0;
		keys[i].press_count = 0;
		keys[i].release_count = 0;
		keys[i].single_click_flag  = 0;
		keys[i].long_click_flag = 0;
	}
	
	// LCD init
	LCD_Init();
	LCD_SetBackColor(Black);
	LCD_SetTextColor(White);
	LCD_Clear(Black);
	LCD_DisplayStringLine(Line1,(unsigned char *)"Hello World");
	
	HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
	HAL_TIM_Base_Start_IT(&htim1);
	
	HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  
  while (1)
  {
		leds();
		get_adc_value();
		LCD_show();
		key_proc();
		error_proc();
		if(!st_status)
			pwm_out();
		HAL_Delay(50);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* 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();
  }
}

/**
  * @brief ADC1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_ADC1_Init(void)
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */

  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.GainCompensation = 0;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_11;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */

}

/**
  * @brief ADC2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_ADC2_Init(void)
{

  /* USER CODE BEGIN ADC2_Init 0 */

  /* USER CODE END ADC2_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC2_Init 1 */

  /* USER CODE END ADC2_Init 1 */

  /** Common config
  */
  hadc2.Instance = ADC2;
  hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
  hadc2.Init.Resolution = ADC_RESOLUTION_12B;
  hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc2.Init.GainCompensation = 0;
  hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc2.Init.LowPowerAutoWait = DISABLE;
  hadc2.Init.ContinuousConvMode = DISABLE;
  hadc2.Init.NbrOfConversion = 1;
  hadc2.Init.DiscontinuousConvMode = DISABLE;
  hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc2.Init.DMAContinuousRequests = DISABLE;
  hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc2.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_15;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC2_Init 2 */

  /* USER CODE END ADC2_Init 2 */

}

/**
  * @brief TIM1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM1_Init(void)
{

  /* USER CODE BEGIN TIM1_Init 0 */

  /* USER CODE END TIM1_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM1_Init 1 */

  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 800-1;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 999;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */

  /* USER CODE END TIM1_Init 2 */

}

/**
  * @brief TIM2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_IC_InitTypeDef sConfigIC = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 80-1;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 4294967295;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_IC_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */

}

/**
  * @brief TIM3 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 80-1;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 65535;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */

  /* USER CODE END TIM3_Init 2 */
  HAL_TIM_MspPostInit(&htim3);

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0
                          |GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4
                          |GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LED_Ctrl_GPIO_Port, LED_Ctrl_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5|GPIO_PIN_8|GPIO_PIN_9, GPIO_PIN_RESET);

  /*Configure GPIO pins : PC13 PC14 PC15 PC0
                           PC1 PC2 PC3 PC4
                           PC5 PC6 PC7 PC8
                           PC9 PC10 PC11 PC12 */
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0
                          |GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4
                          |GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin : B4_Pin */
  GPIO_InitStruct.Pin = B4_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(B4_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : B1_Pin B2_Pin B3_Pin */
  GPIO_InitStruct.Pin = B1_Pin|B2_Pin|B3_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PA8 */
  GPIO_InitStruct.Pin = GPIO_PIN_8;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : LED_Ctrl_Pin */
  GPIO_InitStruct.Pin = LED_Ctrl_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LED_Ctrl_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : PB5 PB8 PB9 */
  GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_8|GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

/* 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 */

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐