(本文基于蓝桥杯嵌入式组国信长天板子编写)

剩余工程配置可参考:蓝桥杯嵌入式组工程创建举例

首先介绍的是捕获模式

根据原理图可以知道PB4跟PA15分别连接J9,J10来捕获旋钮的输出频率,所以我们可以做出如下引脚配置

以下介绍两种捕获的设置模式

第一种不用打开NVIC,将主通道(我这里是第一通道)设置为直接捕获,次通道(我这里是第二通道)设置为间接捕获,然后将PSC设置为80-1,因为配置时钟时是配置成80M,频率 = 系统时钟 / (PSC + 1) / (ARR + 1),后续只需要修改ARR就能改变频率,可以直接用1e6 / (ARR+ 1)。   占空比 = 间接通道 。(还需要将通道一设置为上升沿触发,通道二设置为下降沿触发,截图漏了)

配置完成之后编写对应驱动程序

首先需要自行打开定时器IC捕获,该方法使用到了通道一与通道二,所以都需要打开

HAL_TIM_IC_Start(&htim2,TIM_CHANNEL_1);
HAL_TIM_IC_Start(&htim2,TIM_CHANNEL_2);
HAL_TIM_IC_Start(&htim3,TIM_CHANNEL_1);
HAL_TIM_IC_Start(&htim3,TIM_CHANNEL_2);

以下是读取计算函数以及屏幕显示函数

uint32_t R39_freq,R40_freq;
uint8_t R39_Duty,R40_Duty;
void TIM_process(void){
	R40_freq = 1e6 / (HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1) + 1);
	R40_Duty = (HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_2) + 1) * 100 / (HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1) + 1);
	
	R39_freq = 1e6 / (HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1) + 1);
	R39_Duty = (HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_2) + 1) * 100 / (HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1) + 1);
}
uint8_t lcd_buff[30];
void lcd_process(){
	if(lcd_mode == 1){
		sprintf((char *)lcd_buff,"Time1:%d  ",time1);
		LCD_DisplayStringLine(Line0,lcd_buff);
		sprintf((char *)lcd_buff,"Time2:%d   ",time2);
		LCD_DisplayStringLine(Line1,lcd_buff);
		sprintf((char *)lcd_buff,"Time3:%d   ",time3);
		LCD_DisplayStringLine(Line2,lcd_buff);
		sprintf((char *)lcd_buff,"Time4:%d   ",time4);
		LCD_DisplayStringLine(Line3,lcd_buff);
	}else if(lcd_mode == 0){

	}
	
	
	sprintf((char *)lcd_buff,"r37_val:%.2f  ",r37_val);
	LCD_DisplayStringLine(Line4,lcd_buff);
	sprintf((char *)lcd_buff,"r38_val:%.2f   ",r38_val);
	LCD_DisplayStringLine(Line5,lcd_buff);
	sprintf((char *)lcd_buff,"R39_freq:%d     ",R39_freq);
	LCD_DisplayStringLine(Line6,lcd_buff); 
	sprintf((char *)lcd_buff,"R40_freq:%d     ",R40_freq);
	LCD_DisplayStringLine(Line8,lcd_buff);
	sprintf((char *)lcd_buff,"R39_Duty:%d%%    ",R39_Duty);
	LCD_DisplayStringLine(Line7,lcd_buff);
	sprintf((char *)lcd_buff,"R40_Duty:%d%%   ",R40_Duty);
	LCD_DisplayStringLine(Line9,lcd_buff);
	
}

把所有函数都放在while(1)里轮询。

最终效果如下,频率输出值在700-30000范围内则是正常了

第二种则是需要打开NVIC,但只需要配置一个通道即可,默认上升沿触发即可

不同点在于启动时调用HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1)函数而不是HAL_TIM_IC_Start(&htim2,TIM_CHANNEL_1),然后需要在中断里进行处理

以下为中断函数以及计算函数

注意点在于,浮点计算不能在中断里面进行,就是代码里面注释掉的部分,亲测如果放在了中断里面,如果同时开两个,两个都扭到最大时单片机会死机!!!展示效果是跟上图一致就不再次上传

uint32_t freq_text2 = 0,freq_text3;
uint8_t tim2_up,tim3_up;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
	if(htim == &htim2){
		freq_text2 = __HAL_TIM_GetCounter(&htim2);
		__HAL_TIM_SetCounter(&htim2,0);
		tim2_up = 1;
//		if(freq_text2 != 0) R40_freq = 1e6 / freq_text2;
	}
	if(htim == &htim3){
		freq_text3 = __HAL_TIM_GetCounter(&htim3);
		__HAL_TIM_SetCounter(&htim3,0);
		tim3_up = 1;
//		if(freq_text3 != 0) R39_freq = 1e6 / freq_text3;
	}
}
void Main_Handle(){
	if(tim2_up == 1){
		if(freq_text2 != 0){
			R40_freq = 1e6 / freq_text2;
		} 
		R40_Duty = TIM2->CCR1 / TIM2->ARR * 100;
		tim2_up = 0;
	}
	if(tim3_up == 1){
		if(freq_text3 != 0) R39_freq = 1e6 / freq_text3;
		R40_Duty = TIM3->CCR1 / TIM3->ARR * 100;
		tim3_up = 0;
	}
}

然后是PWM输出介绍

在比赛题目里会要求不同的引脚输出,我这里使用PA7展示。

如图所示将PSC设置为79,ARR设置为999,计算得到的频率为1khz,同时设置Pulse为500,占空比为500/(999 + 1) = 50%

生成工程后根据上面所展示捕获模式,将J10跳线帽拔开用杜邦线短接PA7观察

可以观测到频率与占空比与计算结果一致,说明配置正确。

接下来分享修改输出频率与占空比的函数,初始频率根据题目要求设定,每次传入更新后的值

uint32_t current_freq = 1000; // 初始频率 1kHz,存储当前值
uint32_t current_duty = 10;   // 初始占空比 10%,存储当前值
void PWM_UpDate_Set(uint32_t freq,uint8_t duty){
	if(freq == 0) return;
	
	//计算新的arr
	uint32_t new_arr = (1e6 / freq) - 1;
	
	//计算新的ccr,保持占空比
	uint32_t new_pulse = duty * (new_arr + 1) / 100;
	
	//写入寄存器
	__HAL_TIM_SET_AUTORELOAD(&htim17,new_arr);
	__HAL_TIM_SET_COMPARE(&htim17,TIM_CHANNEL_1,new_pulse);
}

关于该函数的使用可以参考以下,我设置了四个按键,KB1为+1khz,KB2为-1khz,KB3为+10%,KB4为-10%。按键具体代码参考03-按键驱动代码分享

最终完成修改

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