搜索
bottom↓
回复: 0

使用STM32 TIM的门控模式对外部信号计频

[复制链接]

出30入54汤圆

发表于 2019-1-11 00:02:20 | 显示全部楼层 |阅读模式
算是代码分享吧,网上找了一圈木有。。。网上只搜到了门控来控制脉冲输出的。。。
想想32的定时器如此强大,应该可以实现利用内部的IP资源就完成高频测量的功能,于是开始研究手册、研究代码。

为啥要折腾:
一般对外部高频信号的计频一般是通过定时器A来周期性的中断,然后用定时器B来对外部信号计数,然后在定时器A中断里面记录定时器B的计数值,
然后根据相邻两次的差值和定时器A的周期T就可以计算出外部信号频率了,公式这里都不写了。
但是上面的方法需要软件在中断里面去记录计数值,中断在某些情况下(比如被嵌套)不能保证稳定和精确的响应时间,因此这里会有软件上的误差,
所以这里就用到门控的原理,门控信号开启时是计数的,门控信号关闭时不计数,这个时候有大把的时间让软件来处理计数值(此时计数值不会发生改变),这样就避免了软件误差。

程序基本原理:
利用一个定时器的OC输出作为另外一个定时器的门控,然后后者对外部输入信号进行计数,然后在前者的OC中断中读取门控时间的脉冲个数从而计算外部信号的频率

注意:
该方式只适合中高频测量,测量低频信号需要使用捕获模式,这个网上有很多不赘述了。
本实例在STM32F407上用标准库函数实现,其他系列请酌情参考

阐述一下基本的编程思路:
首先选择用来对外部信号计数的TIM,最好是32位计数器,不容易溢出,所以这里使用TIM2;
然后该定时器需要工作在 “外部时钟模式2+内部触发+门控模式” 下(有点拗口),其中 “内部触发” 需要根据手册上的 “TIMx内部触发连接” 来选择与其匹配的定时器的;
比如手册上说在TIM2的内部触发连接到TIM3时,使用的是ITR2这个连接,所以下面的代码中 TIM_ITRxExternalClockConfig 函数使用的是 ITR2 所对应的参数;
然后就是需要TIM3配合完成一个门控,这个就用比较输出功能来实现,类似PWM输出,唯一不同的是需要通过函数 TIM_SelectOutputTrigger 将 OCxREF信号输出来;
这样就可以利用TIM3的比较输出信号来控制TIM2是否使能计数了
最后在TIM3的OC中断里面把计数值读出来,清空原有的计数,根据门控时间算出频率

下面是代码:
//IO:
/*
* PA15 -> TIM2_ETR
*/

#define FREQ_METER_GATE_TIME                200         //ms, measure time
#define FREQ_METER_GATE_PERIOD              300         //ms, measure period, must greater than FREQ_METER_GATE_TIME
#if FREQ_METER_GATE_PERIOD <= FREQ_METER_GATE_TIME
    #error "FREQ_METER_GATE_PERIOD must greater than FREQ_METER_GATE_TIME"
#endif

static uint32_t fm_count;

int freq_meter_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_OCInitTypeDef TIM_OCInitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;
   
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource15, GPIO_AF_TIM2);

    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStruct.TIM_Period = FREQ_METER_GATE_PERIOD * 2 - 1;
    TIM_TimeBaseInitStruct.TIM_Prescaler = 8400 * 5 - 1;
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);

    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Reset;
    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Disable;
    TIM_OCInitStruct.TIM_Pulse = FREQ_METER_GATE_TIME * 2;
    TIM_OC1Init(TIM3, &TIM_OCInitStruct);
    TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
    TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_OC1Ref);

    //TIM2 for counter
    TIM_TimeBaseInitStruct.TIM_ClockDivision = 0;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStruct.TIM_Period = 0xFFFFFFFF;
    TIM_TimeBaseInitStruct.TIM_Prescaler = 0;
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);

    TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);
    TIM_ITRxExternalClockConfig(TIM2, TIM_TS_ITR2);
    TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Gated);

    NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStruct);

    TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);

    return 0;
}

int freq_meter_run(void)
{
    TIM_SetCounter(TIM2, 0);
    TIM_Cmd(TIM3, ENABLE);
    TIM_Cmd(TIM2, ENABLE);

    return 0;
}

int freq_meter_stop(void)
{
    TIM_Cmd(TIM3, DISABLE);
    TIM_Cmd(TIM2, DISABLE);

    return 0;
}

uint32_t freq_meter_get(void)
{
    return fm_count;
}

void TIM3_IRQHandler(void)
{
    if(TIM_GetFlagStatus(TIM3, TIM_FLAG_CC1) != RESET)
    {
        fm_count = TIM_GetCounter(TIM2) * 1000 / FREQ_METER_GATE_TIME;
        TIM_SetCounter(TIM2, 0);
        TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
    }
}
另外附上该驱动源码文件

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-25 11:15

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表