STM32L051使用HAL库操作实例(10)- 输入捕获实例

目录

一、前言

二、工作原理

①输入捕获的通道概览

②输入捕获的工作过程

③溢出时间计算

三、STM32CubeMX配置(本文使用的STM32CubeMX版本为5.6.0)

1.MCU选型

2.使能时钟

3.时钟配置

​4.设置GPIO口​

5.定时器配置

6.串口配置

四、配置STM32CubeMX生成工程文件​​

五、KEIL程序


一、前言

STM32L051C8T6除了基本定时器 TIM6 和 LPTIM1,其他定时器都具有输入捕 获功能。输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,通常用于测量输入信号的脉宽、测量 PWM 输入信号的频率及占空比。

二、工作原理

 

STM32L051使用HAL库操作实例(10)- 输入捕获实例_第1张图片

在通用定时器框图中,主要涉及到最顶上的一部分(计数时钟的选择)、中间部分(时基单元)、左下部分(输入捕获)这三个部分。这里主要讲解一下左下部分(输入捕获);

①输入捕获的通道概览

  • 每一个捕获/比较通道都是围绕着一个捕获/比较寄存器(包含影子寄存器),包括捕获的输入部分(数字滤波、多路复用和预分频器),和输出部分(比较器和输出控制)
  • 捕获/比较模块由一个预装载寄存器和一个影子寄存器组成。读写过程仅操作预装载寄存器。
  • 在捕获模式下,捕获发生在影子寄存器上,然后再复制到预装载寄存器中。
  • 在比较模式下,预装载寄存器的内容被复制到影子寄存器中,然后影子寄存器的内容和计数器进行比较。
    STM32L051使用HAL库操作实例(10)- 输入捕获实例_第2张图片
  • 输入部分对相应的TIx输入信号采样,并产生一个滤波后的信号TIxF。然后,一个带极性选择的边缘检测器产生一个信号(TIxFPx),它可以作为从模式控制器的输入触发或者作为捕获控制。该信号通过预分频进入捕获寄存器(ICxPS)。

总结下来工作过程:通过检测TIMx_CHx通道上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。同时,还可以配置捕获时是否触发中断/DMA等。

②输入捕获的工作过程

将输入捕获的通道图进行分解,分解成四个部分,下面对这四个部分进行分析来了解输入捕获的工作过程:
STM32L051使用HAL库操作实例(10)- 输入捕获实例_第3张图片

  • 设置输入捕获滤波器
    输入捕获滤波器IC1F[3:0],这个用于设置采样频率和数字滤波器长度。其中:fCK_INT是定时器的输入频率,fDTS是根据TIMx_CR1的CKD[1:0]的设置来确定的。
    这里滤波器的作用是什么呢?数字滤波器由一个事件计数器组成,它记录到N个事件后会产生一个输出的跳变。也就是说连续N次采样,如果都是高电平,则说明这是一个有效的触发,就会进入输入捕捉中断(如果设置了的话)。这样就可以滤除那些高电平脉宽低于8个采样周期的脉冲信号,从而达到滤波的作用。
  • 设置输入捕捉极性
    这里是设置捕捉事件是发生在上升沿还是下降沿。
  • 设置输入捕获映射关系
    STM32L051使用HAL库操作实例(10)- 输入捕获实例_第4张图片
    在TIMx_CH1和TIMx_CH2两条通道的情况下,我们可以看出除了TIMx_CH1捕捉到的信号可以连接到IC1,TIMx_CH2捕捉到的信号可以连接到IC2之外,TIMx_CH1捕捉到的信号也可以连接到IC2,TIMx_CH2捕捉到的信号也可以连接到IC1。
    一般情况下,我们设置成TIMx_CH1捕捉到的信号可以连接到IC1,TIMx_CH2捕捉到的信号可以连接到IC2。
  • 设置输入捕获分频器
    这里设置的是每N个事件触发一次捕捉。也就是说,我们可以设置成,每2次上升沿事件触发一次捕捉。

③溢出时间计算

STM32L051使用HAL库操作实例(10)- 输入捕获实例_第5张图片

t1时刻检测到高电平,发生中断,在中断里将计数值置0,开始记溢出次数N,

其中每计数0xFFFF次溢出一次,直到t2时刻跳变回低电平,

获取最后一次溢出时到t2时刻的计数值TIM2CH1_CAPTURE_VAL

则  高电平时间 = 溢出次数*65535+TIM2CH1_CAPTURE_VAL     us ;根据定时器初始化时的频率即可计算出溢出总次数所占用的时间,即为高电平时间。

如果计数器值为 32 bit   那么最大为0xFFFFFFFF

如果计数器值为 16bit   那么最大为0xFFFF

高电平时间:

三、STM32CubeMX配置(本文使用的STM32CubeMX版本为5.6.0)

思路:将LED3配置成呼吸灯。

1.MCU选型

本例程使用的为STM32L051C8T6型号

2.使能时钟

3.时钟配置

STM32L051使用HAL库操作实例(10)- 输入捕获实例_第6张图片
4.设置GPIO口
STM32L051使用HAL库操作实例(10)- 输入捕获实例_第7张图片

5.定时器配置

