前言
之前拿外部中断做过这个实验,但是精度范围都不是很理想。之后尝试过输入捕获的方法,虽然精度提高了不少,但是输入范围依旧不是很理想(精度做到了误差0.5%,范围做到了1.1MHZ)。而且更要命的是,这两种方法对于cpu的占用率特别的大,在测试的时候,我因为多加了一句串口输出函数,就导致了整体频率检测误差(虽然一句串口对于整个系统来讲不需要耗时多久,但是在检测高频率信号时,可能处理串口的时间就大于了频率检测的时间,这就是为什么这两个方法都不适用于检测高频信号的原因了,当然了真的想追求极致的话是可以采用DMA进行输出的,但是这个也只是治标不治本)。
之后在看了使用 STM32 测量频率和占空比的几种方法这篇博客。我知道了还能用定时器的外部计数器模式来检测信号的上升沿个数,所以这次我打算用外部计数器模式来做一个频率计。
外部计数器的相关知识
我现在对于这种方法的理解就相当于是一种用硬件来实现检测信号上升沿的方法。特点在于不消耗CPU资源,所以只需要在规定时间内调用相关函数,就能完成对信号上升沿次数的读取了。
思路
除了串口之外,我配置了两个定时器 TIM1和TIM2.我用TIM1来作为定时器中断,用TIM2来作为外部计数器。
这里用的是0.0005s的定时器(这个是有讲究的,之后会讲)
重点看一下这里的65535这个数,这个是外部计数器的满载值,就是说如果计数值大于这个,他就会自动清零了。(对于低频信号来讲,这个值是十分的大的,但是对于一个以百万为单位的频率,这个值是十分的小的,因此我们需要缩短中断的时间,这样才能保证我们的计数值不会超出这个满载值)
代码实现
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim-》Instance == htim1.Instance)
{
pwm_value= __HAL_TIM_GetCounter(&htim2);//读取外部计数器的值
__HAL_TIM_SetCounter(&htim2,0);
pwm_sum+=pwm_value;
pwm_value=0;
pwm_flag++;
if(pwm_flag == 2000)
{
printf(“频率为 %d hzrn”,pwm_sum);
pwm_flag = 0;
pwm_sum=0;
}
}
原理还是和之前的一样的,1s信号上升沿的个数就是他的频率值,但是因为满载值的影响,我测的是0.0005s的上升沿个数,然后再叠加到1s,这样就是频率了。
结果
在15MHz的时候,频率也能保证在误差只有0.005%左右,但是因为触发定时器中断较为频繁,所以在测量一些频率较低的信号的时候,这个频率计的精度就没有那么的高了(相比于输入捕获),但是我觉得这也是能接受的。
后续的规划
想要优化的话其实可以用DMA的方式进行输出,但是我觉得之后一定会接触到DMA所以我这里就不再做优化了。
然后再次感谢之前提到的那些博客的代码,真的十分的感谢!!!自己本来连这个东西是什么都没有认识,直到看到了那几篇干货我才有了对这个的认识,万分感谢。
前言
之前拿外部中断做过这个实验,但是精度范围都不是很理想。之后尝试过输入捕获的方法,虽然精度提高了不少,但是输入范围依旧不是很理想(精度做到了误差0.5%,范围做到了1.1MHZ)。而且更要命的是,这两种方法对于cpu的占用率特别的大,在测试的时候,我因为多加了一句串口输出函数,就导致了整体频率检测误差(虽然一句串口对于整个系统来讲不需要耗时多久,但是在检测高频率信号时,可能处理串口的时间就大于了频率检测的时间,这就是为什么这两个方法都不适用于检测高频信号的原因了,当然了真的想追求极致的话是可以采用DMA进行输出的,但是这个也只是治标不治本)。
之后在看了使用 STM32 测量频率和占空比的几种方法这篇博客。我知道了还能用定时器的外部计数器模式来检测信号的上升沿个数,所以这次我打算用外部计数器模式来做一个频率计。
外部计数器的相关知识
我现在对于这种方法的理解就相当于是一种用硬件来实现检测信号上升沿的方法。特点在于不消耗CPU资源,所以只需要在规定时间内调用相关函数,就能完成对信号上升沿次数的读取了。
思路
除了串口之外,我配置了两个定时器 TIM1和TIM2.我用TIM1来作为定时器中断,用TIM2来作为外部计数器。
这里用的是0.0005s的定时器(这个是有讲究的,之后会讲)
重点看一下这里的65535这个数,这个是外部计数器的满载值,就是说如果计数值大于这个,他就会自动清零了。(对于低频信号来讲,这个值是十分的大的,但是对于一个以百万为单位的频率,这个值是十分的小的,因此我们需要缩短中断的时间,这样才能保证我们的计数值不会超出这个满载值)
代码实现
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim-》Instance == htim1.Instance)
{
pwm_value= __HAL_TIM_GetCounter(&htim2);//读取外部计数器的值
__HAL_TIM_SetCounter(&htim2,0);
pwm_sum+=pwm_value;
pwm_value=0;
pwm_flag++;
if(pwm_flag == 2000)
{
printf(“频率为 %d hzrn”,pwm_sum);
pwm_flag = 0;
pwm_sum=0;
}
}
原理还是和之前的一样的,1s信号上升沿的个数就是他的频率值,但是因为满载值的影响,我测的是0.0005s的上升沿个数,然后再叠加到1s,这样就是频率了。
结果
在15MHz的时候,频率也能保证在误差只有0.005%左右,但是因为触发定时器中断较为频繁,所以在测量一些频率较低的信号的时候,这个频率计的精度就没有那么的高了(相比于输入捕获),但是我觉得这也是能接受的。
后续的规划
想要优化的话其实可以用DMA的方式进行输出,但是我觉得之后一定会接触到DMA所以我这里就不再做优化了。
然后再次感谢之前提到的那些博客的代码,真的十分的感谢!!!自己本来连这个东西是什么都没有认识,直到看到了那几篇干货我才有了对这个的认识,万分感谢。
举报