STM32第九课(Input Capture, HAL)

输入捕获测量高电平脉宽的原理,
首先设置定时器通道 x 为上升沿捕获,这样, t1 时刻,就会捕获到当前的 CNT 值,然后立即清零 CNT,
并设置通道 x为下降沿捕获,这样到 t2 时刻,又会发生捕获事件,得到此时的 CNT 值,记为 CCRx2。
根据定时器的计数频率,我们就可以算出 t1~t2 的时间,从而得到高电平脉宽。

在 t1~t2 之间,可能产生 N 次定时器溢出,这就要求我们对定时器溢出,做处理,
t1~t2之间, CNT计数的次数等于:
N*ARR+CCRx2,
有了这个计数次数,再乘以 CNT 的计数周期,即可得到 t2-t1 的时间长度,

定时器,除了 TIM6 和 TIM7,其他定时器都有输入捕获功能。

简单的说就是通过检测 TIMx_CHx 上的边沿信号,将当前定时器的值( TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。
同时还可以配置捕获时是否触发中断/DMA 等。

++++++++++++++++++++++++++++++++++++++++++
来看看捕获/比较模式寄存器 1: TIMx_CCMR,
TIMx_CCMR1 明显是针对 2 个通道的配置, CCMR2 这个寄存器 是用来控制通道 3 和通道 4。

输入捕获 1 滤波器 IC1F[3:0],这个用来设置输入采样频率和数字滤波器长度。
定时器的输入频率(TIMxCLK),一般为 84Mhz/168Mhz(看该定时器在那个总线上),
CKD[1:0]的设置来确定的分频比。
N 值就是滤波长度,
在捕获到上升沿的时候,连续采样到 N 次通道 1 的电平,如果都是高电平,则说明却是一个有效的触发,就会触发输入捕获中断(如果开启了的话)。
这样可以滤除那些高电平脉宽低于 8 个采样周期的脉冲信号,从而达到滤波的效果。
如果不做滤波处理,所以设置 IC1F[3:0]=0000,只要采集到上升沿,就触发捕获。

我们需要用到中断来处理捕获数据,所以必须开启通道 1 的捕获比较中断,

来看看捕获/比较寄存器 1: TIMx_CCR1,该寄存器用来存储捕获发生时, TIMx_CNT的值,我们从 TIMx_CCR1 就可以读出通道 1 捕获发生时刻的 TIMx_CNT 值,通过两次捕获(一次上升沿捕获,一次下降沿捕获)的差值,就可以计算出高电平脉冲的宽度(注意,对于脉宽太长的情况,还要计算定时器溢出的次数)。

+++++++++++++++++++++++++++++++++++++++
开启 TIM5 时钟,配置 PA0 为复用功能(AF2),并开启下拉电阻。
要使用 TIM5,我们必须先开启 TIM5 的时钟。
要捕获 TIM5_CH1 上面的高电平脉宽,所以先配置 PA0 为带下拉的复用功能,同时,为了让 PA0 的复用功能选择连接到 TIM5,所以设置 PA0 的复用功能为 AF2,即连接到 TIM5 上面。

__HAL_RCC_TIM5_CLK_ENABLE(); //使能 TIM5 时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启 GPIOA 时钟
GPIO_Initure.Pin=GPIO_PIN_0; //PA0
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推挽输出
GPIO_Initure.Pull=GPIO_PULLDOWN; //下拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH //高速
GPIO_Initure.Alternate=GPIO_AF2_TIM5; //PA0 复用为 TIM5 通道 1
HAL_GPIO_Init(GPIOA,&GPIO_Initure);

在 HAL 库中使用输入捕获特定的定时器初始化函数HAL_TIM_IC_Init。
函数内部会调用输入捕获初始化回调函数HAL_TIM_IC_MspInit来初始化与 MCU 无关的步骤。
函数 HAL_TIM_IC_Init 声明如下:

HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef *htim);

例如;

TIM_HandleTypeDef TIM5_Handler;
TIM5_Handler.Instance=TIM5; //通用定时器 5
TIM5_Handler.Init.Prescaler=89; //分频系数
TIM5_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; //向上计数器
TIM5_Handler.Init.Period= 0XFFFFFFFF; //自动装载值
TIM5_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; //时钟分频银子

HAL_TIM_IC_Init(&TIM5_Handler);//初始化输入捕获时基参数

设置 TIM5 的输入捕获参数,开启输入捕获。
HAL 库是通过 HAL_TIM_IC_ConfigChannel 函数来初始化输入比较参数的:

HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef *htim,
								TIM_IC_InitTypeDef* sConfig, uint32_t Channel);

第一个参数是定时器初始化结构体指针类型,即TIM句柄。
第三个参数是设置要初始化的定时器通道值,取值范围为 TIM_CHANNEL_1到TIM_CHANNEL_4。

