stm32-TIM-输入捕获
介绍

PWMI模式即PWM输入模式,是专门测量频率和占空比的
频率测量方法

测频法
规定一段时间T,对这段时间内的上升沿计数,一共N次上升沿,因为一个周期内上升沿只有一次,那么周期就是T/N,频率就是F=N/T。这种方式适合高频信号,一段时间内的上升沿多,误差就小,如图左侧;如果这段时间内频率有变化,得到的就是平均频率
测周法
使用一个已知频率f的信号为标准,从待测信号的一次上升沿开始,下一个上升沿结束,标准信号周期T出现了N次,那么待测信号的周期就是NT,频率就是1/NT,代入标准频率,待测频率F=f/N。这个方式适合低频信号,一个周期内标准信号周期越多,误差越小,如图右侧
这两种方法都有误差,对于测频法,时间T末尾的周期可能不完整,此时只能把这个周期舍弃或者当作一个完整周期,N就会多计或者少计,即有正负一误差;测周法也类似,接近下一个上升沿时标准信号的周期也可能不完整,也有正负一误差
当两个方法测出的N相等,即FT=f/F时,说明误差相等,待测频率F=,这就是中界频率。先粗略测一下待测频率,再与中界频率作比较,高于中界频率就用测频法,低于中界频率就用测周法。
输入捕获通道结构


过程
输入捕获有四个引脚、四个通道,从CH1引脚进入的信号TI1由于噪声干扰会有毛刺,为了避免后续信号采集影响,要先进行滤波,滤波后的信号TI1F进行边沿检测,设置检测上升沿或者下降沿,随后如果输入通道1即为TI1FP1,这是直接输入,输入通道二为TI1FP2,这是间接输入,因为有交叉;CH2引脚的信号也是如此,但都不能进入通道3和通道4,交叉只存在于通道1、2之间,3、4之间。之后还要经过预分频处理选择有效触发
定时器部分,以设置检测上升沿为例,CNT自增,检测到上升沿时,将当前CNT的值存入CCR,然后清零CNT,下一次上升沿时同样操作,由于清零了CNT,所以第二次变化CNT相当于是从0开始计数的;
又配置了时基单元,能算出CNT自增一次的时间t=(PSC+1)/72MHZ,最后读出CCR的值,就能知道这两次变化之间即一个周期的长度,就能知道频率,使用的是测周法。
上升沿时同时也会产生一个更新事件,会挂起标志位,可以申请中断.
这样一个引脚使用一个通道可以测频率。PWMI模式是通过一个引脚使用两个通道捕获来测频率和占空比:将TI1F设置上升沿检测,输入通道1,检测频率;再设置下降沿检测,输入通道2,下降沿之后不清零CNT,上升沿才清零,从上升沿到下降沿也相当于是从0开始计数的,下降沿时将此时的CNT数值存入另一个CCR中,这就是高电平的时间,由于通道1测得了周期时间,将两个CNT数值相比就是占空比了。
主从模式
使用通道1和通道2时,将CNT清零的操作可以由从模式完成,实现了硬件自动化

主模式是定时器将内部事件(如复位,使能,更新等)映射到TRGO引脚,再连接其他外设,这样就能通过定时器去控制其他外设;从模式则是通过外部信号映射到TRGI引脚来控制定时器的启停,复位,计数等等,外部信号触发源可以是其他定时器的ITR引脚,自身的输入捕获通道等等
从模式控制CNT清零,是选择输入捕获通道作为触发源,每次上升沿的时候触发源就会通过从模式控制定时器复位,即CNT清零。
通道3和通道4并不能使用从模式,要清零CNT可以通过每次上升沿申请中断清零CNT。
输入捕获基本流程

这就是使用了一个通道,测频率的结构。配置好时基单元,启动定时器,CNT就会自增,频率就是经过PSC之后的频率;将GPIO口输入的外部信号滤波以及设置边沿检测等后,检测到上升沿,就会将此时CNT的值存入CCR,同时选择TI1FP1作为从模式的触发源,操作选择复位,上升沿时就会自动将CNT清零。先存入,再清零。
PWMI模式基本流程

PWMI模式使用两个通道测频率和占空比,对比上面多了一个通道,将这里设置为下降沿触发,下降沿时存入对应CNT的值,就是高电平的时间,这样就同时测得了频率和占空比
输入捕获测频率代码
使用定时器输入捕获测频率,先开启RCC,初始化输入信号的GPIO口,然后选择内外时钟源,配置时基单元,配置输入捕获单元(包括滤波参数,边沿检测,极性选择,分频器),接着配置从模式:选择触发源为TI1FP1,选择复位操作,最后开启定时器。以上输入捕获初始化完成后,需要读取CCR的值来计算频率。
void ic_init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//初始化GPIO口,使用TIM3_CH1引脚,是复用在PA6的
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//选择时钟源,配置时基单元
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period=65536-1;//ARR设置最大,防止CNT自增的时候溢出了
TIM_TimeBaseInitStructure.TIM_Prescaler=72-1;//PSC,输入捕获设置PSC是设置CNT自增一次的时间,t=PSC+1/72MHZ,这里是一微秒一次
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
//配置输入捕获单元
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//通道1,输入捕获四个通道共用一个函数
TIM_ICInitStructure.TIM_ICFilter=0xf;//滤波参数
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//检测上升沿
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//不分频,需要每次触发上升沿都有效
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接连接,就是CH1引脚直接连通道1,不交叉去间接连通道2;//
TIM_ICInit(TIM3,&TIM_ICInitStructure);
//配置触发源
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//TI1FP1作为触发源控制TIM3
//选择操作
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//让TIM3复位
//开启定时器
TIM_Cmd(TIM3,ENABLE);
}
//读取CCR并计算频率
uint32_t ic_getfreq(void)
{
return 1000000/TIM_GetCapture1(TIM3);//一微秒自增一次,两次上升沿之间时间=CCR*1us,频率就是取倒数
}
PWMI模式测频率占空比代码
步骤和上面时类似的,在选择两个通道的时候可以使用库函数,最后还要计算占空比
void ic_init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//初始化GPIO口,使用TIM3_CH1引脚,是复用在PA6的
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//选择时钟源,配置时基单元
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=65536-1;
TIM_TimeBaseInitStructure.TIM_Prescaler=72-1;//输入捕获设置时基单元是设置CNT自增一次的时间,t=PSC+1/72MHZ,这里是一微秒一次
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
//配置输入捕获单元
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//通道1,输入捕获四个通道共用一个函数
TIM_ICInitStructure.TIM_ICFilter=0xf;//滤波参数
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//不分频,需要每次触发上升沿都有效
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接连接,就是CH1引脚直接连通道1,不交叉去间接连通道2;//
TIM_PWMIConfig(TIM3,&TIM_ICInitStructure);//PWMI模式需要两个通道,使用这个函数,上传一个通道的结构体参数,它会自动配置好另一个通道的参数,取相反的
//配置触发源
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//TI1FP1作为触发源控制TIM3
//配置从模式
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//让TIM3复位
//开启定时器
TIM_Cmd(TIM3,ENABLE);
}
//读取CCR并计算频率
uint32_t ic_getfreq(void)
{
return 1000000/TIM_GetCapture1(TIM3);//一微秒自增一次,两次上升沿总时间=CCR*1us,频率就是取倒数
}
//计算占空比
uint32_t ic_getduty(void)
{
return TIM_GetCapture2(TIM3)*100/(TIM_GetCapture1(TIM3)+1);//下降沿的CNT值在CCR2中
}
更多推荐

所有评论(0)