一、什么是捕获计数器(说人话)?
比如说,我们想知道一个高电平输入到某引脚持续的时间(信号频率其实也是在求信号输入的持续时间),stm32里的定时器肯定是可以实现这一功能的。
我们刚所说的定时器其实在此时不太准确,应该称之为计数器,因为定时功能的实现其实是基于计数功能的使用。定时器是一秒钟计数80M个数,在预分频80之后,也就是一秒钟计数1M次,如果在输入信号的上升沿(就是高电平时)占0.1M个数,那就是100ms的高电平维持。
二、那怎样配置定时器才能实现这样的功能呢?
以捕获上升沿为例:
1、配置定时器
看看信号输入的引脚在哪个定时器的第几个通道,对该定时器的这个通道进行设置,设置好预分频数,确定好一秒的计数值,后分频数尽量大。不设置自动重装载值,向上计数模式。
2、配置该引脚为下拉输入模式
3、定时器输入捕获设置
设置为上升沿输入捕获(当高电平结束就开启中断),上升一次就执行输入捕获中断。
最后开启中断。
4、输入捕获中断函数
中断函数里写读取计数器的数值,然后与1s内的计数值进行比较来计算高电平存在的时间。再开启中断(类似串口接受中断函数每次都需要重新开启中断)
三、以蓝桥杯TIM_FRQ例程为例:
定时器输入捕获初始化:
TIM_HandleTypeDef htim2;
static void MX_TIM2_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 80;//预分频
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;//向上计数
htim2.Init.Period = 0xFFFF;//后分频尽量大
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;//无自动重装载值
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();
}
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);//开启输入捕获中断入口
}
输入捕获中断执行函数:
uint32_t cc1_value_2 = 0; // TIMx_CCR1 µÄÖµ
uint32_t f40 = 0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//ÖжϺ¯Êý
{
cc1_value_2 = __HAL_TIM_GET_COUNTER(&htim2);//获取定时器的计数值
__HAL_TIM_SetCounter(&htim2,0);//计数值归零
f40 = 1000000/cc1_value_2;//计算频率
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);//重新打开输入捕获中断入口
}
主函数:
int main(void)
{
char buf[20];
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
LCD_DisplayStringLine(Line0, (uint8_t *)" ");
LCD_DisplayStringLine(Line1, (uint8_t *)" ");
LCD_DisplayStringLine(Line2, (uint8_t *)" TIM Test ");
LCD_DisplayStringLine(Line3, (uint8_t *)" ");
LCD_DisplayStringLine(Line4, (uint8_t *)" ");
LCD_SetBackColor(White);
LCD_SetTextColor(Blue);
LCD_DisplayStringLine(Line5, (uint8_t *)" ");
LCD_DisplayStringLine(Line6, (uint8_t *)" TIM2 CH1 ");
LCD_DisplayStringLine(Line7, (uint8_t *)" ");
LCD_DisplayStringLine(Line8, (uint8_t *)" ");
LCD_DisplayStringLine(Line9, (uint8_t *)" ");
while (1)
{
sprintf(buf, " FRQ(R40):%dHz ",f40);
LCD_DisplayStringLine(Line8, (uint8_t *)buf);
HAL_Delay(200);
}
}
四、用Cubmx配置:
完美运行!