TIM输入捕获(计算频率和占空比)
首先我们知道PWM的频率=更新频率=72mhz/(PSC+1)/(ARR+1)
占空比:CCR/(ARR+1)
要想改变频率而不改变占空比的前提,只能通过更改PSC的值,也就是预分频器的值
需要用到单独更改PSC的值的函数
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);
这个函数用来单独写预分频值的,第一个参数:定时器几,第而个参数:要写入的预分频值,第三个参数:写入的值是立即生效还是先存入影子寄存器
输入捕获常用的函数
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
上面四个见过的哈他是PWM输出的四个通道每个通道对应一个函数void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
这个是输入捕获的初始化函数,一个函数可以控制四个输入捕获的通道,通过结构体里面的函数来控制void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
这个函数就是快速配置两个输入捕获通道的
给结构体赋初始值
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);
OC就是输出比较的简写,所以这个函数是给输出比较结构体赋初值的void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);
IC就是代表输入捕获的意思,所以这个就是给输入捕获的结构体赋值值的
选择 从模式输入触发源TRGI
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);

选择 主模式的触发源TRGO
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);

选择从模式
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);

启动定时器
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
配置分频器
void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
分别对应通道1,2,3,4的分配器配置
读取CCR的值(输入捕获/输出比较寄存器)
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx);
分别对应1,2,3,4通道的CCR值读取
代码实现(通过TIM3输入捕获计算频率)
1.先初始化对应的GPIO口
2.初始化TIM并配置好PSC和ARR(时基单元配置)
3.初始化输入捕获单元
4.根据公式计算频率(从CCR里面读取值出来)
第一步1.先初始化对应的GPIO口和2.初始化TIM并配置好PSC和ARR(时基单元配置)
//使用TIM3定时器的通道1 也就是PA6引脚
void Ic_Init(void)
{//初始化GPIO//配置时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//配置结构体GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//传入结构体GPIO_Init(GPIOA,&GPIO_InitStruct);//开启APB1时钟 配置时基单元RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//选择时基单元的时钟 注意这里是配置时钟 (我们选择内部时钟)TIM_InternalClockConfig(TIM3);//配置时基单元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//选择分频一般是1分频TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//计数模式TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//接下来三个参数的配置就是时基关键寄存器参数的配置//周期就是ARR自动重装载器的值TIM_TimeBaseInitStruct.TIM_Period=65536-1;//Prescaler是PSC预分频器的值TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//RepetitionCounter是重复计数器的值 高级定时器才有TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);}
第二部.初始化输入捕获单元
//初始化输入捕获单元
void Ic_get(void)
{TIM_ICInitTypeDef 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);TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//配置从模式为restTIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//启动定时器TIM_Cmd(TIM3,ENABLE);}
第三步根据公式计算频率(从CCR里面读取值出来 频率=Fs/CCR)
完整代码如下
/*
用于测量频率
*///使用TIM3定时器的通道1 也就是PA6引脚
void Ic_Init(void)
{//初始化GPIO//配置时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//配置结构体GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//传入结构体GPIO_Init(GPIOA,&GPIO_InitStruct);//开启APB1时钟 配置时基单元RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//选择时基单元的时钟 注意这里是配置时钟 (我们选择内部时钟)TIM_InternalClockConfig(TIM3);//配置时基单元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//选择分频一般是1分频TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//计数模式TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//接下来三个参数的配置就是时基关键寄存器参数的配置//周期就是ARR自动重装载器的值TIM_TimeBaseInitStruct.TIM_Period=65536-1;//Prescaler是PSC预分频器的值TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//RepetitionCounter是重复计数器的值 高级定时器才有TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);}//初始化输入捕获单元
void Ic_get(void)
{TIM_ICInitTypeDef 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);TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//配置从模式为restTIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//启动定时器TIM_Cmd(TIM3,ENABLE);}
//获取CCR的值
uint32_t Get_Psc_Number(void)
{return 1000000/TIM_GetCapture1(TIM3);
}
//调用函数 实现使用TIM3定时器的通道1 也就是PA6引脚进行输入捕获
void use_IC(void)
{Ic_Init();Ic_get();
}
采用PWMI来获取占空比和频率(完整代码)
代码更改如下
//PWMI方式计数占空比和频率
//使用TIM3定时器的通道1 也就是PA6引脚
void Ic2_Init(void)
{//初始化GPIO//配置时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//配置结构体GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//传入结构体GPIO_Init(GPIOA,&GPIO_InitStruct); //开启APB1时钟 配置时基单元RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//选择时基单元的时钟 注意这里是配置时钟 (我们选择内部时钟)TIM_InternalClockConfig(TIM3);//配置时基单元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//选择分频一般是1分频TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//计数模式TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//接下来三个参数的配置就是时基关键寄存器参数的配置//周期就是ARR自动重装载器的值TIM_TimeBaseInitStruct.TIM_Period=65536-1;//Prescaler是PSC预分频器的值TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//RepetitionCounter是重复计数器的值 高级定时器才有TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
}//最低频率是1M/65536=15HZ//初始化输入捕获单元
void Ic2_get(void)
{TIM_ICInitTypeDef 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);TIM_PWMIConfig(TIM3,&TIM_ICInitStruct);//注意这个不一样TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);//配置从模式为restTIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//启动定时器TIM_Cmd(TIM3,ENABLE);}//获取CCR的值 频率
uint32_t Get_Psc2_Number(void)
{return 1000000/TIM_GetCapture1(TIM3);
}//获取占空比 高电平计数存放在CCR2里面,低电平计数存到CCR1里面
uint32_t Get_Duty_Number(void)
{
return TIM_GetCapture2(TIM3)/TIM_GetCapture1(TIM3);
}uint32_t IC_GetDuty(void)
{return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);
}//调用函数 实现使用TIM3定时器的通道1 也就是PA6引脚进行输入捕获
void use_IC2(void)
{Ic2_Init();Ic2_get();
}
最低支持频率=1M/65536,再低就测不到了,除非更改预分频的值使得所支持的频率变低
//误差百分之1
频率上限:1000000/100=10k
//误差千分之1
频率上限:1000000/1000=1k
如果拿标准频率1m赫兹去测量20K的波形那么测试出来的结果大概是在20200赫兹,这就是误差
如果拿标准频率1m赫兹去测量10K的波形那么测试出来的结果大概是在1010赫兹,
如果拿标准频率1m赫兹去测量1K的波形那么测试出来的结果大概是在1001赫兹,
记住这个误差是根据你测量的频率而变化的,避免这种情况最好的办法就是在规定范围内测试频率或者提高基础频率。
最后补充一下
//获取CCR的值 频率
uint32_t Get_Psc2_Number(void)
{return 1000000/TIM_GetCapture1(TIM3);
}
这里频率为什么要拿1000000除CCR的值
我们在输出PWM的时候需要确定三个寄存器的值,ARR,PSC,CCR由这三个参数去确定输出的pwm频率和占空比
输出频率是由72m赫兹/(ARR+1)/(PSC+1) 我们上边是因为把PSC预分频系数填的72所以我们时钟频率是10m赫兹,所以下面算频率的时候才是1m赫兹/CCR的值
如果我们把分频系数改成720,也就是时钟频率是100k,那么计算频率就应该改成100K/CCR的值
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
