输入捕获:

  • 输入捕获简介:
  • IC(Input Capture)输入捕获:
  • 输入捕获和输出比较的区别:
  • 频率测量:
  • 测频法:
  • 测周法:
  • 中界频率:
  • 主从触发模式:
  • 基本结构:
  • 输入捕获基本结构:
  • PWMI基本结构:
  • 代码实现:
  • 信号源:
  • pwm初始化:
  • pwm占空比:
  • pwm频率:
  • pwm输出:
  • 输入捕获配置:
  • 输入捕获配置的基本步骤:
  • 第一步:
  • 第二步:
  • 第三步:
  • 第四步:
  • 初始化捕获单元:
  • 初始化结构体:
  • 初始化函数:
  • 第五步:
  • 第六步:
  • 第七步:
  • • 读取:
  • • 读取频率:
  • • 读取占空比:
  • 代码示例:
  • 测频率的性能:
  • 输入捕获简介:

    IC(Input Capture)输入捕获:

    输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到 CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数

    输入捕获和输出比较的区别:

    输入捕获:
    • 接收到输入信号执行CNT锁存到CCR的动作
    输出比较:
    • 根据CNT和CCR的大小关系来执行输出动作

    • 每个高级定时器和通用定时器都拥有4个输入捕获通道
    • 可配置为PWMI模式,同时测量频率和占空比
    • 可配合主从触发模式,实现硬件全自动测量

    频率测量:

    测频法:

    •测频法适合测量高频信号,在闸门时间内,最好要多出现一些上升沿,计次数量多一些,有助减少误差。
    •测频法结果更新较慢,数值相对稳定
    实现思路:
    • 之前的对射式红外传感器计次计次,每来一个上升沿计次1,再用有一个定时器,每隔1s中断,再中断中,每隔1s取一次计次值,同时清0计次,为下一次做准备,这样每次读取的计次值就是频率
    • 定时器外部时钟也同理,每隔1s取一次计次,就能实现
    正负一误差:
    在闸门时间内,并不是每个周期信号都是完整的,比如在最后时间里,可能有一个周期刚出现一半,闸门时间就到了,但这只有半个周期,只能把它舍弃或当做一整个周期来看,这样就会多计一个或少计一个

    测周法:

    • 测周法适合测量低频信号,低频信号,周期比较长,计次比较多,有助减少误差
    • 测周法结果更新的快,数值跳变也很快
    实现思路:
    测量两个上升沿的时间
    正负一误差:
    标准频率fc频率计次,在最后时刻,有可能一个数记到一半,计时就结束了,那这半个数也只能舍弃或按一整个数算了

    中界频率:

    • 正负一误差是上面两种方式都固有误差,要想减少正负一误差的影响,就只能尽量多计一些数(N),当计次N比较大时。正负一误差对N的影响就会很小。所以总结就是N越大,正负一误差对我们的影响越少,那当有一个频率,测频法和测周法计次的N相同,就说明误差相同,这就是中界频率。
    • 当待测频率大于中界频率时,适用测频法,当待测频率小于中界频率时,适用测周法。

    主从触发模式:

    基本结构:

    输入捕获基本结构:

    斯柯达
    • 只使用一个通道,只能测频率。
    • 时基单元:把时机单元配置好,启动定时器,CNT就会在标准时钟频率的驱动下不断自增。(标准时钟频率=72M/预分频系数)
    • 输入捕获通道:输入捕获通道1的GPIO口,输入一个方波信号,经过滤波器和边沿检测,选择TIFP1为上升沿触发,之后选择直连的通道,分频器选择不分频,从模式触发源选择,选中TI1FP1为触发信号,从模式选择复位操作,这样TI1FP1的上升沿,就会触发CNT的清零操作
    • 执行: TI1FP1出现上升沿后,将CNT的当前计数值转运到CCR1中,再触发从模式给CNT清零,或者是非阻塞的同时转移,然后进行下一轮的捕获。
    • 只要读取CCR1中的值,再fc/N就可以得到频率
    • 频率过低,CNT(最大65535)可能会溢出
    • 从模式只能在输入捕获通道1和输入捕获通道2使用,对于通道3和通道4,只能在中断中清零。

    PWMI基本结构:


    • 使用两个通道,能测频率和占空比。
    • 时基单元:把时机单元配置好,启动定时器,CNT就会在标准时钟频率的驱动下不断自增。(标准时钟频率=72M/预分频系数)
    • 输入捕获通道1:输入捕获通道1的GPIO口,输入一个方波信号,经过滤波器和边沿检测,选择TIFP1为上升沿触发,之后选择直连的通道,分频器选择不分频,从模式触发源选择,选中TI1FP1为触发信号,从模式选择复位操作,这样TI1FP1的上升沿,就会触发CNT的清零操作
    • 输入捕获通道2:选择TIFP2为下升沿触发,通过交叉通道,触发通道2的捕获单元
    • 执行: 在上升沿,将CNT的当前计数值转运到CCR1中,再触发从模式给CNT清零,或者是非阻塞的同时转移,在下降沿,将CNT的当前计数值转运到CCR2中,然后进行下一轮的捕获。
    • 只要读取CCR1中的值,再fc/N就可以得到频率
    •读取CCR1和CCR2中的值,再CCR2/CCR1就可以得到占空比

    代码实现:

    信号源:

    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调节频率

    void PWM_Init()
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	
    	GPIO_InitTypeDef GPIO_InitStruct;
    	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
    	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStruct);
    	
    	
    	TIM_InternalClockConfig(TIM2);
    	
    	TIM_TimeBaseInitTypeDef PWM_Init;
    	PWM_Init.TIM_ClockDivision=TIM_CKD_DIV1;
    	PWM_Init.TIM_CounterMode=TIM_CounterMode_Up;
    	PWM_Init.TIM_Period=100 - 1;
    	PWM_Init.TIM_Prescaler=720-1;
    	PWM_Init.TIM_RepetitionCounter=0;
    	
    	TIM_TimeBaseInit(TIM2,&PWM_Init);
    	
    	TIM_OCInitTypeDef TIM_OCInitStruct;
    	TIM_OCStructInit(&TIM_OCInitStruct);
    	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;
    	TIM_OCInitStruct.TIM_OCNPolarity=TIM_OCPolarity_High;
    	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
    	TIM_OCInitStruct.TIM_Pulse=0;
    	TIM_OC1Init(TIM2,&TIM_OCInitStruct);
    	
    	TIM_Cmd(TIM2,ENABLE);
    }
    

    pwm占空比:

    void PWM_SetComparel_1(uint16_t CCR)
    {
    
    	TIM_SetCompare1(TIM2,a);
    
    }
    

    pwm频率:

    void PWM_SetPrescaler(uint16_t PSC)
    {
    	TIM_PrescalerConfig(TIM2, PSC, TIM_PSCReloadMode_Immediate);		//设置PSC的值
    }
    

    pwm输出:

    PWM_Init();
    PWM_SetPrescaler(720-1);//Freq = 72M / (PSC + 1) / 100  //1000hz
    PWM_SetComparel_1(50);//Duty = CCR / 100        //占空比为50%
    

    输入捕获配置:

    输入捕获配置的基本步骤:

    第一步:RCC开启时钟,打开GPIO和TMI的时钟
    第二步:GPIO初始化,配置成输入模式,一般选择上拉输入或者浮空输入模式
    第三步:配置时基单元,让CNT计数器在内部时钟的驱动下自增运行
    第四步:配置输入捕获单元,包括滤波器、级联、直联通道还是交叉通道、分频器等参数
    第五步:选择从模式的触发源,触发源选择为TI1FP1
    第六步:选择触发之后执行RESET操作
    第七步:开启定时器
    读取

    第一步:
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//开启TIM3的RCC时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA的RCC时钟
    
    第二步:
    PIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStruct);//配置PA16为上拉输入模式
    

    输入捕获引脚详见:这里

    第三步:
    	TIM_InternalClockConfig(TIM3);//选择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;//标准频率=72M/72=1M
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
    	
    	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
    
    第四步:
    初始化捕获单元:
    初始化结构体:

    • 初始化结构体原型:

    typedef struct
    {
    
      uint16_t TIM_Channel;      //指定要配置的通道
      uint16_t TIM_ICPolarity;   //选择极性
      uint16_t TIM_ICSelection;  //指定信号输入通道
      uint16_t TIM_ICPrescaler;  //触发信号分频器(注:此参数会改变信号的频率)
      uint16_t TIM_ICFilter;     //配置输入捕获的滤波器
    } TIM_ICInitTypeDef;
    
    初始化函数:
    
    /*
    	TIMx:选择要配置哪个定时器的捕获单元,其中x可以是1 2 3 4 5 8 9 12或15。
    	TIM_ICInitStruct:指向TIM_ICInitTypeDef类型结构体的指针
    */
    void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct)//配置指定定时器的指定输入捕获通道
    void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct)///此函数同时会把另一个通道配置为相反的配置(注:此函数只能配置输入捕获通道1或输入捕获通道2)
    
    第五步:
    /*
    	TIMx:选择要将哪个定时器配置为从模式,其中x可以是1 2 3 4 5 8 9 12或15。
    	TIM_InputTriggerSource:选择从模式的触发源
    */
    void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource)
    
    第六步:
    /*
    	TIMx:指定一个从模式定时器
    	TIM_SlaveMode:指定要执行的操作
    */
    void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode)
    
    第七步:
    TIM_Cmd(TIM3,ENABLE);
    
    • 读取:
    • 读取频率:

    想要获取最新一个周期的频率时,直接读取CCR寄存器,然后按照fc除N计算即可(fc,标准频率=72M/预分频系数)

    uint32_t IC_GetFreq(void)
    {
    	return 1000000 / (TIM_GetCapture1(TIM3)+1);//标准频率1Mhz/N
    }
    
    • 读取占空比:

    用CRR1的值(整个周期的时间)除以CCR2(周期中高电平的时间)

    uint32_t IC_GetDuty(void)
    {
    	return (TIM_GetCapture2(TIM3)+1)*100/(TIM_GetCapture1(TIM3)+1);
    }
    

    代码示例:

    void IC_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//开启TIM3的RCC时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA的RCC时钟
    	
    	GPIO_InitTypeDef GPIO_InitStruct;
    	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
    	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
    	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStruct);//配置PA16为上拉输入模式
    	
    	
    	TIM_InternalClockConfig(TIM3);//选择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;//标准频率=72M/72=1M
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
    	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
    	
    	TIM_ICInitTypeDef TIM_ICInitstructure;//定义结构体变量
    	TIM_ICInitstructure.TIM_Channel=TIM_Channel_1;//选择配置定时器3的捕获通道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_ICInit,配置TIM3的输入捕获通道
    	
    	TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//触发源选择TI1FP1
    	TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//从模式选择复位
    												//即TI1产生上升沿时,会触发CNT归零
    	
    	TIM_Cmd(TIM3,ENABLE);//使能TIM3,定时器开始运行
    }
    
    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);
    }
    

    PWMI模式:

    void IC_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//开启TIM3的RCC时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA的RCC时钟
    	
    	GPIO_InitTypeDef GPIO_InitStruct;
    	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
    	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
    	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStruct);//配置PA16为上拉输入模式
    	
    	
    	TIM_InternalClockConfig(TIM3);//选择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;//标准频率=72M/72=1M
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
    	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
    	
    	TIM_ICInitTypeDef TIM_ICInitstructure;//定义结构体变量
    	TIM_ICInitstructure.TIM_Channel=TIM_Channel_1;//选择配置定时器3的捕获通道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_PWMIConfig,配置TIM3的输入捕获通道
    											//此函数同时会把另一个通道配置为相反的配置,实现PWMI模式
    	
    	TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//触发源选择TI1FP1
    	TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//从模式选择复位
    												//即TI1产生上升沿时,会触发CNT归零
    	
    	TIM_Cmd(TIM3,ENABLE);//使能TIM3,定时器开始运行
    }
    
    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);
    }
    

    测频率的性能:

    • 测频率的范围:目前给标准频率1MHZ时,计数器最大只能到65535,所以测量的最低频率是1M/65535,大概是 15HZ,若频率再低,则溢出,此时可以增大预分屏,就可以使得标准频率更低
    • 测量的最高频率没有上限,但是频率越大,误差越大。如果非要找一个频率上限,就是1MHZ,因为超过标准频 率,时误差非常大
    • 如果要求误差等于1/1,000时,频率为上限,则这个上限就是1兆除1,000=1,000HZ
    • 如果要求误差可以到1%,那频率上限就是1MHZ除100=10KHZ
    • 如果想提高频率的上限,就要把PSC给降低一些,提高标准频率,上限制就会提高
    若要更高的频率,则用测频法

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32输入捕获技术详解

    发表评论