STM32输入捕获原理与配置


一、输入捕获原理

        输入捕获模式可以用来测量脉冲宽度或者测量频率。

        

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

       

二、输入捕获过程

1.设置输出捕获滤波器(通道1为例)

         滤波器IC1F[3:0]是用来设置输入采样频率和数字滤波器长度。f_{DTS}是根据TIMx_CR1的CKD[1:0]来设置的,如果CKD[1:0]设置为00,则f_{DTS} = f_{CK\, INT}。fCK_INT是内部时钟,等于72MHz。假如为上升沿触发,那么在捕获上升沿的时候,再以fCK_INT的频率连续采样8次通道1的电平,如果都是高电平,则是一个有效的触发。这样就可以滤掉低于8个采样周期的脉冲信号(IC1F[3:0]=0011,滤波长度N=8),实现滤波效果。IC1F[3:0]=0000,只用采集上升沿,就触发捕获。

2.设置输入捕获极性

         边沿检测器检测信号,比如设置为上升沿捕获,则捕获上升沿,下降沿同理;CC1输出设置高电平有效还是低电平有效;CC1输入则是选择捕获上升沿或下降沿。

3.设置输入捕获映射通道

 

         

4.设置输入捕获分频器

        

 

         每两个事件(设置为上升沿捕获):每隔2次上升沿执行一次捕获

5.捕获到有效信号可以开启中断

         如果开启了捕获中断,就是在捕获上升沿或下降沿  的时候开启中断。

6.工作工程        

        通过检测TIMx CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器 (TIMx CCRx)里面,完成一次捕获。

三、输入捕获编程流程(HAL库)

         

        1.定时器输入捕获时基参数初始化

        HAL_TIM_IC_Init(TIM_HandleTypeDef *htim);        // IC输入捕获初始化

        2.初始化通道参数配置

        HAL_TIM_IC_ConfigChannel(); 

        3.初始化回调函数(一般情况,回调函数里编写时钟使能,IO口配置以及优先级设置等)

        __HAL_RCC_TIM5_CLK_ENABLE();

        4.使能定时器并使能输入捕获通道

        HAL_TIM_IC_Start();             // 使能

        HAL_TIM_IC_Start_IT();        // 捕获的同时开启中断    

       

        5.捕获中断服务函数

        HAL_TIM_IRQHandler();

       

        6.读取捕获值

        uint32_t HAL_TIM_ReadCapturedValue();

四、程序要求

        测量信号的脉冲宽度。

五、代码实现

        tip:因为要检测上图高电平信号,所以我们用PA0按键,因为PA0是高电平有效,低电平无效。因为是用的是PA0,所以用的是TIM5_CH1。

1.timer.h

#ifndef __TIMER_H
#define __TIMER_H

#include "sys.h"

extern TIM_HandleTypeDef TIM5_IC_Handle;
void TIM5_IC_Init(void);


#endif

2.timer.c

#include "timer.h"

TIM_HandleTypeDef TIM5_IC_Handle;    // TIM句柄
TIM_IC_InitTypeDef TIM5_IC_InitStruct;   // TIM_IC句柄

void TIM5_IC_Init(void)
{

    TIM5_IC_Handle.Instance = TIM5;
    TIM5_IC_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;   // 设置TIM5的计数模式,向上计数
    TIM5_IC_Handle.Init.Period = 0xFFFFFFFF;               // 设置自动装载值
    TIM5_IC_Handle.Init.Prescaler = 90 - 1;               // 设置分频系数
    
    HAL_TIM_IC_Init(&TIM5_IC_Handle);


    TIM5_IC_InitStruct.ICPolarity = TIM_ICPOLARITY_RISING;                          // 捕获极性:上升沿捕获
    TIM5_IC_InitStruct.ICPrescaler = TIM_ICPSC_DIV1;                                // 输入分频:配置输入分频,选择不分频
    TIM5_IC_InitStruct.ICSelection = TIM_ICSELECTION_DIRECTTI;                      // 输入映射:映射到TI1上 
    TIM5_IC_InitStruct.ICFilter = 0;                                                // 配置滤波器,不滤波
    HAL_TIM_IC_ConfigChannel(&TIM5_IC_Handle, &TIM5_IC_InitStruct, TIM_CHANNEL_1);  // 配置IC通道

    HAL_TIM_IC_Start_IT(&TIM5_IC_Handle, TIM_CHANNEL_1);                            // 开启TIM5捕获通道,并且开启捕获中断
    __HAL_TIM_ENABLE_IT(&TIM5_IC_Handle, TIM_IT_UPDATE);                            // 当按键按得过长或许会溢出ARR(设定的装载值),需要记录溢出多少次,所以要开启更新中断

}