第二个入口参数 sConfig,该参数是 TIM_IC_InitTypeDef 结构体指针类型,
它是真正用来初始化定时器通道的捕获参数的。该结构体类型定义为:

typedef struct
{
	uint32_t ICPolarity;
	uint32_t ICSelection;
	uint32_t ICPrescaler;
	uint32_t ICFilter;
} TIM_IC_InitTypeDef;

ICPolarity 用 来 设 置 输 入 信 号 的 有 效 捕 获 极 性 ,
取 值 范 围 为 :
TIM_ICPOLARITY_RISING(上升沿捕获),
TIM_ICPOLARITY_FALLING(下降沿捕获)和
TIM_ICPOLARITY_BOTHEDGE(双边沿)捕获。

ICSelection 用来设置映射关系,
我们配置 IC1 直接映射在 TI1 上,选择TIM_ICSELECTION_DIRECTTI。

ICPrescaler用来设置输入捕获分频系数, 可以设置为
TIM_ICPSC_DIV1(不分频),
TIM_ICPSC_DIV2(2 分频),
TIM_ICPSC_DIV4(4 分频)以及
TIM_ICPSC_DIV8(8 分频),

ICFilter 用来设置滤波器长度,这里我们不使用滤波器,所以设置为 0。

实例代码如下:

TIM_IC_InitTypeDef TIM5_CH1Config;
TIM5_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING; //上升沿捕获
TIM5_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI;//IC1 映射到 TI1 上
TIM5_CH1Config.ICPrescaler=TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM5_CH1Config.ICFilter=0; //配置输入滤波器,不滤波
HAL_TIM_IC_ConfigChannel(&TIM5_Handler,&TIM5_CH1Config,TIM_CHANNEL_1);

使能捕获和更新中断(设置 TIM5 的 DIER 寄存器)
我们要捕获的是高电平信号的脉宽,所以,第一次捕获是上升沿,第二次捕获时下降沿,必须在捕获上升沿之后,设置捕获边沿为下降沿,
由于 STM32F4 的 TIM5 是 32 位定时器,假设计数周期为 1us,那么需要 4294 秒才会溢出一次,这基本上是不可能的。

这两件事,我们都在中断里面做,所以必须开启捕获中断和更新中断。

HAL 还提供了一个函数同时用来开启定时器的输入捕获通道和使能捕获中断,实际上该函数同时还启动了定时器,一个函数具备三个功能。该函数为:

HAL_StatusTypeDef HAL_TIM_IC_Start_IT (TIM_HandleTypeDef *htim, uint32_t Channel);

如果我们不需要开启捕获中断,只是开启输入捕获功能, HAL 库函数为:

HAL_StatusTypeDef HAL_TIM_IC_Start (TIM_HandleTypeDef *htim, uint32_t Channel);

++++++++++++++++++++++++++++++++++++++
编写中断服务函数。定时器 5 中断服务函数为:

void TIM5_IRQHandler(void);

HAL 库提供了一个共用的中断处理入口函数 HAL_TIM_IRQHandler,该函数中会对
中断来源进行判断然后调用相应的中断处理回调函数。
HAL 库提供了多个中断处理回调函数,
我们要使用到更新中断和捕获中断,所以我们要使用的回调函数为:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);//更新(溢出) 中断
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);//捕获中断

++++++++++++++++++++++++++++++++++++++
实例,
在cubemx中,
配置PA0为TIM5_CH1.
选择pulldown。
选择speed high。

配置TIM5,
选择internal clock,
设置PSC为8399,
设置auto reload 为9999,
设置trigger event 为update event,

配置input capture channel 1,
设置polarity为 rising edge,
设置prescaler divide ratio 为 no divide,
设置input filter为4,即2^4,为16。

配置NVIC,使能TIM5的interrupt。

配置usart1,

覆盖定义HAL_TIM_IC_CaptureCallback。

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if(htim == &htim5){
        if(cap_rising_edge == 0){
                       
            cap_pulse_val = 0;
            
            __HAL_TIM_DISABLE(htim);
            __HAL_TIM_SET_COUNTER(htim,0);
            
            TIM_RESET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1);
            TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);
            __HAL_TIM_ENABLE(htim);
            
            cap_rising_edge = 1;
            
        }
        
        else if(cap_rising_edge == 1){
            if(cap_falling_edge == 0){
                               
                cap_pulse_val = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
                TIM_RESET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1);
                TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);
                
                cap_falling_edge = 1;
            
            }
        
        }
            
    }  
}

覆盖定义HAL_TIM_PeriodElapsedCallback。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim == &htim5){
        beep = !beep;
    }  
}

修改main,

		if(cap_rising_edge && cap_falling_edge){
            HAL_UART_Transmit(&huart1, (uint8_t*)&cap_pulse_val, 1, 1000);
            
            cap_rising_edge = 0;
            cap_falling_edge = 0;
        
        }

