IC(Input Capture)输入捕获 输入捕获模式下,当通道输入引脚出现指定电平跳变时(这个需要配置,是上升沿还是下降沿),当前CNT的值将被锁存到CCR中(就是把CNT的值赋值给CCR),可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数 每个高级定时器和通用定时器都拥有4个输入捕获通道
可配置为PWMI模式,同时测量频率和占空比
可配合主从触发模式,实现硬件全自动测量
上图,越往右频率越低,都是高低电平的数字信号,STM32来说也只能测信号的,如果需要测试正弦波的信号,就应该搭建一个信号预处理电路,也就是信号比较器,把模拟信号转变为数字信号输送给STM32单片机就行了。
侧周法的核心就是测量一个周期的时间,然后取倒数就是等于频率了,两个上升沿之间就是一个周期的长度,在一个周期之内用已知的频率计数,得到计数次数N,fc倒数乘以N就是等于这段时间的长度,取倒数就是频率。
侧频法适合高频信号,在一定时间内,尽量多一些出现上升沿,多一些计数,减小误差;测周法适合低频信号,两个上升沿的时间尽量长,在一定频率下多次进行计数,减小误差。侧频法是一段时间频率的平均值,值比较平滑,但是不容易受外界影响;而测周法是计算两个上升沿之间的值,更新的速度比较快,但是容易受到影响。
无论这两种方法哪一种,都会有正负一的误差,比如测频法在一定时间内最后一个不一定是完整的周期,或者对于测周法,有时候频率fc计数的时间不到,第二个上升沿就出现了,所以会有一个正负一的差别。
所以要尽量N要大,减小误差,联立两条表达式,得到中介频率,大于和中介频率就用侧频法,小于就用测周法。
侧频法在STM32中具体的实现,顶一个定时中断,一秒取一次计数值,计数值在每一次上升沿计数一次,每一秒读取一次的计数值就是频率了。
1.2.3输入通道有一个三输入的异或门,当输入通道有任何一个电平反转的时候,经过异或门就产生一次电平反转,当数据选择器选择选择上面的一个通道,输出引脚就相当于三个输入引脚的亦或值。当数据选择器选择下面这个,就跟异或门没有任何关系。此设计与三相无刷电机息息相关,三相无刷电机有三个霍尔传感器检测转子的位置,可以根据转子的位置进行换相。有了异或门就可以在1.2.3通道街上三相无刷电机的霍尔传感器。 电视气就作为无刷电机的接口定时器,驱动环相电路工作。
进来,进入滤波器以及边沿检测信号器,滤波器避免一些高频毛刺的误触发。
在滤波以及边沿检测这一部分中,具有两套的极性选择以及滤波电路,所以在这一部分有两个输出,一个接着往后输出,一个船到别的地方形成交叉传输,这样做的目的有两个,一个是灵活切换后续电路的输入,一个是把一个引脚的输入同时映射到两个捕获单元(后续电路),经典的PWMI的经典结构。
PWMI模式:两条电路,一条高电平触发,用来捕获周期(也就是侧频法以及测周法),第二条用来低电平触发,用来捕获占空比。两个通道同时对一个引脚进行捕获,同时测量频率以及占空比。如图所示一二通道以及三四通道都是一样的结构。
TRC信号来自于图片的上面部分。
信号经过预分频值就可以按照触发条件进行触发了,每次触发就把CNT的值存入CCR之中,然后产生一个更新事件,更新事件会进行一个中断标志位,可以经过中断标志位产生中断,如果在不活的瞬间需要处理一些事情的话,这里就可以产生中断进入中断处理函数。
CNT的值是用前面部分内部已知时钟的频率驱动的,所以在每次输入信号触发捕获CNT的值存入CCR中就可以知道两个上升沿之剑的时间,这个时间间隔就是周期,倒数就是测周法的频率了。每次捕获的时候把CNT存入CCR之后,都会把CNT清零一次,所以每一次CNT中得到的才能计算两个上升沿的时间间隔。
这个不活一次自动清零的操作可以用主从触发模式来完成,就只用内部硬件结构就可以了,不用占用CPU。
TI1就是CH1的引脚,FDTS就是采样时钟来源,ICF可以控制滤波器的参数,滤波器的工作原理就是以采样频率的进行N此采样,若N此都是统一电平,就输出相应电平,否则保持原本的电平不变,采样频率越低,N值越大,滤波效果就越好。(频率低就是采样的点离得比较远,检测的范围就比较大,更有说服力)
详细的使用在使用手册14.4.7中。
CC1E位置进行输出使能,icps进行分频器的选择,选择几分频。还有一条交叉的输出到后续电路这里没有画出来。
进过分频器之后就可以选择把CNT的值写入CCR中,但是在这之前要进行CNT的清零,如何完成这一操作呢?在上面的部分有两个方式可以被信号船到从模式之中,从模式之中后续有电路进行清零的操作。
主从触发模式就是主模式从模式触发源选择三者的合成,主模式可以把懂事起内部的信号映射到TRGO引脚,用来触发别的外设,从模式就是接受自身外设以及别的外设的信号,控制自身定时器的运行,被别的信号控制,触发源选择,就是选择从模式的控制信号!
如果要进行CNT清零操作,就可以选择TI1FP1信号源,然后再从模式中选择RESTET的操作!
至于各种信号的具体解释可以查看手册的14.4.2
次连接方式只使用了一个通道,功能是用来测试频率!
时基单元部分,72MHz的输入频率经过预分频器得到频率fc,控制CNT的计数。GPIO口输入一个左上角一样的方波信号,经过滤波边沿检测,根据设定上升沿还是下降沿触发CNT的转运功能。同时进行主从触发模式,惊醒清零操作。先转运值,在进行清零操作。
左上角的值就是上升沿转运,然后清零,第二次不活的就是0到CNT的值了。
计算两个上升沿的时间,就是先读取CCR的值,也就是测周法的N,然后又知道fc(也就是时基单元分频频率后的),ARR最大是65535,CNT也是65535,注意触发源的选择,只有TI1FP1以及2,没有3.4,所以对于通道3.4,就只能手动在中断之中进行清零操作了,不能运用硬件自动清零,没办法,手动中断清零只能占用CPU软件资源。
上面通道一样,下面通道就是选择下降沿触发,根据左上角的图片来看,下降沿触发得到CNT1的值,不清零,然后一直到下一个上升沿然后捕获CNT2,那么CNT1/CNT2的值就是占空比啦,就与下面那个空白的通道,也可以用它的两个输出,理论是一样的,要灵活变通。
代码部分:
接线,PWM波从PA0输出传入PA6,根据输入捕获的图,输入引脚应该是定时器的某个通道,要到那张引脚图片上寻找对应的引脚,PA6对应的就是TIM3_CH1。
利用原本输出PWM波的代码改进,输出想要的频率以及占空比的PWM信号。
PWM频率跟psc以及ARR有关,而占空比与ARR和CCR有关,我们的目的是设立两个函数,分别修改一个参数,并且这个参数就是可以表示占空比或者PWM频率的,就能得到相应的波形。
这里选择把ARR的值固定,假设设定为100-1,那么占空比就应该是通过函数传入的CCR的值。一般根据分辨率的要求确定ARR,然后再在函数中计算出相应的公式,把我们直接可调节的参数(比如需要多少占空比,多少频率)输入,得到我们想要的PWM波。
单独写入PSC的函数:void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);
第一参数是哪个定时器,第二个参数是新的预重装值,第三个参数是影子寄存器:选择更新事件再把预重装值更新,就会获得完整波形,把哪个要写入的值收入缓冲器中,等到周期结束,更新事件的时候,在同一更新,不会被中途输出一半然后更新,而改变输出的PWM的周期,开始新的周期,立即更新就是后者。
根据上图进行输出捕获的配置。
1.开启RCC时钟,TIM以及GPIO的时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
2.配置GPIO,把它配成输入模式
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);
3.配置时基单元,让CNT在内部时钟的控制下不断自增
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
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 – 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
4.配置输入捕获通道 void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);输入捕获以及输出比较都有四个通道,但是输入捕获的四个通道共用一个函数,其中有一个参数是选择通道的,方便运用。
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);快速配置两个通道,也就是PWMI模式的配置,如下图:
void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);就是给结构体富裕一个初始值的,不用手动一个个配置,具体是什么可以跳转查看
代码:
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;//预分频器,1分频是不分频,2分频是隔着一个有效,以此类推
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//选择信号是从那个通道输入的,是直连通道还是交叉通道
TIM_ICInit(TIM3, &TIM_ICInitStructure);
5.配置触发源的选择,根据需要选择,这里选择TI1FP1void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
6.配置从模式执行的功能,void TIM_SelectMasterSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_MasterSlaveMode);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
跳转的函数参数说明对应的是下面的四个,而上面的三个是编码器接口使用的。
7.调用TIM_cmd函数开启定时器
当我们需要读取最新一个周期的频率的时候,直接读取CCR的值,然后根据fc/n计算一下就可以了。
***这个函数的作用是配置主模式的输出的触发源:void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);
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);
//这四个函数配置的是输入捕获通道的预分频器。
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);
//这四个是读取四个通道的CCR
在输出比较模式下,CCR是只写的,在输入捕获的模式下,CCR是只读的。
如果要配置PWMI模式:
其余不变,多增加了一条路,应该增加相关配置,方法一:直接利用 TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);函数进行代替方法二后面那一大串东西,该函数的逻辑是配置一个与通道一配置相反的通道,通道一,直连,上升沿,对应通道二,交叉,下降沿。具体变化看跳转函数源码就知道了,该函数在方法一的作用是与方法二再次通道配置部分是一致的。所以该函数只能使用在通道一二!!
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_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_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI ;
测试的最低频率,就是固定的内部时钟72MHz除以设定好的72PSC,就是标准频率,然后除以ARR的最大值65535,就得到了最小频率大概15Hz。如果想要更小的频率,就需要把PSC增大。
最大一般认为是1MHz,但是此时的误差已经非常大了,没什么意义,所以想要知道频率上限在哪里,一般就要看你的误差允许范围在哪里,相对误差等于误差数/ARR,如果相对误差要1/1000,那么就应该是标准频率1MHz*相对误差等于1kHz,就是频率上限。想要提高频率,就要把psc减小。如果频率太高,就选择测频法了!!!
————————————————
版权声明:本文为CSDN博主「笔下觅封侯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_63148816/article/details/130448721