void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{

    if (htim->Instance == TIM5)                       // 判断为TIM5
    {
        
        __HAL_RCC_TIM5_CLK_ENABLE();                // 使能TIM5
        __HAL_RCC_GPIOA_CLK_ENABLE();               // 使能PA

        GPIO_InitTypeDef GPIO_InitStruct;           // GPIO句柄

        GPIO_InitStruct.Pin = GPIO_PIN_0;           // PA0
        GPIO_InitStruct.Pull = GPIO_PULLDOWN;       // 下拉
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;     // 推挽输出
        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;    // 高速
        GPIO_InitStruct.Alternate = GPIO_AF2_TIM5;  // 复用为TIM5

        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);      // 初始化GPIOA

        HAL_NVIC_EnableIRQ(TIM5_IRQn);              // 使能TIM5
        HAL_NVIC_SetPriority(TIM5_IRQn, 2, 1);      // 设置TIM5优先级

    }
    
}


/*
    捕获状态:
        [7]:0:没有捕获成功;1:捕获成功
        [6]:0:没有捕获高电平;1:捕获高电平
        [5-0]:捕获低电平后溢出的次数
*/

u8  TIM5CH1_CAPTURE_STA=0;	//输入捕获状态		    				
u32	TIM5CH1_CAPTURE_VAL;	//输入捕获值(TIM2/TIM5是32位)

void TIM5_IRQHandler(void)                              // TIM5中断服务函数
{

    HAL_TIM_IRQHandler(&TIM5_IC_Handle);            // 中断处理入口函数(所有的TIM中断都用函数)

}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)     // 定时器更新中断(溢出)处理回调函数,在HAL_TIM_IRQHandler调用
{

    if ((TIM5CH1_CAPTURE_STA&0x80) == 0)                        // 还未捕获成功
    {
        
        if (TIM5CH1_CAPTURE_STA&0x40)                    // 捕获成功
        {
            
            if ((TIM5CH1_CAPTURE_STA&0x3F) == 0x3F)             // 高电平太长
            {
                
                TIM5CH1_CAPTURE_STA |= 0x80;                    // 标记捕获成功一次
                TIM5CH1_CAPTURE_VAL = 0XFFFFFFFF;

            }
			else
			{
				
				TIM5CH1_CAPTURE_STA++;                              // 自加1次
				
			}
 
        }
        
    }
    
}

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)        // 定时器输入捕获回调函数,在HAL_TIM_IRQHandler调用
{

    if ((TIM5CH1_CAPTURE_STA&0x80) == 0)                        // 未捕获成功
    {
        
        if (TIM5CH1_CAPTURE_STA&0x40)                    // 捕获到下降沿
        {
            
            TIM5CH1_CAPTURE_STA |= 0x80;                        // 标志成功捕获到一次高电平脉宽
            TIM5CH1_CAPTURE_VAL = HAL_TIM_ReadCapturedValue(&TIM5_IC_Handle,TIM_CHANNEL_1);     // 获取当前的捕获值

            TIM_RESET_CAPTUREPOLARITY(&TIM5_IC_Handle, TIM_CHANNEL_1);                          // 清除之前的设置
            TIM_SET_CAPTUREPOLARITY(&TIM5_IC_Handle, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);     // 配置TIM5通道1上升沿捕获 

        }
        else
        {
            
            TIM5CH1_CAPTURE_STA = 0;                            // 清零
            TIM5CH1_CAPTURE_VAL = 0;
            TIM5CH1_CAPTURE_STA |= 0x40;                        // 捕获到上升沿

            __HAL_TIM_DISABLE(&TIM5_IC_Handle);                 // 关闭定时器TIM5
            __HAL_TIM_SET_COUNTER(&TIM5_IC_Handle, 0); 

            TIM_RESET_CAPTUREPOLARITY(&TIM5_IC_Handle, TIM_CHANNEL_1);                          // 清除之前的设置
            TIM_SET_CAPTUREPOLARITY(&TIM5_IC_Handle, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);     // 配置TIM5通道1下降沿捕获 

            __HAL_TIM_ENABLE(&TIM5_IC_Handle);                  // 使能TIM5

        }
        
        
    }
    

}

3.main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "timer.h"

extern u8  TIM5CH1_CAPTURE_STA;	//输入捕获状态		    				
extern u32	TIM5CH1_CAPTURE_VAL;	//输入捕获值(TIM2/TIM5是32位)

int main()
{

	long long temp = 0;
	HAL_Init();
	Stm32_Clock_Init(360, 25, 2, 8);
	delay_init(180);
	uart_init(115200);
	
	TIM5_IC_Init();

	while (1)
	{

		delay_ms(10);
		
		if (TIM5CH1_CAPTURE_STA&0x80)		// 成功捕获了一次高电平
		{
			
			temp = TIM5CH1_CAPTURE_STA&0x3F;		// 先把最大的值赋值给temp
			temp *= 0XFFFFFFFF;				// 再和TIM最大值相乘可以得到溢出时间的总和
			temp += TIM5CH1_CAPTURE_VAL;			// 得到高电平时间
			
			printf("高电平时间:%lldus \r\n", temp);		// 输出打印高电平时间
			
			TIM5CH1_CAPTURE_STA = 0;				// 清零,进行下一次捕捉

		}
		
		
	}
	

}

4.实验结果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值