前幾天剛剛參加完第十四屆的省賽,這屆題目比我想象中的要難,其實想一想這也是應該的,以前的知識點都被摸透了,也是需要加入新的知識點了,但是我還是想說能不能別在我參加的時候加大題目難度啊。
不過聽說隔壁單片機的省賽都比往年的國賽還難,這就有點離譜了。好了,進入正題了,老規(guī)矩先看看客觀題。
客觀題
收集的一些歷年的比賽客觀題和解析,以及程序設計題的PDF,在這里分享給大家。?
鏈接:https://pan.baidu.com/s/1hTw0inSbLjX57hOtankgKw?
提取碼:np1p
有什么不理解的地方,可以在評論區(qū)提出來嗷。
程序設計題?
題目解析
這屆題目用到的模塊是LCD,LED,按鍵,ADC,PWM和脈沖捕獲。其中新考點就是按鍵的長按和脈沖輸入捕獲。
按鍵長按的話,由于我是在定時器中每10ms掃描一次按鍵,按照題目要求長按時間是2s以上,所以設置一個變量用來計數(shù),如果在按鍵松開時計數(shù)值達到200以上就是長按,否則就是短按。
脈沖捕獲,其實就是使用定時器獲得一個方波周期的時間,再用定時器頻率 / 時間t就可以計算出引腳的輸出頻率了。
?如圖所示,當有上升沿發(fā)生就進入中斷,開始計時,當下一個上升沿來到時也進入中斷,這就可以獲得時間t計算出頻率,然后再清除t的值,具體看代碼。再多使用一個通道捕獲下降沿的時間t1,就可以計算出占空比,用高電平的時間t1?/ 總的時間t。感興趣的可以試試,多準備準備,以防下次會考。說完了,那就配置CubeMX吧。
CubeMX配置
時鐘配置完了,需要按下回車(Enter)來保存。?
?根據(jù)原理圖配置GPIO引腳,其中l(wèi)cd和led的引腳都設置為output,按鍵設置為input,PB15設置為ADC2的15通道,PA1設置為定時器2的第2通道,PA7設置為定時器17的通道1,需要把PD2也設置為output用來作為led的鎖存器。?
?在GPIO中選中按鍵的引腳,設置為上拉輸入模式。?
在GPIO中,選中l(wèi)ed的引腳,設置為初始狀態(tài)為高電平,推挽輸出模式,既不上拉也不下拉。其他引腳使用默認設置就是行。
設置定時器3每10ms中斷一次。?
?
定時器2的通道2設置為PWM通道2,然后設置預分頻器值和自動重裝值以及占空比。
開啟定時器中斷,設置通道1為上升沿的輸入捕獲。
勾選ADC2的第15通道,其他設置默認就行。?
設置項目名字和保存路徑(建議不要有中文),以及IDE的版本。??
?
?勾選這個主要是讓.c和.h文件單獨分開,之后就可以生成代碼了,CubeMX配置就完成了,如果之后想要添加新的模塊或者修改配置好了模塊的值,可以直接在文件中打開CubeMX的工程進行修改,改完后再點擊GENERATE CODE就行了。
代碼演示?
main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2023 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "tim.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "sys.h"
#include "show.h"
#include "lcd.h"
#include "timer.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 uint8_t btn,long_btn; //按鍵短按值,和key4的長按標志
extern uint32_t f; //是捕獲計算的頻率
bool choice = 0; //0是參數(shù)R,1是參數(shù)K
bool fre_flag = 0; //切換高低頻模式的鎖,為1時不能切換
bool lock = 0; //為1時占空比鎖定
char M='L'; //L是低頻模式,H是高頻模式
uint8_t jm = 0; //0是數(shù)據(jù)界面,1是參數(shù)界面,2記錄界面
uint16_t P = 100; //占空比
uint8_t N = 0;
uint8_t R = 1,K = 1;
uint8_t tempR = 1,tempK = 1;
float V = 0.0f,MH = 0.0f,ML = 0.0f;
float Volt = 0.0f;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* 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_ADC2_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_TIM17_Init();
/* USER CODE BEGIN 2 */
LCD_Init();
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
HAL_TIM_Base_Start_IT(&htim3);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&htim17,TIM_CHANNEL_1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
Volt = getADC(&hadc2);
V = (f*2*R*3.14f)/(100*K);
switch(btn)
{
case 1:
{
Key1();
btn = 0;
}
break;
case 2:
{
Key2();
btn = 0;
}
break;
case 3:
{
Key3();
btn = 0;
}
break;
case 4:
{
Key4();
btn = 0;
}
break;
}
if(long_btn && 0 == jm)
{
lock = 1;
long_btn = 0;
}
if(0==jm)
DATA();
else if(1==jm)
PARA();
else
RECD();
LED_Hint(); //處理LED
InferDuty(); //調(diào)整占空比
InferFre(); //計算最大最小速度值
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
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();
}
}
/* 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 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
main.h
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* Copyright (c) 2023 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 */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32g4xx_hal.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
main.h中添加了幾個頭文件和define。
sys.c
#include "sys.h"
Btn key[4] = {0};
uint8_t btn = 0, long_btn = 0;
uint16_t LED = 0xff00;
extern uint8_t jm;
extern bool L2_flag;
extern bool fre_flag;
extern bool lock, choice;
extern uint8_t R ,K ,N;
extern uint8_t tempR ,tempK;
void LED_SET(void)
{
GPIOC->ODR = (uint32_t)LED;
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
void LED_Hint(void)
{
if(0 == jm)
{
LED &= ~(0x01ff);
LED_SET();
}
else
{
LED |= 0x0100;
LED_SET();
}
if(1 == L2_flag && 1 == fre_flag)
{
LED &= ~(0x02ff);
LED_SET();
}
else
{
LED |= 0x0200;
LED_SET();
}
if(1 == lock)
{
LED &= ~(0x04ff);
LED_SET();
}
else
{
LED |= 0x0400;
LED_SET();
}
}
void KEY_Scan(void)
{
uint8_t i;
key[0].press = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);
key[1].press = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);
key[2].press = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);
key[3].press = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
for(i=0;i<4;i++)
{
switch(key[i].state)
{
case 0:
if(key[i].press == 0)
key[i].state = 1;
break;
case 1:
{
if(key[i].press == 0)
{
key[i].state = 2;
btn = i+1;
if(3 == i)
key[i].long_time = 1;
}
else
key[i].state = 0;
}
break;
case 2:
{
if(key[i].press == 1)
{
key[i].state = 0;
if(key[3].long_time>=200)
long_btn = i+1;
else
key[3].long_time++;
}
if(3 == i)
key[3].long_time++;
}
break;
}
}
}
float getADC(ADC_HandleTypeDef *pin)
{
uint16_t adc;
HAL_ADC_Start(pin);
adc = HAL_ADC_GetValue(pin);
return adc*3.3/4096;
}
void Key1(void) //按鍵1需要完成的功能
{
if(3 == ++jm)
jm = 0;
if(1 == jm)
{
tempR = R;
tempK = K;
}
else // 從參數(shù)界面退出時,新的 R 參數(shù)和 K 參數(shù)生效。
{
R = tempR;
K = tempK;
}
choice = 0;
LCD_Clear(Black);
}
void Key2(void) //按鍵2需要完成的功能
{
if(0 == jm && 0 == fre_flag)
{
fre_flag = 1;
N++;
}
if(1 == jm)
{
choice ^= 1;
}
}
void Key3(void) //按鍵3需要完成的功能
{
if(1 == jm)
{
if(0 == choice)
{
if(++tempR>10)
tempR = 1;
}
else
{
if(++tempK>10)
tempK = 1;
}
}
}
void Key4(void) //按鍵4需要完成的功能
{
if(1 == jm)
{
if(0 == choice)
{
if(--tempR<1)
tempR = 10;
}
else
{
if(--tempK<1)
tempK = 10;
}
}
if(0 == jm)
lock = 0;
}
sys.h
#ifndef __SYS_H
#define __SYS_H
#include "main.h"
#include "lcd.h"
typedef struct{
bool press;
uint8_t state;
uint16_t long_time;
}Btn;
void LED_SET(void);
void LED_Hint(void);
void KEY_Scan(void);
float getADC(ADC_HandleTypeDef *pin);
void Key1(void);
void Key2(void);
void Key3(void);
void Key4(void);
#endif
led使用寄存器,目的是單獨控制一個LED燈時不干擾其他LED燈,使用HAL庫函數(shù),改變一個燈的值,會干擾到其他燈的顯示,有沒有好心人在評論區(qū)告知一下怎么使用HAL庫才不會有這種情況,感謝。??
show.c
#include "show.h"
char text[21] = {0};
extern uint8_t N,R,K;
extern uint16_t P;
extern uint16_t fre;
extern float V,MH,ML;
extern char M;
extern float Volt;
extern bool lock;
extern uint8_t tempR,tempK;
void LCD_SHOW(uint8_t line, char *text)
{
LCD_DisplayStringLine(line*24, (u8 *)text);
}
void DATA(void)
{
sprintf(text," DATA ");
LCD_SHOW(1,text);
sprintf(text," M=%c ",M);
LCD_SHOW(3,text);
sprintf(text," P=%d%% ",P);
LCD_SHOW(4,text);
sprintf(text," V=%.1f ",V);
LCD_SHOW(5,text);
}
void PARA(void)
{
sprintf(text," PARA ");
LCD_SHOW(1,text);
sprintf(text," R=%d ",tempR);
LCD_SHOW(3,text);
sprintf(text," K=%d ",tempK);
LCD_SHOW(4,text);
}
void RECD(void)
{
sprintf(text," RECD ");
LCD_SHOW(1,text);
sprintf(text," N=%d ",N);
LCD_SHOW(3,text);
sprintf(text," MH=%.1f ",MH);
LCD_SHOW(4,text);
sprintf(text," ML=%.1f ",ML);
LCD_SHOW(5,text);
}
void InferDuty(void)//調(diào)整占空比
{
if(lock == 0)
{
if(Volt<=1.0f)
{
P = 10*(fre+1)/100;
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,P);
}
else if(Volt>=3.0f)
{
P = 85*(fre+1)/100;
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,P);
}
else
{
P = 37.5f*Volt-27.5f;
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,P*(fre+1)/100);
}
}
}
void InferFre(void)//計算最大最小速度值
{
ML = (4000*2*R*3.14f)/(100*K);
MH = (8000*2*R*3.14f)/(100*K);
}
show.h
#ifndef __SHOW_H
#define __SHOW_H
#include "main.h"
#include "lcd.h"
#include "tim.h"
void LCD_SHOW(uint8_t line, char *text);
void DATA(void);
void PARA(void);
void RECD(void);
void InferDuty(void);
void InferFre(void);
#endif
timer.c
#include "timer.h"
uint16_t CCR1 = 0;
uint32_t fre_CNT = 0;
uint16_t fre = 999;
uint32_t f = 0;
uint8_t L2_CNT = 0;
bool L2_flag = 0;
extern bool fre_flag;
extern char M;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM3)
{
KEY_Scan();
if(1 == fre_flag) //高低頻模式切換,5秒鐘內(nèi)保證占空比不變,頻率每10ms加減一
{ //500次剛好完成高低頻模式切換需要改變的自動重裝載值
if(++fre_CNT>500)
{
fre_flag = 0;
fre_CNT = 0;
if('L' == M)
M = 'H';
else
M = 'L';
}
else
{
if('L' == M)
{
fre--;
__HAL_TIM_SET_AUTORELOAD(&htim2,fre);
}
else
{
fre++;
__HAL_TIM_SET_AUTORELOAD(&htim2,fre);
}
}
if(++L2_CNT>10)
{
L2_flag ^= 1;
L2_CNT = 0;
}
}
}
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
/*PWM 信號上升沿時,會進入中斷,IC1會捕獲,對應的是周期寬度測量*/
if(htim->Instance == TIM17)
{
if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)
{
CCR1 = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
__HAL_TIM_SetCounter(htim,0);
f = (80000000/80)/(CCR1+1);
HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);
}
}
}
timer.h
#ifndef __TIMER_H
#define __TIMER_H
#include "main.h"
#include "tim.h"
#include "sys.h"
#endif
以上就是我修改過的文件和新添加的文件。還有l(wèi)cd模塊,不過不需要我們自己寫,官方有提供,直接復制過來就行,注意有三個文件,別只復制lcd.c和lcd.h。
文章來源:http://www.zghlxwxcb.cn/news/detail-736266.html
好了,以上就是藍橋杯嵌入式第十四屆省賽的題目解析了,如果有什么問題和建議都歡迎在評論區(qū)提出來喔。?文章來源地址http://www.zghlxwxcb.cn/news/detail-736266.html
到了這里,關于藍橋杯嵌入式第十四屆省賽題目解析的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!