IC(Input Capture)输入捕获
输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
每个高级定时器和通用定时器都拥有4个输入捕获通道,可配置为PWMI模式,同时测量频率和占空比,可配合主从触发模式,实现硬件全自动测量
频率测量:
测频法适合频率较高的情况,由于测量方法为选取一段时间测量特定边沿取平均值,故波动较低,受噪声影响较小;测周法适合频率较低的情况,测量方法为选取一个周期,测量标准频率(即时钟),故波动较大,受噪声影响较大;当有一个频率,测频法和测周法的N相同,则误差相同,即为中界频率
正负1误差:在测量的时间(测频)或者周期(测周)中,可能出现测量的边沿(测频)或者频率(测周)不完整,只能舍弃或者当作一整个周期看待,若想减小正负1误差,需要尽量多计一些数
这节主要采用的是测周法
输入捕获相关电路
从左侧的四个通道引脚进入电路,首先1~3通道接入一个三输入的异或门,可用于三相无刷电机接入霍尔传感器检测转自位置使用,以驱动换相电路工作;接着进入输入滤波其和边沿检测器,对信号进行滤波和选择高/低电平触发。在下一步的输出上可分为两组:CH1和CH2、CH3和CH4,以前者举例:1、每条通道独立使用,CH1的信号得到TI1FP1输入到通道1的后续电路,或者CH1的信号得到TI1FP2输入到通道2的后续电路;CH2的信号同理 2、PWMI模式,可将一个引脚的输入同时映射到两个捕获单元,第一个捕获通道使用上升沿触发,用于捕获周期,第二个通道使用下降沿触发,用于捕获占空比,同时对一个引脚进行捕获即可同时测量频率和占空比
输入信号进行滤波和极性选择后进入预分频器,分频后的触发信号即可进行触发捕获电路工作,每出现一个触发信号,CNT的值就会向CR寄存器转运一次,同时发生一个捕获事件,在状态寄存器置标志位的同时,也可产生中断
测周法:若配置上升沿触发捕获,那么每出现一个上升沿,CNT转运置CCR一次,由于CNT由内部标准时钟驱动,故CNT的值可用于记录两个上升沿之间的时间间隔,即为周期,取倒数即为频率
主从触发模式
主模式可将定时器内部信号映射至TRGO引脚,以触发其他外设;从模式可接受其他外设或自身外设的信号,用于控制自身定时器的运行;触发源选择,即选择从模式的触发信号源,选择指定信号,得到TRGI,从模式在列表中选择一项操作自动执行,以实现硬件自动化;
在输入捕获中,若想使用从模式进行操作,由于触发源选择中只有TI1FP1、TI2FP2,故只能使用通道1和通道2,通道3和通道4则不能使用,只能开启中断并手动清零
PWMI
PWMI模式使用两个通道同时捕获一个引脚,可同时测量周期和占空比,TI1FP1配置上升沿触发,触发捕获和清零CNT,进行周期的捕获,而TI1FP2配置为下降沿触发,通过交叉通道触发通道2的捕获单元,CCR2捕获不触发CNT清零,是高电平期间的计数值,用CCR2/CCR1,即为占空比
初始化步骤
1、RCC开启始终,打开GPIO和TIM时钟
2、GPIO初始化,将GPIO配置为输入模式
3、配置时基单元,让CNT计数器在内部时钟的驱动下自增运行
4、配置输入捕获单元,包括滤波器、极性、直连通道/交叉通道、分频器等
5、选择从模式触发源,选择为TI1FP1
6、选择触发后执行的操作,执行ReSet操作
7、开启定时器
相关库函数
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
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);
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);
TIM_ICInit:用于结构体配置输入捕获单元,四个通道共用一个函数
TIM_PWMIConfig:用于快速配置PWMI所需的两个输入通道
TIM_ICStructInit:用于给输入捕获结构体赋初始值
TIM_SelectInputTrigger:用于选择输入触发源TRGI
TIM_SelectOutputTrigger:用于选择输出触发源TRGO
TIM_SelectSlaveMode:用于选择从模式
TIM_SetIC1Prescaler:用于单独配置各通道的分频器
TIM_GetCapture1:用于读取各通道的CCR
代码实现
基本输入捕获模式:
//PWM.c文件 用于输出PWM波至IC输入口
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);//使用正点原子精英板,需要对TIM3进行重映射
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &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 = 99;
TIM_TimeBaseInitStructure.TIM_Prescaler = 719;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器,高级定时器才可使用,置0
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure); //用于给结构体中的所有变量赋初始值
//避免使用高级定时器时因为部分变量未赋值而报错
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
//TIM_OCInitStructure.TIM_Pulse = 50;
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的预装载寄存器
TIM_Cmd(TIM3, ENABLE);
}
void PWM_SetCompare2(uint16_t Compare)
{
TIM_SetCompare2(TIM3, Compare);
}
void PWM_SetPrescaler(uint16_t Prescaler)
{
TIM_PrescalerConfig(TIM3, Prescaler, TIM_PSCReloadMode_Update);
}
//IC.c文件
#include "stm32f10x.h"
void IC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//TIM_InternalClockConfig(TIM2); //这句不写也没有影响,默认使用内部时钟
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 = 71;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器,高级定时器才可使用,置0
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //使用TIM2_CH2
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(TIM2, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);
TIM_Cmd(TIM2, ENABLE);
}
uint32_t IC_GetFreq(void)
{
return 1000000 / TIM_GetCapture2(TIM2);
}
//main.c 文件
int main(void)
{
delay_init();
OLED_Init();
PWM_Init();
IC_Init();
PWM_SetPrescaler(719); //Freq = 72M/ (PSC+1) / (ARR+1)
PWM_SetCompare2(50);
OLED_ShowString(1,1,"Freq:00000Hz");
int i;
while(1)
{
OLED_ShowNum(1,6, IC_GetFreq(), 5);
for(i=0; i<100; i++)
{
PWM_SetCompare2(i);
delay_ms(10);
}
for(i=0; i<100; i++)
{
PWM_SetCompare2(100-i);
delay_ms(10);
}
}
}
PWMI模式:
//PWM输出部分同上
//PWMI部分代码:
#include "stm32f10x.h" // Device header
void IC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//TIM_InternalClockConfig(TIM2); //这句不写也没有影响,默认使用内部时钟
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 = 71;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器,高级定时器才可使用,置0
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //使用TIM2_CH2
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(TIM2, &TIM_ICInitStructure);
//TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);
TIM_Cmd(TIM2, ENABLE);
}
uint32_t IC_GetFreq(void)
{
return 1000000 / TIM_GetCapture2(TIM2);
}
uint32_t IC_GetDuty(void)
{
return (TIM_GetCapture1(TIM2)+1)*100 / (TIM_GetCapture2(TIM2)+1);
}
//main函数:
int main(void)
{
delay_init();
OLED_Init();
PWM_Init();
IC_Init();
PWM_SetPrescaler(719); //Freq = 72M/ (PSC+1) / (ARR+1)
PWM_SetCompare2(50);
OLED_ShowString(1,1,"Freq:00000Hz");
OLED_ShowString(2,1,"Duty:00%");
int i;
while(1)
{
OLED_ShowNum(1,6, IC_GetFreq(), 5);
for(i=0; i<100; i++)
{
PWM_SetCompare2(i);
delay_ms(10);
OLED_ShowNum(2,6, IC_GetDuty(), 2);
}
for(i=0; i<100; i++)
{
PWM_SetCompare2(100-i);
delay_ms(10);
OLED_ShowNum(2,6, IC_GetDuty(), 2);
}
}
}