+++++++++++++++++++++++++++++++
在前后台架构中,callback负责打标,main负责清标。
另外,callback还需要负责进行一些必要的现场即时处理。
所以我们看到,这里callback除了负责打标,还负责即时配置TIM5。从而让TIM5接下来的行为符合要求。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: STM32F103RB 的 PWM 输入捕获代码可以通过使用内置的定时器和外设(如 IC 输入)来实现。您需要配置定时器以便捕获 PWM 信号,并通过 IC 输入中断读取捕获到的时间值。 以下是一份简单的代码示例,它演示了如何配置定时器以捕获 PWM 信号: ``` #include "stm32f10x.h" void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) { TIM_ClearITPendingBit(TIM2, TIM_IT_CC1); /* 读取捕获到的时间值 */ uint16_t capture = TIM_GetCapture1(TIM2); /* 在此处进行处理 */ } } void TIM2_Config(void) { /* 配置定时器 */ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period = 0xFFFF; TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &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; TIM_ICInitStructure.TIM_ICFilter = 0x0; TIM_ICInit(TIM2, &TIM_ICInitStructure); /* 使能输入捕获中断 */ TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE); NVIC_EnableIRQ(TIM2_IRQn); /* 启动定 ### 回答2: Stm32f103rb是ST公司推出的一款基于ARM Cortex-M3内核的32位微控制器。该微控制器具有丰富的外设功能,包括PWM输入捕获功能。 PWM输入捕获是一种用于测量外部PWM信号的功能。通过该功能,可以获取PWM信号的频率和占空比等参数。在Stm32f103rb中,可以通过配置定时器来实现PWM输入捕获功能。 在使用PWM输入捕获功能之前,需要先对定时器进行初始化,并设置输入引脚作为捕获通道。接着,需要配置定时器的工作模式为输入捕获模式,并设置相关的捕获参数。当有PWM信号输入时,定时器会自动捕获该信号,并记录捕获时刻的计数值。 使用PWM输入捕获功能的代码示例如下: 1. 初始化定时器 ```c TIM_HandleTypeDef htim; TIM_IC_InitTypeDef ic_config; htim.Instance = TIMX; htim.Init.Prescaler = 0; htim.Init.CounterMode = TIM_COUNTERMODE_UP; htim.Init.Period = 0xFFFF; htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&htim); ``` 2. 配置输入捕获通道 ```c ic_config.ICPolarity = TIM_ICPOLARITY_RISING; ic_config.ICSelection = TIM_ICSELECTION_DIRECTTI; HAL_TIM_IC_ConfigChannel(&htim, &ic_config, TIM_CHANNEL_X); ``` 3. 启动定时器 ```c HAL_TIM_Base_Start(&htim); ``` 4. 获取捕获值 ```c uint32_t capture_value = HAL_TIM_ReadCapturedValue(&htim, TIM_CHANNEL_X); ``` 在实际应用中,我们可以通过上述代码获取PWM信号的频率和占空比。频率可以通过捕获时刻的计数值与定时器时钟频率的比例计算得出,而占空比则可以通过周期与占空比的比例计算得出。 以上是关于Stm32f103rb PWM输入捕获功能的简要介绍和代码示例。具体的应用场景和使用方式根据实际需求可能会有所不同,需要根据具体情况进行相应调整和完善。 ### 回答3: Stm32f103rb是一款常用的32位ARM微控制器,可以用于实现各种嵌入式系统。其中PWM输入捕获是一种常见的用法,用于测量或获取外部信号的脉宽信息。 可以通过以下步骤来编写Stm32f103rb的PWM输入捕获代码: 1. 初始化计时器和GPIO引脚: 首先,需要初始化相应的定时器和GPIO引脚,用于接收和测量PWM输入信号。根据需求选择合适的定时器和GPIO引脚。 2. 配置定时器为输入捕获模式: 将定时器配置为输入捕获模式,使其能够测量外部信号的脉宽。需要设置定时器的捕获模式、输入频率和捕获触发方式等参数。 3. 编写中断服务程序: 当定时器捕获到PWM输入信号时,会触发中断。需要编写相应的中断服务程序,用于处理捕获到的信号和数据。 4. 获取捕获信号的脉宽信息: 在中断服务程序中,可以通过定时器的捕获寄存器获取捕获到的PWM信号的脉宽信息。可以将脉宽数据保存到变量中,用于后续的处理或显示。 5. 使用脉宽信息进行其他操作: 获取到脉宽信息后,可以进行各种操作,如计算频率、测量信号周期、控制其他外设等。 需要注意的是,实现PWM输入捕获功能时,需要根据具体的硬件和使用的定时器进行相应的配置和编程。以上是大致的代码流程,具体实现的细节还需要根据具体的需求和环境进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值