> 文章列表 > 【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 

目录

0 题目介绍

1 题目分析

2 Cubemx配置

4 代码

5 效果显示


 

0 题目介绍

具体要求如下图

【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

1 题目分析

拿到题目咋一看,就是基本操作,实际做起来一堆定时器操作,很容易把人绕晕。

首先看看需要用到的外设

1. GPIO(key/led)

2.LCD

3.输入捕获(TIM3通道2)和PWM(TIM2通道2)

4.ADC(R37)

这里首先得有个概念,碰到定时之类的,应该想到标志位+计数器的组合,用标志位触发定时器计数,把开始的过程和最终执行的过程分离开来,减少代码耦合。

2 Cubemx配置

配置完成如下:

【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 

时钟树配置如下(确保SYSCLK=80M)

【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

GPIO配置过(LED设置INPUT初始状态高,PD12使能位INPUT,KEY设置位OUTPUT) 

ADC配置如下

【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

定时器2  TIM2通道二(PWM输出配置PA1)这里80M预分频79后为1M,初始阶段频率1M/(999+1)=1Khz(题目要求4000,后面代码里具体设置)

【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 定时器3 TIM3通道二(输入捕获输出配置PA7)

这里简单介绍一下:触发源选TI2FP2(因为PA7是TIM3_CH2),选这个后PA7就会变绿,时钟选内部时钟(80M),通道二(Channel)作为主通道(PA7对的是通道二),通道一作为从通道。

主通道(通道2)检测上升沿,从通道(通道1)检测下降沿(计算频率只需要计算上升沿的捕获值,计算占空比根据上升沿和下降沿的比例关系计算)。

预分频还是79(+1)后到1M。

【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 tim2中断打开(整个题目唯一用到的中断)【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 生成文件

【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 移植lcd相关文件头文件,创建一个user.c和user.h(个人习惯)放一些功能代码,主要代码全写在main.c文件中(如果缺少.s文件,请自行添加)【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 编译保证不报错。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbGnmn5DlvIDov4flhYnvvIg15Z2X77yJ,size_12,color_FFFFFF,t_70,g_se,x_16

4 代码

自己需要写的文件只有两个

1. user.c和user.h

2.main.c

user文件如下,这个没啥好说的

user.h:

#include "main.h"void Led_Disp(unsigned char c);
unsigned char Key_Scan(void);uint16_t getADC2(void);

user.c:

#include "user.h"
#include "adc.h"//灯
void Led_Disp(unsigned char c)
{//全部熄灭HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);//点亮对应位HAL_GPIO_WritePin(GPIOC, c<<8, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}//按键扫描
unsigned char Key_Scan(void)
{unsigned char c;if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==GPIO_PIN_RESET){c = 1;}else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==GPIO_PIN_RESET){c = 2;}else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==GPIO_PIN_RESET){c = 3;}else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET){c = 4;}return c;
}//adc
uint16_t getADC2(void)
{uint16_t adc = 0;HAL_ADC_Start(&hadc2);adc = HAL_ADC_GetValue(&hadc2);return adc;
}

主函数这里使用了一个100ms执行一次的计数器和50ms执行一次的计数器,100ms主要控制那个灯闪烁的需求,其他定时都放在50ms函数中。

可以根据测试数据来观察定时器的作用

【蓝桥杯嵌入式】蓝桥杯嵌入式2023年第十四届省赛真题解答

 timer_b2是按键2相关的计时器, timer_b4是按键4相关的计时器,timer_MH是题目那个保持2s需求的计时器

flag是对应的标志位,具体功能见注释

屏幕第九行是adc电压值和cap采集的频率

main.c


