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日 南京 多云 微凉