输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器,除了TIM6、TIM7,其他的定时器都有输入捕获的功能。应用场景是编码器。
测量频率
当捕获通道TIx 上出现上升沿时,发生第一次捕获,计数器CNT 的值会被锁存到捕获寄存器CCR 中,而且还会进入捕获中断,在中断服务程序中记录一次捕获(可以用一个标志变量来记录),并 把捕获寄存器中的值读取到value1 中。
当出现第二次上升沿时,发生第二次捕获,计数器CNT 的值会再次被锁存到捕获寄存器CCR 中,并再次进入捕获中断,在捕获中断中,把捕获寄存器 的值读取到value3 中,并清除捕获记录标志。利用value3 和value1 的差值我们就可以算出信号的 周期(频率)。
测量脉宽
当捕获通道TIx 上出现上升沿时,发生第一次捕获,计数器CNT 的值会被锁存到捕获寄存器CCR 中,而且还会进入捕获中断,在中断服务程序中记录一次捕获(可以用一个标志变量来记录),并 把捕获寄存器中的值读取到value1 中。
然后把捕获边沿改变为下降沿捕获,目的是捕获后面的 下降沿。当下降沿到来的时候,发生第二次捕获,计数器CNT 的值会再次被锁存到捕获寄存器 CCR 中,并再次进入捕获中断,在捕获中断中,把捕获寄存器的值读取到value2,利用value2-value1的差值即可算出脉冲宽度。
PWM输入模式
由上述我们知道,输入捕获模式,不仅可以单独测量脉宽,还可以单独测量频率,那么是否可以同时测量脉宽和频率呢?(这种也是最常用的方式),答案是肯定可以,只不过需要占用两个捕获寄存器(单独测量脉宽和频率只需要一个)
具体过程:
1.信号由输入通道TI1 进入,信号会被分为两路,一路是 TI1FP1,另外一路是TI2FP2。其中一路是周期,另一路是占空比。(作为触发输入的那一路信号对应的就是 周期,另一路就是对应占空比。作为触发输入的那一路信号还需要设置极性,是上升沿还是下降 沿捕获,一旦设置好触发输入的极性,另外一路硬件就会自动配置为相反的极性捕获,无需软件 配置。一句话概括就是:选定输入通道,确定触发信号,然后设置触发信号的极性即可)
2.将从模式控制器配置为复位模式(配置寄存器SMCR 的位 SMS[2:0] 来实现),即当我们启动触发信号开始进行捕获的时候,同时把计数器CNT 复位清零。
3.以下图为例:
PWM 信号由输入通道TI1 进入,配置TI1FP1 为触发信号,上升沿捕获。当上升沿的时候IC1 和 IC2 同时捕获,计数器CNT 清零。
到了下降沿的时候,IC2 捕获,此时计数器CNT 的值被锁存 到捕获寄存器CCR2 中,到了下一个上升沿的时候,IC1 捕获,计数器CNT 的值被锁存到捕获寄 存器CCR1 中。
可知CCR2 测量的是脉宽,CCR1 测量的是周期。
应用:
- 电机控制
输入捕获功能可用于监测电机的霍尔传感器反馈或者反电动势(back electromotive force, BEMF),从而确定电机的转子位置和速度,以便进行适时的换相,实现电机的高效控制。
- 实时监控和反馈控制
位置监测与控制:通过捕获传感器反馈信号,可以实时监测设备或系统的位置,并提供精确的反馈控制,如自动化生产线、机器人操作等。
速度闭环控制:捕获速度反馈信号,用于实现速度闭环控制系统,如电梯速度控制、风扇转速控制等。
- 串口通信同步(底层原理)
在串口通信中,数据的传输需要严格的同步,以确保发送端和接收端能够正确地识别和解析数据。输入捕获功能可以用于同步接收端的数据接收时钟,从而实现可靠的串口通信。
发送端:发送端根据通信协议的波特率(Baud Rate)产生一个连续的数据流,并将其转换成电平信号发送。波特率定义了每秒钟传输的比特数,因此发送端的时钟需要与波特率相匹配。
接收端:接收端使用输入捕获功能来捕获串口接收线上的数据边沿,通常是起始位(Start Bit)的边沿。通过捕获起始位的边沿,接收端可以确定数据的到达时间,并据此同步接收时钟。
同步原理:接收端根据捕获的起始位边沿和预设的波特率来生成一个本地时钟,该本地时钟与发送端的时钟同步。当本地时钟与发送端的时钟同步时,接收端就能够精确地在每个数据位的中间捕获数据,并正确地解析数据。
代码
cs
#include "public.h"
void TIMx_Capture_Config(void)
{
TIMx_GPIO_Config();
TIMx_NVIC_Config();
//配置TIM8时基
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
//APB2 84Mhz TIM8=168Mhz
TIM_TimeBaseStructure.TIM_Period= 50000; //ARR计数最大值 输入捕获有什么影响?
TIM_TimeBaseStructure.TIM_Prescaler= 168-1;//PSC分频系数
/*
168Mhz/168=1Mhz 数一个数:1/1000000 s 1/1Mhz = 168/168M x
*/
TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
//输入捕获配置
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //输入捕获通道选择
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
//???
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//设置捕获通道的信号直连和非直连
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//1分频,即捕获信号的每个有效边沿都捕获
TIM_ICInitStructure.TIM_ICFilter = 0x0;//滤波,经历几个周期跳变,认为波形稳定。
TIM_PWMIConfig(TIM8, &TIM_ICInitStructure);
/* Select the TIM8 Input Trigger: TI1FP1 */
TIM_SelectInputTrigger(TIM8, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM8, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM8,TIM_MasterSlaveMode_Enable);
TIM_Cmd(TIM8, ENABLE);
TIM_ClearITPendingBit(TIM8, TIM_IT_CC1);
TIM_ITConfig(TIM8, TIM_IT_CC1, ENABLE);
}
static void TIMx_GPIO_Config(void)
{
//1.TIM8 PC6 配置成输入捕获通道
GPIO_InitTypeDef GPIO_InitStructure;
/* TIM4 clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
/* GPIOB clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
/* TIM8 chenne1 configuration : PC.6 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Connect PC.6 pin to TIM8 */
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM8);
}
static void TIMx_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM8_CC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
cs
__IO uint16_t IC1Value=0; //TIM8 IC1的值
__IO uint16_t IC2Value=0; //TIM8 IC2的值
__IO float DutyCycle=0; //脉宽,占空比
__IO float Frequency=0; //频率
void TIM8_CC_IRQHandler(void)
{
if (TIM_GetITStatus(TIM8, TIM_IT_CC1) == SET)
{
TIM_ClearITPendingBit(TIM8, TIM_IT_CC1);
/* 获取输入捕获的值*/
IC1Value = TIM_GetCapture1(TIM8);
IC2Value = TIM_GetCapture2(TIM8);
if(IC1Value!=0)
{
//占空比
DutyCycle=(float)(IC2Value+1)/(IC1Value+1)*100;
//频率
Frequency= (168000000/168)/(float)IC1Value;
}
else
{
//周期和脉宽为0
DutyCycle=0;
Frequency=0;
}
}
cs
#include "public.h"
int main(void)
{
//2号分组:2bit给抢占 2bit给响应 0-3 0-3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
SysTick_Init();
//1.初始化定时器TIM4的通道引脚
TIMx_GPIO_Init();
//2.定时器TIM4初始化
TIMx_PWM_Config();
//修改CCR比较值,调节不同的占空比
//TIM_SetCompare1(TIM4,1000-1);
uint16_t Compare1=1;
uint16_t flag = 1;
while(1)
{
Delay_ms(2);
if(flag)
Compare1+=10;
else
Compare1-=10;
if(Compare1>2000-1)
flag=0;
if(Compare1<=10)
flag=1;
TIM_SetCompare1(TIM14,Compare1);
}
}