①定时器配置
STM32L051使用HAL库操作实例(10)- 输入捕获实例_第8张图片

  • 1设置定时器CH1为输入捕获模式
  • 2.设置分频系数及装载值
  • 3.开启定时器中断

6.串口配置

STM32L051使用HAL库操作实例(10)- 输入捕获实例_第9张图片

  • 1设置串口通讯模式为异步通讯模式
  • 2.设置串口波特率、数据位、检验位、停止位

 

四、配置STM32CubeMX生成工程文件

6.点击GENERATE CODE生成工程文件

五、KEIL程序

1.相关函数:

初始化定时器函数,此函数初始化了在STM32CubeMX内设置的参数,系统已经处理好了,并已经添加在了main函数内;

MX_TIM2_Init();  //初始化定时器配置

使能TIM2定时器;

HAL_TIM_Base_Start_IT(&htim2);

开启定时器输入捕获中断;

HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);

在main.h中添加枚举定义变量;

typedef struct              //测量低电平脉宽
{   
	uint8_t   ucFinishFlag; //结束
	uint8_t   ucStartFlag;  //开始
	uint16_t  usCtr;
	uint16_t  usPeriod;
}STRUCT_CAPTURE;

在main.c中定义全局变量;

/* USER CODE BEGIN 0 */
STRUCT_CAPTURE strCapture = { 0, 0, 0 };
uint32_t ulTmrClk, ulTime,ulTimea,ulTimeb;
/* USER CODE END 0 */

在main函数代码;

int main(void)
{
    /* USER CODE BEGIN 1 */
    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_TIM2_Init();
    MX_USART1_UART_Init();
    /* USER CODE BEGIN 2 */
    printf ( "STM32 输入捕获实验\n" );
    printf ( "按下KEY1,测试KEY1按下的时间\n" );
		/* 获取定时器时钟周期 */	
    ulTmrClk = HAL_RCC_GetHCLKFreq()/32; //实际上就是定时器时钟/预分频系数 32M/32获取每次计数时间
		/* 启动定时器 */
    HAL_TIM_Base_Start_IT(&htim2);
		/* 启动定时器通道输入捕获并开启中断 */
    HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);

    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
        /* 完成测量低电平脉宽 */
        if(strCapture.ucFinishFlag == 1 )
        {
            /* 计算低电平计数值 ,0xFFFF为Period计数周期*/
            ulTime = strCapture .usPeriod * 0xFFFF + strCapture .usCtr;
            /* 打印低电平脉宽时间 */
            printf ( ">>测得低电平脉宽时间:%d.%d s\n", ulTime / ulTmrClk, ulTime % ulTmrClk );
            strCapture .ucFinishFlag = 0;
        }
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */
}

在main.c文件中添加中断回调函数,用于处理定时器输入捕获时处理的数据;

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    /*每次溢出时间为65536us*/
    /*需要判断电平时间是否太长*/
    if(strCapture.ucFinishFlag==0)//还未成功捕获
    {
        if(strCapture.ucStartFlag==1)//已经开始捕获
        {
            if(strCapture.usPeriod==0XFFFF)//电平太长了
            {
                strCapture.ucFinishFlag=1;		//标记成功捕获了一次
                strCapture .usCtr=0XFFFF;
            } else strCapture .usPeriod ++;
        }
    }
    /*不需要判断电平时间是否太长*/
//  strCapture .usPeriod ++;
}

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    TIM_IC_InitTypeDef sConfigIC;

    if ( strCapture .ucStartFlag == 0 )
    {

        __HAL_TIM_SET_COUNTER(htim,0); // 清零定时器计数
        strCapture .usPeriod = 0;
        strCapture .usCtr = 0;

        /*配置输入捕获参数,主要是修改触发电平*/
        sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
        sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
        sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
        sConfigIC.ICFilter = 0;
        HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);
        /*清除中断标志位*/
        __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);
        /*启动输入捕获并开启中断*/
        HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
        strCapture .ucStartFlag = 1;
    }

    else
    {

        /*获取定时器计数值*/
        strCapture .usCtr = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);
        /*配置输入捕获参数,主要是修改触发电平*/
        sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
        sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
        sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
        sConfigIC.ICFilter = 0;
        HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);

        /*清除中断标志位*/
        __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);
        /*启动输入捕获并开启中断*/
        HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
        strCapture .ucStartFlag = 0;
        strCapture .ucFinishFlag = 1;
    }
}
/* USER CODE END 4 */

在usart.c文件中添加串口重定向;

#include "stdio.h"   //这个一定不能忘

/* USER CODE BEGIN 1 */

/**
  * 函数功能: 重定向c库函数printf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
    return ch;
}

/**
  * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fgetc(FILE * f)
{
    uint8_t ch = 0;
    HAL_UART_Receive(&huart1,&ch, 1, 0xffff);
    return ch;
}

/* USER CODE END 1 */

2.编译文件,下载。即可,将杜邦线PA0与PB0引脚相连接,按下KEY1实现效果如下:

STM32L051使用HAL库操作实例(10)- 输入捕获实例_第10张图片

源工程文件代码下载:https://download.csdn.net/download/cheng_nnan/12366745

你可能感兴趣的