此次利用TIM2实现利用总线时钟来计算输入信号(方波)的频率和其占空比。
原理部分:通过TIM_CH1输入捕获功能,并利用其内部两个捕获/比较寄存器和CNT计数器进行比较来产生相应中断,一个捕获寄存器用来记录一个周期信号的内部脉冲数,另一个寄存器用来记录信号高电平的持续时间内的内部脉冲数,内部脉冲由总线时钟提供。这两个脉冲数的比值即为占空比,频率等于总线时钟/一个周期信号脉冲数,该方法也叫测周法。
首先配置CUBEMX的TIM2模块,利用的是TI1FP1和TI1FP2这两个信号,分别给到两个寄存器中,CNT计数器为记录的脉冲数。输入信号需要输入滤波,如果存在毛刺现象会导致测量的脉冲数量不准确的情况。
文章的设置与链接文章的测周法略微不同(https://www.cnblogs.com/helesheng/p/14107012.html),由于链接文章使用的自动重装载计数器是16bit,会面临计算的脉冲数溢出的问题,所以他会检测数据溢出的次数,并通过相关计算来纠正实际的脉冲值。由于这里选择TIM2的计数器位数为32bit不用担心数据溢出的问题,因为pwm生成频率并不会超过80MHz。通道1选择上升沿触发中断,通道2选择下降沿触发中断,各自会将CNT的值更新到相应的捕获寄存器中。
接下来的操作与之前类似,使能中断和设置中断优先级。
变量定义
uint32 pul_frq;//对应的脉冲频率
uint32 ov_num;//定时器溢出的次数,用于记录之前溢出的次数
uint32 pul_num;//记录到一个信号周期的脉冲数量
uint32 pul_high;//计算高电平的脉冲数量
float d; //占空比计算
初始化函数
HAL_TIM_PWM_Init(&htim3); //PWM生成初始化
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
//HAL_TIM_Base_Start_IT(&htim2);
__HAL_TIM_ENABLE_IT(&htim2, TIM_IT_UPDATE|TIM_IT_CC1|TIM_IT_CC2); //使能两个捕获寄存器中断和更新事件中断
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); //开启TIM2通道1中断
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2); //开启TIM2通道2中断
捕获中断回调函数,更新事件中断包括以下中断,只需要其中一种触发更新事件中断便会产生中断,在触发中断时读取到相应的捕获值:
1.CNT计数器的溢出
2.软件复位操作
3.工作在复位模式下的定时器收到的触发信号(这里即为上升沿或者下降沿信号)
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(__HAL_TIM_GET_IT_SOURCE(&htim2, TIM_IT_UPDATE)!=RESET) //查询更新事件中断是否产生
{
ov_num++ ;//溢出次数加一
__HAL_TIM_CLEAR_IT(&htim2, TIM_IT_UPDATE);
}
if(__HAL_TIM_GET_IT_SOURCE(&htim2, TIM_IT_CC1)!=RESET) //查询输入脉冲上升沿中断是否产生
{
__HAL_TIM_CLEAR_IT(&htim2, TIM_IT_CC1);
pul_num = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);//读取当前捕获发生时的定时器数值(即脉冲数量)
ov_num = 0;
}
if(__HAL_TIM_GET_IT_SOURCE(&htim2, TIM_IT_CC2)!=RESET) //查询输入脉冲下降沿中断是否产生
{
__HAL_TIM_CLEAR_IT(&htim2, TIM_IT_CC2);
pul_high = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2);//读取当前捕获发生时的定时器数值
}
}
while循环中,计算频率和占空比,还是通过按键来改变信号频率。
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
__HAL_TIM_SET_AUTORELOAD(&htim3, duty-1); //设置频率
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, duty/2); //设置占空比
d=100*(float)pul_high/pul_num; //计算占空比
pul_frq = 80000000 /(unsigned int)pul_num; //计算频率
if(KEY_Scan(0)==1)
{
//HAL_TIM_Base_Start_IT(&htim2);//tim2开始中断
duty+=100;
if(duty>2000)
duty=100;
}
}
接下来为debug的结果,可以看到结果满足预期要求。