7、输入捕获模式测频率、PWMI模式测频率占空比
一、知识点
TIM输入捕获模式:
1、输入捕获模式测频率占空比
信号源:产生一个频率和占空比可调的波形
无信号发生器的情况:先用PWM模块,在PA0端口输出一个频率和占空比可调的波形,把PA0和PA6连在一起,PA6为输入波形,这样就是测量自己PWM模块产生波形的频率
在显示屏上显示PA6的频率
2、PWMI模式测频率占空比
输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中(即把当前CNT的值读出来,写入到CCR中)
2、通用定时器结构
(1)输出比较的执行逻辑
根据CNT和CCR的关系,从通道引脚输出高低电平
(2)四个输入捕获和输出比较通道
共用4个CCR寄存器,其CH1到CH4也是共用的,故对于同一个定时器,输入捕获和输出比较,只能使用一个,不能同时使用
(3)输入捕获的执行流程和输出比较的区别
输出比较:引脚是输出端口,根据CNT和CCR的大小关系来执行输出动作
输入捕获:引脚是输入端口,接收到输入信号,执行CNT锁存到CCR的动作
(4)输入捕获的作用
测量PWM波形的频率、占空比、脉冲间隔(和频率差不多意思)、电平持续时间(和占空比差不多意思)等参数
(5)输入捕获通道
每个高级定时器和通用定时器都拥有4个输入捕获通道,且高级和通用定时器都没有什么区别,基本定时器没有输入捕获的功能
(6)PWMI模式:同时测量频率和占空比
PWMI模式是PWM的输入模式,专门为测量PWM频率和占空比设计的。
(7)主从触发模式:实现硬件全自动测量
注意:(6)、(7)结合起来,测量频率占空比就是硬件全自动执行,软件不需要进行任何干预,也不需要进中断,需要测量时直接读取CCR寄存器的值即可,方便+减轻软件的压力
3、测频法和测周法测量频率
(1)测频法和测周法的原理
测频率法:定义一个T,如1s,在1s的时间内,有多少个周期,就是多少HZ
测周法:周期的倒数就是频率,测出一个周期的时间,再取倒数,就是频率(测量时间的方法:定时器计次,使用一个已知频率fc的计次时钟,来驱动计数器,从一个上升沿开始计,计数器从0开始,一直计到下一个上升沿,停止,计一个数的时间是1/fc,计N个数,时间就是N/fc,N/fc就是周期,再取一个倒数,就得到公式fx=fc/N)
中界频率:测频率法的N=测周法的N,两者误差相等。
(2)测频法和测周法的选择
此时,当待测信号小于中界频率时,用测周法,当大于中界频率时,用测频法
(3)测频法和测周法的比较
测频法适合高频信号(因为若N很小,误差会很大),若闸门时间选为1s,那么每隔1s才能出结果,结果比较慢
测周法适合测量低频信号(周期比较长,计次就会比较多,有助于减少误差),测一个周期就能出现结果,而一般待测信号频率都比较大,故结果更新较快
(4)测频法和测周法的实现
a、测频法的思路:之前的对射式红外传感器计次计次,每来一个上升沿计次1,再用有一个定时器,每隔1s中断,再中断中,每隔1s取一次计次值,同时清0计次,为下一次做准备,这样每次读取的计次值就是频率
定时器外部时钟也同理,每隔1s取一次计次,就能实现
b、测周法:测量两个上升沿的时间(见本次代码)
4、主从触发模式
主从触发模式就是主模式、从模式、触发源选择三个的简称
主模式:可以将定时器内部的信号,映射到TRGO引脚,用于触发别的外设
从模式:接受其他外设或者自身外设的一些信号,用于控制自身定时器的运行,也就是被别的信号控制
触发源选择:选择从模式的触发信号源,可以认为是从模式的一部分,选择指定的一个信号,得到TRGI,TRGI可以取触发从模式,从模式可以在上述右图列表中,选择一项操作来自动执行
若想让TI1FP1信号自动触发CNT清零,触发源一个选择TI1FP1,从模式选择执行Reset的操作,这样TI1FP1信号就可以自动触发从模式,从模式自动清零CNT,实现硬件全自动测量
5、结构
(1)捕获输出基本结构
- 只使用一个通道
- 时基单元:CNT(测周法用来计数计时)会在预分频之后的时钟驱动下,不断自增 。经过预分频后时钟频率会驱动CNT的标准频率fc,标准频率=72M/预分频系数
- 输入捕获通道1的GPIO口输入方波信号,经过滤波器和边沿检测,选择TI1FP1为上升沿触发,选择直连的通道,分频器选择不分频,当TI1FP1出现上升沿后,,CNT的当前计数值转运到CCR1中,同时触发源选择,选中TI1FP1为触发信号,从模式选择复位操作,这样TI1FP1的上升沿,也会通过触发源选择——从模式RESRT这条路去触发CNT清零
- 顺序:先转运CNT的值到CCR中,再触发从模式给CNT清零,或者是非阻塞的同时转移,CNT的值转移到CCR,同时0转移到CNT中去(先捕获,在清零)
- CCR1值为N,fc/N就可以得到频率
- 频率过低,CNT(最大65535)可能会溢出
(2)PWMI基本结构
占空比:CCR2/CCR1
二、输入捕获模式测频率
1、原理图
2、改变PWM频率
• PWM 频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
• PWM 占空比: Duty = CCR / (ARR + 1)
• PWM 分辨率: Reso = 1 / (ARR + 1)
CK_PSC为72M,PSC为预分频器,ARR为自动重装器,CCR为捕获/比较器
改变PSC和ARR都可以调节频率,但改变ARR调节频率会影响到占空比,所以选择PSC调节频率
1 2 3
| TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; TIM_OCInitStructure.TIM_Pulse = 0;
|
这代码中,因为ARR=100,所以CCR的值为占空比(该电平在周期的比例)
3、单独修改PSC的函数
1 2 3 4 5 6 7
| void PWM_SetPrescaler(uint16_t Prescaler) { TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate); }
|
4、设置1000HZ,占空比为50%
1 2
| PWM_SetPrescaler(720 - 1); PWM_SetCompare1(50);
|
5、工作步骤
第一步:RCC开启时钟,打开GPIO和TMI的时钟
第二步:GPIO初始化,配置成输入模式,一般选择上拉输入或者浮空输入模式
第三步:配置时基单元,让CNT计数器在内部时钟的驱动下自增运行
第四步:配置输入捕获单元,包括滤波器、级联、直联通道还是交叉通道、分频器等参数,用结构体统一进行配置
第五步:选择重模式的触发源,触发源选择为TI1FP1(此处调用一个库函数,给个参数即可)
第六步:选择触发之后执行的操作:执行RESET操作(调用库函数)
最后,调用TIM_CMD函数开启定时器
想要获取一个周期的频率时,直接读取CCR计算器,然后按照fc除N计算即可(fc,标准频率=72M/预分频系数)
6、CCR
输入捕获模式下:CCR是只读的,要用GetCapture读出
输出比较模式下:CCR是只写的,要用SetCompare1
7、 代码
(1)IC.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| #include "stm32f10x.h" void IC_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 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; TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); TIM_ICInitTypeDef TIM_ICInitStructure; TIM_ICInitStructure.TIM_Channel = TIM_Channel_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; TIM_ICInit(TIM3, &TIM_ICInitStructure); TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); TIM_Cmd(TIM3, ENABLE); } uint32_t IC_GetFreq(void) { return 1000000 / (TIM_GetCapture1(TIM3) + 1); }
|
(2)mian.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include "stm32f10x.h" #include "Delay.h" #include "OLED.h" #include "PWM.h" #include "IC.h" int main(void) { OLED_Init(); PWM_Init(); IC_Init(); OLED_ShowString(1, 1, "Freq:00000Hz"); PWM_SetPrescaler(720 - 1); PWM_SetCompare1(50); while (1) { OLED_ShowNum(1, 6, IC_GetFreq(), 5); } }
|
三、PWMI模式频率占空比
1、IC.c中不一样的地方
1 2 3 4 5 6 7 8
|
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure); uint32_t IC_GetDuty(void) { return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1); }
|
2、IC.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include "stm32f10x.h" void IC_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 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; TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); TIM_ICInitTypeDef TIM_ICInitStructure; TIM_ICInitStructure.TIM_Channel = TIM_Channel_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; TIM_PWMIConfig(TIM3, &TIM_ICInitStructure); TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); TIM_Cmd(TIM3, ENABLE); } uint32_t IC_GetFreq(void) { return 1000000 / (TIM_GetCapture1(TIM3) + 1); } uint32_t IC_GetDuty(void) { return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1); }
|
3、main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include "stm32f10x.h" #include "Delay.h" #include "OLED.h" #include "PWM.h" #include "IC.h" int main(void) { OLED_Init(); PWM_Init(); IC_Init(); OLED_ShowString(1, 1, "Freq:00000Hz"); OLED_ShowString(2, 1, "Duty:00%"); PWM_SetPrescaler(720 - 1); PWM_SetCompare1(50); while (1) { OLED_ShowNum(1, 6, IC_GetFreq(), 5); OLED_ShowNum(2, 6, IC_GetDuty(), 2); } }
|
四、知识点
测频率的性能
- 测频率的范围:目前给标准频率1MHZ时,计数器最大只能到65535,所以测量的最低频率是1M/65535,大概是15HZ,若频率再低,则溢出,此时可以增大预分屏,就可以使得标准频率更低
- 测量的最高频率没有上限,但是频率越大,误差越大。如果非要找一个频率上限,就是1MHZ,因为超过标准频率,时误差非常大
- 如果要求误差等于1/1,000时,频率为上限,则这个上限就是1兆除1,000=1,000HZ
- 如果要求误差可以到1%,那频率上限就是1MHZ除100=10KHZ
- 如果想提高频率的上限,就要把PSC给降低一些,提高标准频率,上限制就会提高
- 若要更高的频率,则用测频法