江科大STM32入门——输入捕获笔记总结
wx:嵌入式工程师成长日记
输入捕获原理
输入捕获是指 STM32 的定时器可以对外部输入信号的边沿进行检测,并记录下相应的时刻。其基本原理基于定时器的计数器和相关寄存器。
当外部信号连接到定时器的输入捕获引脚时,定时器会根据设定的捕获条件,如上升沿或下降沿,对信号进行监测。当满足捕获条件时,定时器会将当前计数器的值复制到捕获 / 比较寄存器中。通过读取捕获 / 比较寄存器的值,就可以获取到信号边沿出现的时刻。
波形图
1.如果两个上跳沿的捕获发生在同一个计数周期内,两个计数值分别为CCR1和CCR2,则方波的周期为CCR2-CCR1个计数周期,根据定时器的周期就可以计算出方波周期和频率。
如果方波周期超过定时器的计数周期,或两次输入捕获发生在相邻的两个定时周期内,如图CCR2和CCR3,则只需将计数器的计数周期和事件发生次数考虑进去即可,根据CCR2和CCR3计算的脉冲周期应该是 ARR - CCR1 + CCR2。
输入捕获代码配置:
1.定时器初始化配置
htim2.Instance = TIM2;
//将定时器设置为TIM2。
htim2.Init.Prescaler = 84-1;
//设置预分频器的值为83(实际值减去1)。预分频器用于将输入时钟频率分频,从而得到更低的计数频率。在这里,输入时钟频率将被除以84,获得的计数频率为84Mhz /(84-1 +1) = 1MHz。
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
//将计数模式设置为向上计数模式。在向上计数模式下,计数器从0递增到自动重载值。
htim2.Init.Period = 0xFFFFFFFF;
//设置自动重载寄存器的值为0xFFFFFFFF(32位最大值)。这意味着计数器将从0递增到0xFFFFFFFF,然后重新从0开始循环。
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
//设置时钟分频系数为不分频(TIM_CLOCKDIVISION_DIV1)。时钟分频用于进一步分频计数器的时钟频率。
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
//启用自动重载预装载功能。当该功能启用时,新的自动重载值在下一个更新事件时生效,以避免在计数器工作时意外更改自动重载值。
2.启动定时器TIM2的中断模式,并开始输入捕获功能
HAL_TIM_Base_Start_IT(&htim2);
/* 启动TIM2定时器的中断模式 */
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
/* 以中断方式开启TIM2的输入捕获模式 */
3.定时器回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim2){ /* 判断是否为定时器TIM2 */
if(ic_state == runing){ /* 判断是否为是 正在运行状态 */
tim_over ++; /* 定时器溢出值计数 */
}
}
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim2){ /* 判断是否为定时器TIM2 */
if(ic_state == idle){ /* 判断状态是不是 空闲 */
ic_state = runing; /* 将状态设置为 正在运行 */
tim_value = 0; /* 计数值清零 */
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING); /* 将TIM2的通道1捕获极性设置为下降沿捕获 */
__HAL_TIM_SET_COUNTER(&htim2,0); /* 将TIM2的计数值设置为0 */
}else{ /* 此时不是空闲状态 */
HAL_TIM_IC_Stop_IT(&htim2,TIM_CHANNEL_1);/* 停止定时器2输入捕获功能 */
ic_state = end; /* 将状态设置为 结束 */
tim_value = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1); /* 获取此时计数值 */
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);/* 将TIM2的通道1捕获极性设置为上升沿捕获 */
}
}
}
PWM波(输出捕获)
PWM初始化:
//TIM3 PWM初始化
//arr 重装载值
//psc 预分频系数
void TIM3_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStrue;
TIM_OCInitTypeDef TIM_OCInitStrue;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrue;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //使能TIM3和相关GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);// 使能GPIOB时钟(LED在BP5引脚),使能AFIO时钟(定时器3通道2需要重映射到BP5引脚)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStrue.GPIO_Pin=GPIO_Pin_5; // TIM_CH2
GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP; // 复用推挽
GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz; //设置最大输出速度
GPIO_Init(GPIOB,&GPIO_InitStrue); //GPIO端口初始化设置
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);
TIM_TimeBaseInitStrue.TIM_Period=arr; //设置自动重装载值
TIM_TimeBaseInitStrue.TIM_Prescaler=psc; //预分频系数
TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up; //计数器向上溢出
TIM_TimeBaseInitStrue.TIM_ClockDivision=TIM_CKD_DIV1; //时钟的分频因子,起到了一点点的延时作用,一般设为TIM_CKD_DIV1
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStrue); //TIM3初始化设置(设置PWM的周期)
TIM_OCInitStrue.TIM_OCMode=TIM_OCMode_PWM2; // PWM模式2:CNT>CCR时输出有效
TIM_OCInitStrue.TIM_OCPolarity=TIM_OCPolarity_High;// 设置极性-有效为高电平
TIM_OCInitStrue.TIM_OutputState=TIM_OutputState_Enable;// 输出使能
TIM_OC2Init(TIM3,&TIM_OCInitStrue); //TIM3的通道2PWM 模式设置
TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能预装载寄存器
TIM_Cmd(TIM3,ENABLE); //使能TIM3
}
PWM模式:
PWM模式1:在向上计数时,一旦TIMX_CNT<TIMX_CCR1时通道1为有效电平,否则为无效电平:在向下计数时,一旦TIMX_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。
PWM模式2:在向上计数时,一旦TIMX_CNT<TIMX_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMX_CNT>TIMX_CCR1时通道1为有效电平,否则为无效电平。