输入捕获
输入引脚发生跳变时,cnt的值会被记录到ccr中,可以用于测量pwm信号等。配置成pwmi模式还可以同时测量频率和占空比。主从触发模式可以实现硬件全自动测量。
高级定时器和通用定时器才有的功能。
这个功能只能测数字信号,对于a信号需要通过比较器等简历ad转换为数字信号。
测周法速度快,一个周期就测出结果来,但是噪声影响误差可能大。
输入信号经过滤波去除一些毛刺,让信号更稳定;分两路传输,比如CH1分IC1 IC2,这样方便切换,而且方便拓展,比如PWMI要同时计算占空比和频率。
TRC和异或电路用于三相电机。
我们配置psc,设定如上升沿保存一下ccr值,就可以记录两个上升沿之间时间周期了。然后cnt清零。
滤波ICF配置:连续n个相同的事件才会被记录。比如一直是稳定的高电平。如果信号一直抖动就不会记录。如果噪声大可以把这个参数设大一些。
滤波后检测边沿,通过TIFP进行选择。
输出可以设置分频,CC1E使能。TIFP会自动从模式触发cnt清零。
主模式:自身定时器输出信号去触发别的外设。
从模式:接收其他(或自身)外设的信号用于控制自身定时器的运行。
比如本次我们要用到的功能就是从模式的reset,reset cnt。
还有一些其他的用途比如两个定时器级联,第一个定时器预分频后的输出给第二个定时器,这样两者预分频可以计数的周期就更大了。
总结原理:
fc:时钟源频率/psc.
N:最新的ccr值。
fc/N可算出信号频率。
- 注意cnt有上限如65535,因此如果信号频率太低可能溢出,这时我们可以把psc调大一点。
- 1 2定时器只能设置1 2 的从模式,如果想用3 4定时器去触发reset指令,需要用到中断函数,比较消耗资源。
通过上图方式获取频率和占空比。CCR1是整个周期长度,CCR2是高电平周期长度,做比可以求得占空比。
代码:输入捕获模式测频率
我们没有信号发生器,所以利用上节课的PWM波形输出给另一个引脚,另一个引脚IC获得其频率。
因为我们要尝试不同的输入波形,因此psc的值会改变。因此可以写一个改变psc的函数。
初始化函数类似OC。下面的可以同时初始化多个通道。
赋初值。
选触发源。
这个是选择主模式输出的触发源和选择从模式的模式。
读取ccr值。oc状态下ccr只写,可以用setCompare写入。ic状态只读,用这四个函数读。
#include "stm32f10x.h"
void IC_Init(){
//1. 打开输入接收的RCC,GPIO
//2. 时基单元,启动计数器
//3. 设置输入捕获单元
//4. 选用触发源
//5. 设置触发后的reset操作
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, 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;//输入信号频率:1MHz
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//PA6对应定时器3 ch1
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICFilter=0xF;//滤波消除毛刺,越大效果越好,看需求
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);//定时器1的从模式
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
TIM_Cmd(TIM3,ENABLE);
}
uint32_t IC_GetFreq(void){
//fc: 1MHz
return 1000000/(TIM_GetCapture1(TIM3)+1);//CH1的捕获
}
main里设置psc=720,则输入频率为1MHz,1000000,设置ccr值为50。
PWM_SetPrescaler(720-1);//freq: 72M/100/720
TIM_SetCompare1(TIM2,50);//duty: 50/100
OC:PWM设置ccr=50,psc 7200, period 100(因为duty=ccr/(arr+1),所以如果修改输出引脚的分频采用修改arr的方案,那么占空比也会随之改变,不好计算。不如我们固定arr,修改psc。),也就是占空比50/100为一半。因此输出1kHz的波形。
IC:100 0000/1000=1000. 两次相邻的上升沿之间计数1k,用总频率1M/1k得出输入波形。
至于get函数为什么+1,题主也想不太明白,据老师所说可能是到了那里刚好跳变没有记录上上升沿之类的。
代码:检测频率和上升沿
基本不太变,把其中一个IC初始化函数改成同时初始化两个通道的函数。初始化只需要改这一条就行,库函数自动把另一个通道调整为相反的。比如通道1直连上升沿触发,通道2交叉下降沿触发。
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
再写一个获取占空比的函数:
uint32_t IC_GetDuty(void){
return (TIM_GetCapture2(TIM3)+1)*100/(TIM_GetCapture1(TIM3)+1);
}
改setprescaler改频率,改setcompare改duty。
- 输入信号频率1MHz,计数器最大65535,因此最低不溢出的频率是1M/65535≈15Hz。
- 要求误差如千分之一,那么频率为1M/1k=1k.