TIM

TIM1输入捕获模式测量脉冲宽度和频率 和 PWM输入模式的使用

手里有一块传感器芯片,输出的信号是PWM脉冲信号, 输出频率不变,信号通过改变脉宽来输出.

blob.png

需要检测的是位于高电平的脉冲宽度,由于频率不变,使用起来就简便很多.

下面是stm32cubemx针对stm32F407discovery板检测脉宽的配置,

首先是时钟配置,这里我利用先前帖子中的生成的usbhid的那个配置,这样就可以将计算好的脉宽通过hid端口输出到上位机

这里我用到了TIM1端口做检测输入口.可以看到下图中TIM1的时钟为96MHZ

blob.png

配置定时器的输入捕获引脚,这里使用了channel1

blob.png

配置TIM的参数,分频为24 ,这样采样的频率就是96M/24=4M = 0.25us,重载计数值我设定为40000,一次重载时间就为0.25*40000=10ms ,这里我说下为什么设定为10ms, 因为我用的这个传感器输出频率是固定的周期是4096us=4.096ms

这里我让计数器值大于这个值使他不至于每次输出脉冲都需要重载计数值,利于后面对脉宽的计算.

另外,因为我要测量高电平的脉宽,所以需要开启双边缘捕获,选择Both Edge.


二楼继续.



已邀请:

admin

赞同来自:

blob.png

大家看到最下方有个滤波系数我设定的是3,意思是说滤除掉最多在3个内部时钟周期内的抖动.

设定,捕获所用的IO口速度最大.因为我传感器输出的是高低电平的脉冲,驱动能力很强,所以我选择OD模式,并且不使用内部上下拉

blob.png

用到捕获那么就需要开启捕获中断,

blob.png

然后我们在去中断表里调整下中断优先级.这里我捕获的频率高,所以我设定捕获的优先级最大,

blob.png

好了,配置结束,编译生成代码,打开工程.


三楼继续.

admin

赞同来自: HeartBeaTs

开始编写代码:

因为我需要获取上升沿和下降沿的捕获值, 然后将两个值相减得出高电平的脉冲宽度,所以我需要定义三个变量

uint32_t               uwIC1Value1 = 0;
uint32_t               uwIC1Value2 = 0;
uint32_t               uwDiffCapture = 0;

注意,这里定义的是32位,因为获取的捕获值是32位输出,下面还会有介绍.

然后找到main()函数,在这个函数里面添加开启输入捕获的指令

    /* USER CODE BEGIN 2 */
    //开启tim1的channel1输入捕获中断
    HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_1);
    /* USER CODE END 2 */

我们开启了之后,怎么使用呢?当然是利用中断回调.

/* USER CODE BEGIN 4 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
//读取此时IO口的电平,为高,则这次的捕获是上升沿
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_9) == GPIO_PIN_SET)
{
/* Get the 1st Input Capture value */
uwIC1Value1 = HAL_TIM_ReadCapturedValue(&htim1, TIM_CHANNEL_1);

}else{ //下降沿
/* Get the 2st Input Capture value */
uwIC1Value2 = HAL_TIM_ReadCapturedValue(&htim1, TIM_CHANNEL_1);
                                //2大于1,说明在同一个计数周期内,直接减
if(uwIC1Value2 > uwIC1Value1)
uwDiffCapture = uwIC1Value2 - uwIC1Value1; 
else{ //2小于1,不在一个计数周期内,用周期减1的计数,再减去2,得出真是脉宽
uwDiffCapture = (__HAL_TIM_GET_AUTORELOAD(&htim1) -uwIC1Value1 + 1) + uwIC1Value2; 
}
}
      
}

}
/* USER CODE END 4 */

然后我们就可以在usbhid的回调中发送这个 脉冲宽度值到上位机了.


另记:

可能有些人会问: 上面代码为什么要那样减?

我们在定时器tim1的里面设置了重载值,当按照分频之后的步长时间计数到了这个重载值,就会产生重载事件,这个事件会自动的重新把计数值从零开始计数, 这样  就类似一个 环形缓冲区 了,所以,如果第二次捕获在第一次之后,那就说明两个捕获之间产生了一个重载事件,所以........


ok,这次测试记录结束!


本站原创 原则上禁止转帖, 如果非要转载,请一定附上本站的地址!!! 大家都原创不易,谢谢!


附录一张测试时的上位机图片.

blob.png

admin

赞同来自:

忘记记录一个东西了:

上面得到计算好的脉冲宽度值uwDiffCapture 之后,

怎么才能知道真实的脉宽呢?

上面说了,定时器分频之后的频率是0.25

blob.png

所以,吧这个得到的值乘以0.25就可以了.

真实脉冲宽度 = 0.25 * uwDiffCapture

继续研究:

看数据手册上有这么一个PWM输入模式的介绍

blob.png

考虑如果利用这个特性,也许能更好的节省外部脉宽的计算时间(可以通过CCR2一次性的读取到取得的高电平的脉冲宽度)

下面配置pwm输入模式:

blob.png

配置管脚和功能模式:

blob.png

其他的配置和上面介绍的输入捕获模式一致...

然后生成代码:

在main.c文件中,添加打开通道CH2的中断,记得将原来写的那些注释掉不使用.

  /* USER CODE BEGIN 2 */

//开启CH2通道的PWM捕获,
    HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_2);
  /* USER CODE END 2 */

为什么不开启ch1的PWM通道捕获?

因为我只需要取得高电平脉宽,占空比啥的我不需要,如果你需要就同时开启CH1的通道

紧接着,将tim的callback注释掉原来的代码,改为:

/* USER CODE BEGIN 4 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
//如果是CH2产生的中断
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
//获取ch2的捕获值,这个值就是我要的那个脉宽值!!! 一句话搞定了上面写的那么多代码
      uwDiffCapture = HAL_TIM_ReadCapturedValue(&htim1, TIM_CHANNEL_2);
}

}
/* USER CODE END 4 */

测试效果和上面的输入捕获一致!!!

本次结束.

如果计数器溢出了怎么办

Licall郑

赞同来自:

赞!

要回复问题请先登录注册