#include "main.h"
#include "adc.h"
#include "tim.h"
#include "gpio.h"#include "lcd.h"
#include "user.h"
#include <stdio.h>void keyPro(void);
void lcdPro(void);
void ledPro(void);
void ADCPro(void);
void timer_100(void);
void timer_50(void);//tim2   pwm
//tim3   cap__IO uint32_t uwtick_Key,uwtick_Lcd,uwtick_Led,uwtick_ADC,uwtick_timer_200,uwtick_timer_100,uwtick_timer_50;//key
unsigned char Key_Value,Key_Old,Key_Up,Key_Dowm;
unsigned char page = 1;//lcd
unsigned char str[25];
unsigned char test;//*pwm相关变量unsigned char PWM_Mode = 0;
unsigned char PWM_p = 0;
float V = 10;  //V值
float V_old = 10;  //上一次的V值,用于判断V是否稳定uint16_t CAP1_UP_Count;  //上升沿捕获值
uint16_t CAP1_DOWM_Count;  //下降沿捕获值
float CAP1_Duty;  //捕获占空比int32_t PWM1_Duty = 10;  //PWM输出占空比控制
int32_t PWM1_F = 249;   //PWM输出频率控制unsigned char R = 1;  //R
unsigned char K = 1;  //K
unsigned char N = 0;  //N
float MH = 10;  //低频最大值
float ML = 10;  //高频最大值unsigned char select_R_K = 0;  //选择R K
unsigned char lock_b4 = 0;  //ADC上锁
float adc_value = 0;  //ADC值//timer 
int timer_b2 = 0;
int timer_b4 = 0;
int timer_MH = 0; 
int timer_ML = 0; 
//标志位
unsigned flag_b2 = 0;  //1代表正在运行中
int flag_b4 = 0;  //0 没有按下  1上升沿 2下降沿
int flag_MHL = 0; //0没超过  1低超过 2高超过void SystemClock_Config(void);int main(void)
{HAL_Init();SystemClock_Config();LCD_Init();MX_GPIO_Init();MX_ADC2_Init();MX_TIM2_Init();MX_TIM3_Init();//capHAL_TIM_Base_Start(&htim3);HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);//pwmHAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);__HAL_TIM_SET_AUTORELOAD(&htim2,124);   //4k=249   8k=124//__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,124/10);  LCD_Clear(Black);LCD_SetBackColor(Black); LCD_SetTextColor(White);while (1){ADCPro();lcdPro();keyPro();ledPro();timer_100();//灯闪烁时用timer_50();}}void lcdPro(void)
{if(uwTick - uwtick_Lcd<100) return;uwtick_Lcd = uwTick;if(page == 1)  //数据界面{sprintf((char *)str,"        DATA  ");			LCD_DisplayStringLine(Line1,str);	if(PWM_Mode == 0){sprintf((char *)str,"     M=L ");	}else{sprintf((char *)str,"     M=H ");	}	PWM_p = PWM1_Duty;LCD_DisplayStringLine(Line3,str);	sprintf((char *)str,"     P=%02d%%     ",PWM_p);			LCD_DisplayStringLine(Line4,str);	sprintf((char *)str,"     V=%3.1f     ",V);			LCD_DisplayStringLine(Line5,str);	}else if(page == 2)  //参数界面{sprintf((char *)str,"        PARA  ");		LCD_DisplayStringLine(Line1,str);		if(select_R_K == 0){LCD_SetTextColor(Green);}sprintf((char *)str,"     R=%d   ",R);			LCD_DisplayStringLine(Line3,str);		LCD_SetTextColor(White);  //恢复if(select_R_K == 1){LCD_SetTextColor(Green);}sprintf((char *)str,"     K=%d   ",K);	LCD_DisplayStringLine(Line4,str);		LCD_SetTextColor(White);  //恢复}else if (page == 3)  //统计界面{sprintf((char *)str,"        RECD  ");			LCD_DisplayStringLine(Line1,str);		sprintf((char *)str,"     N=%d  ",N);			LCD_DisplayStringLine(Line3,str);		sprintf((char *)str,"     MH=%4.1f  ",MH);			LCD_DisplayStringLine(Line4,str);		sprintf((char *)str,"     ML=%4.1f  ",ML);			LCD_DisplayStringLine(Line5,str);				}//测试用  提交时屏蔽sprintf((char *)str,"t1:%dt2:%dt3:%dt4:%d    ",timer_b2,timer_b4,timer_ML,timer_MH);			LCD_DisplayStringLine(Line7,str);sprintf((char *)str,"b2:%d b4:%d MHL:%d   ",flag_b2,flag_b4,flag_MHL);			LCD_DisplayStringLine(Line8,str);//adcsprintf((char *)str, "R37:%4.2fV PWM:%d ",adc_value,1000000/CAP1_UP_Count);LCD_DisplayStringLine(Line9, str);		
}void keyPro(void)
{if(uwTick - uwtick_Key<50) return;uwtick_Key = uwTick;Key_Value = Key_Scan();Key_Dowm = Key_Value&(Key_Value^Key_Old);Key_Up = ~Key_Value&(Key_Value^Key_Old);if(Key_Value==4&&Key_Old==4&&page==1){flag_b4 = 1;}else if(Key_Value!=4&&Key_Old==4&&page==1){flag_b4 = 2;}else{flag_b4 = 0;}Key_Old = Key_Value;if(Key_Dowm == 1){LCD_Clear(Black);if(page == 1){page = 2;}else if(page == 2){page = 3;}else{page = 1;}}else if(Key_Dowm == 2){if(page == 1)  //数据界面{if(flag_b2 == 0){flag_b2 =1;}}if(page == 2)	//参数界面{if(select_R_K == 0){select_R_K = 1;}else{select_R_K = 0;}}}else if(Key_Dowm == 3){if(page == 2){if(select_R_K == 0) //R++{R++;if(R>10){R=1;}}else  //K++{K++;if(K>10){K=1;}		}}}else if(Key_Dowm == 4){if(page == 2){if(select_R_K == 0) //R--{R--;if(R==0){R=10;}}else  //K--{K--;if(K==0){K=10;}		}}		}
}//定时相关处理 50ms/次
void timer_50(void)
{if(uwTick - uwtick_timer_50<50) return;uwtick_timer_50 = uwTick;//时间累加if(flag_b4==1){timer_b4+=50;}if(flag_b2 == 1){timer_b2+=50;if(PWM_Mode ==1)//4000-8000对应249-124  125/5次 {PWM1_F += 2;   if(PWM1_F>249){PWM1_F = 249;}}else{PWM1_F -= 2; if(PWM1_F<124){PWM1_F=124;}}}if(flag_MHL == 1){timer_ML+=50;}else if(flag_MHL == 2){timer_MH+=50;}else{timer_ML = 0;timer_MH = 0;}//判断执行//b4长短按2sif(flag_b4==2){if(page==1&&timer_b4>2000)//长按{if(lock_b4 == 0){lock_b4 = 1;						}}else  //短按{if(page==1&&lock_b4 == 1){lock_b4 = 0;}}}else if(flag_b4==0){timer_b4 = 0;}//b2记时5s PWM高低模式切换	if(flag_b2 == 1&&timer_b2>5000){flag_b2 = 0;timer_b2 = 0;N++;if(PWM_Mode == 0){PWM_Mode = 1;					}else{PWM_Mode = 0;}}//MH2sif(timer_MH>2000)//低频最大值{MH = V;flag_MHL = 0;}else if(timer_ML>2000){ML = V;flag_MHL = 0;}
}unsigned char lednum;  void ledPro(void)
{if(uwTick - uwtick_Led<100) return;uwtick_Led = uwTick;if(page == 1){lednum|=0x1;}else{lednum&=0xfe;}if(lock_b4 == 1){lednum|=0x04;}else{lednum&=0xfb;}Led_Disp(lednum);
}unsigned char led2flag;  //闪烁标志void timer_100(void)
{if(uwTick - uwtick_timer_100<100) return;uwtick_timer_100 = uwTick;if(timer_b2>0) //闪烁{if(led2flag ==0){led2flag = 1;lednum |=0x2;}else if(led2flag == 1){led2flag = 0;lednum &=0xfd;}}	else{lednum &=0xfd;}	
}void ADCPro(void)
{if(uwTick - uwtick_ADC<150) return;uwtick_ADC = uwTick;adc_value = getADC2()*3.3/4096;//ad转换成占空比if(lock_b4 ==0){if(adc_value<1.0){PWM1_Duty = 10;}else if(adc_value>3.0){PWM1_Duty = 85;}else{PWM1_Duty = 10+ (adc_value-1)*75/2;}}V = (1000000/CAP1_UP_Count)*2*3.14*R/100/K;//需要判断V值是否保持if(V==V_old&&PWM_Mode==0&&V>ML)  //低频下{flag_MHL = 1;}else if(V==V_old&&PWM_Mode==1&&V>MH) //高频下{flag_MHL = 2;}else{flag_MHL = 0;}V_old = V;//频率__HAL_TIM_SET_AUTORELOAD(&htim2,PWM1_F);   //4k//占空比__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,PWM1_F*PWM1_Duty/100);  }//中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2){CAP1_UP_Count =  HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2)+1;CAP1_Duty = (float)CAP1_DOWM_Count/CAP1_UP_Count;}else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){CAP1_DOWM_Count =  HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1)+1;}		
}void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};RCC_PeriphCLKInitTypeDef PeriphClkInit = {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();}/** Initializes the peripherals clocks*/PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC12;PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK){Error_Handler();}
}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 *//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

5 效果显示

抖音同名