基于STM32F103RCT6的输入捕获,测量频率和占空比
相关知识
在输入捕获模式下,当通道引脚出现指定电平跳变时,当前的cnt值将会锁存到CCR中,用于测量PWM的波形,频率,占空比,脉冲间隔,电平持续时间。
每个高级计时器和通用计时器拥有4个输入捕获通道;可以配置PWMI模式同时测量频率和占空比;可配合主从模式实现硬件全自动测量。
因此测量策略可以有:
1.固定时间T内,对上升沿计次得到N,则频率 f=N/T ; 通常直接使用系统周期T 测周法 适合高频信号
2.两个上升沿内,以某个标准频率 fc 计次得到N,则频率 f= fc/N; (即数每两次之间能塞下几个已知周期)测频法适合低频信号
3.区分高频低频,需要参考中界频率 fm=(fc/T)^(1/2)
本文以测周法测量频率为例
硬件部分
芯片型号STM32F103RCT6
使用TIM3提供的测量电路,选择TIM3_CH1对应引脚PA6进行信号输入
代码部分
“IC.h”
#ifndef __IC_H
#define __IC_H
void IC_Init(void);
u32 IC_GetFreq(void);
#endif
“IC.c”
#include "stm32f10x.h" // Device header
#include "IC.h"
void IC_Init(void)
{
//开总线APB1控制的TIM3
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//查看引脚定义表,开启所需引脚的GPIO时钟,这里TIM3需要用到PA6引脚触发
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//使用结构体初始化GPIOA
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//内部时钟选择TIM3
TIM_InternalClockConfig(TIM3);
//配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1; //1分频
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; //选择向上计数模式
TIM_TimeBaseInitStruct.TIM_Period=65536-1; //ARR-1,给最大值65536-1,防止计数溢出
TIM_TimeBaseInitStruct.TIM_Prescaler=72-1; //PSC-1,预分频器72-1
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct); //时基单元初始化
//初始化输入捕获单元
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICStructInit(&TIM_ICInitStruct); //直接调用库函数粗略地初始化,后面再细改
//TIM_PWMIConfig(TIM1,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel=TIM_Channel_1; //选择通道 1 进行捕获
TIM_ICInitStruct.TIM_ICFilter=0xF; //滤波器,设定远高于信号频率的值,滤除高频噪声,使得信号更加平滑
TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising; //上升沿触发
TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1; //1分频,就是保持原有频率
TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI; //选择触发信号输入引脚,直连,交叉,或者TRC引脚
TIM_ICInit(TIM3,&TIM_ICInitStruct); //用上面修改过的结构体初始化TIM3
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1); //TIM3的触发源选择 滤波时钟输入通道 1
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset); //选择从模式为Reset
TIM_Cmd(TIM3,ENABLE); //设置好了之后,启动定时器TIM3
}
u32 IC_GetFreq(void)
{
return 10000/TIM_GetCapture1(TIM3); // 测周法得到f=fc/N 其中fc为系统时钟,N为CCR值
}
“main.c”
#include "stm32f10x.h" // Device header
int main()
{
while(1){
}
}
改进
使用PWMI模式测量频率和占空比
对代码"IC.h"进行更改
#ifndef __IC_H
#define __IC_H
void IC_Init(void);
u32 IC_GetFreq(void);
u32 IC_GetDuty(void);
#endif
对代码"IC.c"进行更改
#include "stm32f10x.h" // Device header
#include "IC.h"
void IC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=65536-1;
TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICStructInit(&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter=0xF;
TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3,&TIM_ICInitStruct);
//直接调用库函数开启PWMI模式
TIM_PWMIConfig(TIM3,&TIM_ICInitStruct);
/*效果等价于
TIM_ICInitStruct.TIM_Channel=TIM_Channel_2; //改成通道2
TIM_ICInitStruct.TIM_ICFilter=0xF;
TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Falling; //改成下降沿触发
TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_IndirectTI; //改成交叉输入
TIM_ICInit(TIM3,&TIM_ICInitStruct);
*/
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
TIM_Cmd(TIM3,ENABLE);
}
u32 IC_GetFreq(void)
{
return 10000/TIM_GetCapture1(TIM3);
}
u32 IC_GetDuty(void)
{ //高电平计数CCR2+1.整个周期计数CCR1+1,二者比值得到占空比,乘100得到百分比的数字部分
return 100*(TIM_GetCapture2(TIM3)+1)/(TIM_GetCapture1(TIM3)+1) ;//
}