|
算是代码分享吧,网上找了一圈木有。。。网上只搜到了门控来控制脉冲输出的。。。
想想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周年了!感谢大家的支持与爱护!!
一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
|