STM32定时器输入捕获航模接收机信号
STM32定时器输入捕获航模接收机信号
前言
最近在做一个检测航模接收机输出的舵机信号,并根据信号不同执行相应功能的小项目。硬件部分使用的是STM32F103C8T6通用定时器TIM3的通道1和通道2分别做两路信号的输入捕获(Input Capture)。
提示:以下是本篇文章正文内容,下面案例可供参考,如有错误,欢迎批评指正!
一、舵机信号(PWM)
PWM就是脉冲宽度调制,也就是占空比可调的脉冲信号。航模接收机输出的舵机PWM信号一般是频率为50HZ即周期为20ms,信号的高电平时间在1000us-2000us之间变化的PWM波,并且当遥控器打到中位时,信号高电平时间为1500us,如下图所:
二、STM32输入捕获功能框图
STM32F103通用定时器输入捕获功能框图如下所示,主要包括捕获通道选择、滤波器设置、捕获极性设置、映射关系设置及分频器配置等部分。
三、输入捕获初始化结构体定义及说明
STM32标准库的stm32f10x_tim.h中定义了定时器输入捕获初始化结构体:
/**
* @brief TIM Input Capture Init structure definition
*/
typedef struct
{
uint16_t TIM_Channel; /*!< 输入通道选择,共4个通道。TIM_Channel_1->TIM_Channel_4 */
uint16_t TIM_ICPolarity; /*!< 输入捕获极性设置,可选择上升沿捕获或下降沿捕获或两者都可捕获。
TIM_ICPolarity_Rising/TIM_ICPolarity_Falling/TIM_ICPolarity_BothEdge */
uint16_t TIM_ICSelection; /*!< 输入捕获通道选择,共3个通道。
TIM_ICSelection_DirectTI/TIM_ICSelection_IndirectTI/TIM_ICSelection_TRC */
uint16_t TIM_ICPrescaler; /*!< 输入捕获通道预分频。可设置分频因子为1、2、4、8*/
uint16_t TIM_ICFilter; /*!< 输入捕获滤波器设置。可设置为0x00到0x0F,一般不用设置为0x00 */
} TIM_ICInitTypeDef;
三、代码
#include "drv_pwm.h"
u8 TIM3_CHL1_CaptureFlag; // TIM3 CH1捕获标志
u32 TIM3_CHL1_Rising_Value ; // TIM3 CH1捕获上升沿值
u32 TIM3_CHL1_Falling_Value ; // TIM3 CH1捕获下降沿值
u16 TIM3_CHL1_PWM1_pulse; // TIM3 CH1捕获PWM脉宽数值
u8 TIM3_CHL2_CaptureFlag; // TIM3 CH2捕获标志
u32 TIM3_CHL2_Rising_Value ; // TIM3 CH2捕获上升沿值
u32 TIM3_CHL2_Falling_Value ; // TIM3 CH2捕获下降沿值
u16 TIM3_CHL2_PWM1_pulse; // TIM3 CH2捕获PWM脉宽数值
void drv_pwm_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
/* 打开GPIO时钟 */
RCC_APB2PeriphClockCmd(TIMX_PORT_CLK, ENABLE);
/* 打开定时器时钟 */
RCC_APB1PeriphClockCmd(TIMX_CLK, ENABLE);
/* 初始化PA6/PA7为下拉输入 */
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStruct.GPIO_Pin = PWM_TIMX_CHL1_PIN | PWM_TIMX_CHL2_PIN ;
GPIO_Init(TIMX_PORT, &GPIO_InitStruct);
GPIO_ResetBits(TIMX_PORT,PWM_TIMX_CHL1_PIN);
GPIO_ResetBits(TIMX_PORT,PWM_TIMX_CHL2_PIN);
/* 初始化定时器1配置 */
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
TIM_TimeBaseInitStruct.TIM_Period = 65535 - 1;
TIM_TimeBaseInitStruct.TIM_Prescaler = 72 - 1; // 1us
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIMX, &TIM_TimeBaseInitStruct);
/* 初始化定时器3中断 */
NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = TIMX_INTERRUPT;
NVIC_Init(& NVIC_InitStruct);
/* 初始化定时器3捕获通道1配置 */
TIM_ICInitStruct.TIM_Channel = PWM_TIMX_CHL1 ;
TIM_ICInitStruct.TIM_ICFilter = 0x00;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Falling; // 下降沿开始捕获(由于原理图中光耦对PWM做了反向,所以下降沿开始捕获)
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIMX, &TIM_ICInitStruct);
/* 初始化定时器3捕获通道1配置 */
TIM_ICInitStruct.TIM_Channel = PWM_TIMX_CHL2 ;
TIM_ICInitStruct.TIM_ICFilter = 0x00;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Falling; // 下降沿开始捕获(由于原理图中光耦对PWM做了反向,所以下降沿开始捕获)
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIMX, &TIM_ICInitStruct);
/* 使能 */
TIM_ITConfig(TIMX,TIM_IT_CC1,ENABLE);
TIM_ITConfig(TIMX,TIM_IT_CC2,ENABLE);
/* 使能定时器 */
TIM_Cmd(TIMX, ENABLE);
}
void TIM3_IRQHandler(void)
{
OS_CPU_SR cpu_sr = (OS_CPU_SR)0;
OS_ENTER_CRITICAL();
OSIntEnter();
OS_EXIT_CRITICAL();
if(TIM_GetITStatus(TIMX, TIM_IT_CC1) == SET){
TIM_ClearITPendingBit(TIMX, TIM_IT_CC1); // 清除标志位
if (TIM3_CHL1_CaptureFlag == 1)
{
TIM3_CHL1_Rising_Value = TIM_GetCapture1(TIMX); // 获取当时检测到上升沿时候CCR寄存器的计数值
if (TIM3_CHL1_Rising_Value < TIM3_CHL1_Falling_Value) // 说明当时获取CCR的值大于65535
Temp1_Value = 65535;
else
Temp1_Value = 0;
TIM3_CHL1_PWM1_pulse = TIM3_CHL1_Rising_Value - TIM3_CHL1_Falling_Value + Temp1_Value; // 计算出PWM1脉宽值
TIM3_CHL1_CaptureFlag = 0;
TIM_OC1PolarityConfig(TIMX, TIM_ICPolarity_Falling); // 设置下降沿捕获
}
else if (TIM3_CHL1_CaptureFlag == 0)
{
TIM3_CHL1_Falling_Value = TIM_GetCapture1(TIMX); // 获取当时检测到下降沿时候CCR寄存器的计数值
TIM3_CHL1_CaptureFlag = 1;
TIM_OC1PolarityConfig(TIMX, TIM_ICPolarity_Rising); // 设置上升沿捕获
}
}
if(TIM_GetITStatus(TIMX, TIM_IT_CC2) == SET){
TIM_ClearITPendingBit(TIMX, TIM_IT_CC2); // 清除标志位
if (TIM3_CHL2_CaptureFlag == 1)
{
TIM3_CHL2_Rising_Value = TIM_GetCapture2(TIMX); // 获取当时检测到上升沿时候CCR寄存器的计数值
if (TIM3_CHL2_Rising_Value < TIM3_CHL2_Falling_Value) // 说明当时获取CCR的值大于65535
Temp2_Value = 65535;
else
Temp2_Value = 0;
TIM3_CHL2_PWM1_pulse = TIM3_CHL2_Rising_Value - TIM3_CHL2_Falling_Value + Temp2_Value; // 计算出PWM2的脉宽值
TIM3_CHL2_CaptureFlag = 0;
TIM_OC2PolarityConfig(TIMX, TIM_ICPolarity_Falling); // 设置下降沿捕获
}
else if (TIM3_CHL2_CaptureFlag == 0)
{
TIM3_CHL2_Falling_Value = TIM_GetCapture2(TIMX); // 获取当时检测到下降沿时候CCR寄存器的计数值
TIM3_CHL2_CaptureFlag = 1;
TIM_OC2PolarityConfig(TIMX, TIM_ICPolarity_Rising); // 设置上升沿捕获
}
}
OSIntExit();
}
TIM3_CHL1_PWM1_pulse 及TIM3_CHL2_PWM1_pulse 即为获取的两路PWM高电平的时间,单位为us。
提示:以上是本篇文章全部内容,如有错误,欢迎批评指正!
----2023年5月7日 南京 多云 微凉