文章目录
- IC(Input Capture)输入捕获
- PWM频率
- 知识点补充
- 1. 滤波器的工作原理:
- 2. 边沿检测器:
- 自动化清零CNT
- 输入捕获的基本结构
- PWMI基本结构
- 滤波器和分频器的区别
- 误差分析
- pwm.c
- main.c
- IC.c
- PWM模式测频率和占空比
IC(Input Capture)输入捕获
输入捕获模式下,当通道输入引脚出现指定电平跳变(上升沿或者下降沿)时,(控制)当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
每个高级定时器和通用定时器都拥有4个输入捕获通道
可配置为PWMI(input)模式,同时测量频率和占空比
可配合主从触发模式,实现硬件全自动测量
(输入捕获,接收到输入信号,执行CNT锁存到CCR的动作)
(输出比较,是根据CNT和CCR的比较关系执行输出动作)
测频法:在闸门时间T内,对上升沿计次,得到N,则频率 (适合测量高频信号)
f
x
=
N
/
T
f_x=N / T
fx=N/T N越大,误差和越小 ,因为容易计数遗漏 (记录的次数多了,一次记错也影响不大)
测周法:两个上升沿内,以标准频率fc计次,得到N ,则频率 f = 1/t (通过计时器记录一个上升加一个下降沿的时间)(适合测量低频信号)
f
x
=
f
c
/
N
f_x=f_c / N
fx=fc/N N越大,误差和越小 多计算一些数
那多高算高频率,多低算低频率。就涉及到中界频率:
中界频率:测频法与测周法误差相等的频率点
f
m
=
√
f
c
/
T
f_m=√f_c / T
fm=√fc/T
测量的是数字信号。
- 因此测频法适用于频率大于中界频率,测周法适合小于中界频率。
- 红外射频,上升沿计次+1,结合定时器,在中断里每隔1S取一下计次值,同时清零,为下一次做准备。
- CNT计数器是由内部的标准时钟驱动的,所以CNT的数值,可以用来计算两个上升沿之间的时间间隔,这就是一个周期,取个倒数 就是测周法测量的频率
- 每来一个上升沿,取CNT的值自动存到CCR里面,CCR捕获到的值就是就是计数值N,CNT的驱动时钟就是fc ,fc/N就得到了待测信号的频率。
- 计数器计时频率:提高标准频率fc,频率就会越大
fc = CK_CNT =CK_PSC/(PSC+1) CK_PSC = 72MHZ
捕获后清零的操作,用的是主从触发模式。
PWM频率
Freq = CK_PSC / (PSC + 1) / (ARR + 1)
知识点补充
1. 滤波器的工作原理:
以采样频率对输入信号进行采样,当连续N个值都为高电平,输出才为高电平,反之亦然,如果信号出现高频抖动,导致连续 采样N个值不全都一样。那输出不会变化。达到滤波的效果。
特点:
采样频率越低,采样个数N越大,滤波器效果就越好。
如果噪声比较大,就将采样频率从的值调大一点,就可以过滤噪声
2. 边沿检测器:
用来捕获上升沿或者下降沿。
- CC1P:用来选择极性
最终到达Tl1FP1触发信号,选择数据选择器。
通过数据选择器进入捕获电路
到达Tl1FP2触发信号,连接到通道2的后续电路,
同样通道2还有Tl2FP1,连接通道1的后续电路
还有TI2FP2,连接通道2的后续电路。共有4种连接方式 - CC1S:配置数据选择器
- ICPS:配置分频器系数
- CC1E控制输出使能或失能,如果使能输出,输出的产生指定边沿信号,经过层层电路,到达捕获电路,就可以让CNT的值转运到CCR里面。
每捕获一次CNT,都要将CNT清零,方便下一次捕获,硬件电路自动完成清零CNT,也就是图中Tl1FP1连接的从模式来处理(自动化)。
自动化清零CNT
输入捕获的基本结构
只有一个通道只能用来测频率。
PWMI基本结构
fx=fc/N N=CNT
因为CNT在清零后一直++
CCR1是一整个周期的计数值
CCR2是高电平期间的计数值
占空比:CCR2/CCR1
这里可以看出来 N = CCR1
uint32_t IC_GetFreq(void)
{ // fx =fc/n fc = CK_PSC / (PSC + 1) -> 72000000Hz/72 = 1MHZ
return 1000000/(TIM_GetCapture1(TIM3)+1); // 占空比= fc/N N就是读取CCR的值
}
uint32_t IC_GetDuty(void) //获得PWM的占空比
{
return TIM_GetCapture2(TIM3)/TIM_GetCapture1(TIM3); //CRR2/CRR1
}
滤波器和分频器的区别
滤波器不会改变信号的原有频率,只会滤除高频噪音。
分频器是对信号进行分频。改变了原有的频率
误差分析
除了由±1误差,还有晶振误差
通过直接在PWM.c文件中修改 PSC和ARR不方便,因此创建一个函数
- 据PWM频率:
Freq = CK_PSC / (PSC + 1) / (ARR + 1) :
72MHZ/(PSC+1)/(ARR+1) = 1000 PSC+1 =72000000/1000000=720HZ - PWM占空比:
Duty = CCR / (ARR + 1)
因此修改ARR会同时影响 频率和占空比,所以修改PSC调节频率最合适
固定ARR = 100-1;
CCR的值 直接就是占空比
#include “stm32f10x.h” // Device header
//1.配置GPIO
//2.选择内部时钟
//3.配置时基单元
//4.配置输入捕获单元
//5.选择从模式触发源
//6.选择触发之后执行的操作
//7.开启定时器
pwm.c
main.c
IC.c
void IC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//给TIM2使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//给GPIO使能
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //上拉输入,
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; //根据引脚表的出CH_1所在引脚时PA0
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
TIM_InternalClockConfig(TIM3); //选择内部时钟
//时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //每一个时钟后面都会加一个滤波器,作用就是为是信号更加稳定,使用的采样的方式,在输入的脉冲中采样,按照n/f,因此采样系数越大,延迟越大
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = 65536-1; //ARR =100
TIM_TimeBaseInitStruct.TIM_Prescaler = 72-1; // psc = 720//预分频器,72MHZ进行7200分频 ,72000/7200 = 10KHZ 1ms = 1KHZ 10KHZ下记10000个数 10000/10 =1000kHZ = 1S
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
//初始化输入捕获单元
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1 ;
TIM_ICInitStruct.TIM_ICFilter = 0xF; //数值越大,采样效果越好(以采样频率对输入信号进行采样,当连续N个值都为高电平,输出才为高电平,反之亦然,如果信号出现高频抖动,导致连续 采样N个值不全都一样。那输出不会变化。达到滤波的效果。)
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);
//选择从模式 自动清理CNT
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
//启动时基单元
TIM_Cmd(TIM3,ENABLE);
}
uint32_t IC_GetFreq(void)
{ // fx =fc/n fc = CK_PSC / (PSC + 1) -> 72000000Hz/72 = 1MHZ
return 1000000/(TIM_GetCapture1(TIM3)+1); // freq= fc/N N就是读取CCR的值
}
PWM模式测频率和占空比
uint32_t IC_GetFreq(void)
{ // fx =fc/n fc = CK_PSC / (PSC + 1) -> 72000000Hz/72 = 1MHZ
return 1000000/(TIM_GetCapture1(TIM3)+1); // 占空比= fc/N N就是读取CCR的值
}
uint32_t IC_GetDuty(void)
{
return (TIM_GetCapture2(TIM3)+1)*100/(TIM_GetCapture1(TIM3)+1); //*100可以变为整数
}
//配置成两个通道同时捕获一个引脚
//初始化输入捕获单元
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1 ;
TIM_ICInitStruct.TIM_ICFilter = 0xF; //数值越大,采样效果越好(以采样频率对输入信号进行采样,当连续N个值都为高电平,输出才为高电平,反之亦然,如果信号出现高频抖动,导致连续 采样N个值不全都一样。那输出不会变化。达到滤波的效果。)
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);
//如何配置成两个通道同时捕获一个引脚,采用下面的函数
//只支持通道1和通道2
TIM_PWMIConfig(TIM3,&TIM_ICInitStruct); //这个函数会自动将配置呈相反的,上升沿变下降沿,直连变交叉
//配置触发源
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
//选择从模式 自动清理CNT
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset
);
定时器输入捕获库函数
//也有四个通道,初始化输入捕获单元
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
//给初始化PWMI
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
//给结构体初始化值
void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);
//选择输入触发源 (从模式)
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
//选择输出触发源
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);
//选择从模式
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);
//分别单独配置通道1,2,3,4的分频器
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);
void TIM_SetClockDivision(TIM_TypeDef* TIMx, uint16_t TIM_CKD);
//分别读取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);