文章目录
前言
临近比赛了,最后在写一篇最新的真题来巩固复习一下比赛用的知识,同时也希望最后几天能帮助到小伙伴们,一起努力在比赛中取得好名次。废话不多说,来看真题。
一、题目介绍
二、重难点介绍
1.重难点分析
这届的试题还是有点难度的,主要考查了PWM和定时器的输入捕获,重点在定时器的使用和高低频的切换斜率图得出占空比的数学公式,有点容易让人头脑混乱。但是抓住了其中的本质,还是能够解决的。
三、题解
1、相关定义:
char view=0;
char led=0;
char led2_flag=0;
char fre_flag=0;
char M='L';
float max_h,max_l=0;//
float volt=0.0;
float v=0.0;
uint32_t f=0;
uint8_t lock=0;
uint8_t Num=0;
uint8_t H_flag,L_flag=0;
uint8_t R=1,K=1;
uint8_t R_flag=1,K_flag=0;
uint8_t text[20];
uint16_t P=100;
extern struct keys key[4];
void led_pro();
void lcd_pro(void);
void key_pro(void);
2、LED显示以及处理函数:
void LED_Disp(char dsLED)
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);//让所有GPIOC置高电平,灯泡熄灭。
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);
}
void led_pro()
{
if(view==0)
{
led|=1;
}
else if(view==1||view==2)
{
led&=~1;
}
if(fre_flag==1&&led2_flag==1)
{
led^=2;
}
else if(fre_flag==0)
{
led&=~(1<<1);
}
if(lock==1)
{
led|=1<<2;
}
else if(lock==0)
{
led&=~(1<<2);
}
}
3、按键扫描以及处理函数:
//定义
struct keys key[4]={0,0,0};
struct keys
{
char judge_sta;
bool key_sta;
bool single_flag;
bool long_flag;
uint8_t key_time;
};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM16)
{
key[0].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key[1].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key[2].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key[3].key_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
for(int i=0;i<4;i++)
{
switch (key[i].judge_sta)
{
case 0:
{
if(key[i].key_sta==0)
{
key[i].judge_sta=1;
key[i].key_time=0;
}
}
break;
case 1:
{
if(key[i].key_sta==0)
{
key[i].judge_sta=2;
}
}
break;
case 2:
{
if(key[i].key_sta==1)
{
key[i].judge_sta=0;
if(key[i].key_time<200)
{
key[i].single_flag=1;
}
}
else{
key[i].key_time++;
if(key[i].key_time>200)
{
key[i].long_flag=1;
}
}
}
break;
}
}
}
}
//处理函数
void key_pro(void)
{
if(key[0].single_flag==1)
{
view++;
if(view>2)
{
view=0;
}
LCD_Clear(Black);
key[0].single_flag=0;
}
if(key[1].single_flag==1)
{
if(view==0&&fre_flag==0)
{
fre_flag=1;
Num++;
}
if(view==1)
{
if(R_flag==1)
{
R_flag=0;
K_flag=1;
}
else
{
R_flag=1;
K_flag=0;
}
}
key[1].single_flag=0;
}
if(key[2].single_flag==1)
{
if(R_flag==1)
{
R++;
if(R>10)
{
R=1;
}
}
if(K_flag==1)
{
K++;
if(K>10)
{
K=1;
}
}
key[2].single_flag=0;
}
if(key[3].single_flag==1)
{
if(view==0)
{
lock=0;
}
if(view==1)
{
if(R_flag==1)
{
R--;
if(R<1)
{
R=10;
}
}
if(K_flag==1)
{
K--;
if(K==0)
{
K=10;
}
}
}
key[3].single_flag=0;
}
if(key[3].long_flag==1)
{
lock=1;
key[3].long_flag=0;
}
}
4、LCD处理函数:
void lcd_pro(void)
{
if(view==0)
{
sprintf((char *)text," DATA");
LCD_DisplayStringLine(Line2,text);
sprintf((char *)text," M=%c",M);
LCD_DisplayStringLine(Line4,text);
sprintf((char *)text," P=%d%%",P);
LCD_DisplayStringLine(Line5,text);
sprintf((char *)text," V=%.1f",v);
LCD_DisplayStringLine(Line6,text);
sprintf((char *)text," V=%d",f);
LCD_DisplayStringLine(Line8,text);
}
if(view==1)
{
sprintf((char *)text," PARA");
LCD_DisplayStringLine(Line2,text);
sprintf((char *)text," R=%d ",R);
LCD_DisplayStringLine(Line4,text);
sprintf((char *)text," K=%d ",K);
LCD_DisplayStringLine(Line5,text);
}
//´¦ÓÚͳ¼Æ½çÃæÊ±
if(view==2)
{
sprintf((char *)text," RECT");
LCD_DisplayStringLine(Line2,text);
sprintf((char *)text," N=%d",Num);
LCD_DisplayStringLine(Line4,text);
sprintf((char *)text," MH=%.1f",max_h);
LCD_DisplayStringLine(Line5,text);
sprintf((char *)text," ML=%.1f",max_l);
LCD_DisplayStringLine(Line6,text);
}
}
5、PWM捕获以及高低频切换处理函数:
//定义
uint8_t led2_cnt=0;
uint32_t fre_cnt=0;//切换低频到高频的计数值 记到500就是5秒
uint16_t fre=999;//频率为4khz的重装值
uint32_t ccrval=0;//定时器输入捕获值
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM17)
{
ccrval=HAL_TIM_ReadCapturedValue(&htim17,TIM_CHANNEL_1);
//用于计数器清零 为下次捕获做好准备
__HAL_TIM_SetCounter(&htim17,0);
f=(80000000/80)/(ccrval+1);
//为这个重新开启定时器输入捕获
HAL_TIM_IC_Start(&htim17,TIM_CHANNEL_1);
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM3)
{
if(fre_flag == 1) //高低频模式切换,5秒钟内保证占空比不变,频率每10ms加减一
{ //500次刚好完成高低频模式切换需要改变的自动重装载值
if(fre_cnt++>500)
{
fre_flag = 0;
fre_cnt = 0;
if(M == 'L')
M = 'H';
else
M = 'L';
}
else
{
if(M == 'L')
{
fre--;
__HAL_TIM_SET_AUTORELOAD(&htim2,fre);
}
else
{
fre++;
__HAL_TIM_SET_AUTORELOAD(&htim2,fre);
}
}
if(led2_cnt++>10)
{
led2_flag=1;
led2_cnt=0;
}
}
}
}
6、获取ADC函数:
//通过adc值来获取电压值 使R37调整电位器
float getADC(ADC_HandleTypeDef *pin)
{
uint16_t adc;
HAL_ADC_Start(pin);
adc = HAL_ADC_GetValue(pin);
return adc*3.3/4096;
}
7、主函数:
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_TIM2_Init();
MX_TIM3_Init();
MX_TIM4_Init();
MX_ADC2_Init();
MX_TIM17_Init();
MX_TIM16_Init();
/* USER CODE BEGIN 2 */
LED_Disp(0x00);
LCD_Init();
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
HAL_TIM_Base_Start_IT(&htim16);
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)
{
volt=getADC(&hadc2);
v=(f*2*R*3.14f)/(100*K);
led_pro();
key_pro();
lcd_pro();
InferDuty();
InferFre();
LED_Disp(led);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
总结
最后题目就讲解到这里了,因为这次事件比较赶,没有像以往一样写注释和更深入分析了,希望小伙伴们多多见谅,如果有需要的话可以看看最后的源码,最后祝愿小伙伴们在后天的比赛都能取得理想的名次。
源码:
链接:https://pan.baidu.com/s/1PobayhziKU4czu9uCa6oMA?pwd=3rkb
提取码:3rkb
–来自百度网盘超级会员V3的分享