STM32CubeMX第六篇之捕获实验
发布日期:2021-05-14 11:31:45 浏览次数:15 分类:精选文章

本文共 16543 字,大约阅读时间需要 55 分钟。

文章目录

前言

本文主要讲解自己实现的捕获程序。本文程序借鉴了正点原子的例程。关于正点原子的程序详解,可以参考博客<>。

本文介绍的程序的不同主要如下:

  1. 通过高级时钟TIM8实现捕获功能。
  2. 通过通道1和通道2分别捕获PC6管脚上的上升沿与下降沿。
  3. 使用定时器的复位模式,实现硬件复位。

本文使用的HAL库的版本为:STM32Cube_FW_F4_V1.25.0

本文使用的STM32CubeMX版本为:6.1.1

该工程的下载地址为:

  • keil版本:
  • Cube版本:

结构体

/**  * @brief  TIM Slave configuration Structure definition  */typedef struct{     uint32_t  SlaveMode;         /*!< Slave mode selection                                    This parameter can be a value of @ref TIM_Slave_Mode */  uint32_t  InputTrigger;      /*!< Input Trigger source                                    This parameter can be a value of @ref TIM_Trigger_Selection */  uint32_t  TriggerPolarity;   /*!< Input Trigger polarity                                    This parameter can be a value of @ref TIM_Trigger_Polarity */  uint32_t  TriggerPrescaler;  /*!< Input trigger prescaler                                    This parameter can be a value of @ref TIM_Trigger_Prescaler */  uint32_t  TriggerFilter;     /*!< Input trigger filter                                    This parameter can be a number between Min_Data = 0x0 and Max_Data = 0xF  */} TIM_SlaveConfigTypeDef;

SlaveMode(从模式)

从模式的参数选择如下:

/** @defgroup TIM_Slave_Mode TIM Slave mode  * @{  */#define TIM_SLAVEMODE_DISABLE                0x00000000U                                        /*!< Slave mode disabled           */#define TIM_SLAVEMODE_RESET                  TIM_SMCR_SMS_2                                     /*!< Reset Mode                    */#define TIM_SLAVEMODE_GATED                  (TIM_SMCR_SMS_2 | TIM_SMCR_SMS_0)                  /*!< Gated Mode                    */#define TIM_SLAVEMODE_TRIGGER                (TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1)                  /*!< Trigger Mode                  */#define TIM_SLAVEMODE_EXTERNAL1              (TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0) /*!< External Clock Mode 1         *//**  * @}  */

从模式的在寄存器上对应解释如下:

在这里插入图片描述

InputTrigger(触发源)

触发源的参数选择如下:

/** @defgroup TIM_Trigger_Selection TIM Trigger Selection  * @{  */#define TIM_TS_ITR0          0x00000000U                                                       /*!< Internal Trigger 0 (ITR0)              */#define TIM_TS_ITR1          TIM_SMCR_TS_0                                                     /*!< Internal Trigger 1 (ITR1)              */#define TIM_TS_ITR2          TIM_SMCR_TS_1                                                     /*!< Internal Trigger 2 (ITR2)              */#define TIM_TS_ITR3          (TIM_SMCR_TS_0 | TIM_SMCR_TS_1)                                   /*!< Internal Trigger 3 (ITR3)              */#define TIM_TS_TI1F_ED       TIM_SMCR_TS_2                                                     /*!< TI1 Edge Detector (TI1F_ED)            */#define TIM_TS_TI1FP1        (TIM_SMCR_TS_0 | TIM_SMCR_TS_2)                                   /*!< Filtered Timer Input 1 (TI1FP1)        */#define TIM_TS_TI2FP2        (TIM_SMCR_TS_1 | TIM_SMCR_TS_2)                                   /*!< Filtered Timer Input 2 (TI2FP2)        */#define TIM_TS_ETRF          (TIM_SMCR_TS_0 | TIM_SMCR_TS_1 | TIM_SMCR_TS_2)                   /*!< Filtered External Trigger input (ETRF) */#define TIM_TS_NONE          0x0000FFFFU                                                       /*!< No trigger selected                    *//**  * @}  */

其对应寄存器解释为:

在这里插入图片描述

TriggerPolarity(触发极性)

/** @defgroup TIM_Trigger_Polarity TIM Trigger Polarity  * @{  */#define TIM_TRIGGERPOLARITY_INVERTED           TIM_ETRPOLARITY_INVERTED               /*!< Polarity for ETRx trigger sources             */#define TIM_TRIGGERPOLARITY_NONINVERTED        TIM_ETRPOLARITY_NONINVERTED            /*!< Polarity for ETRx trigger sources             */#define TIM_TRIGGERPOLARITY_RISING             TIM_INPUTCHANNELPOLARITY_RISING        /*!< Polarity for TIxFPx or TI1_ED trigger sources */#define TIM_TRIGGERPOLARITY_FALLING            TIM_INPUTCHANNELPOLARITY_FALLING       /*!< Polarity for TIxFPx or TI1_ED trigger sources */#define TIM_TRIGGERPOLARITY_BOTHEDGE           TIM_INPUTCHANNELPOLARITY_BOTHEDGE      /*!< Polarity for TIxFPx or TI1_ED trigger sources *//**  * @}  */

在这里插入图片描述

在这里插入图片描述

TriggerPrescaler(外部触发预分频)

/** @defgroup TIM_Trigger_Prescaler TIM Trigger Prescaler  * @{  */#define TIM_TRIGGERPRESCALER_DIV1             TIM_ETRPRESCALER_DIV1             /*!< No prescaler is used                                                       */#define TIM_TRIGGERPRESCALER_DIV2             TIM_ETRPRESCALER_DIV2             /*!< Prescaler for External ETR Trigger: Capture performed once every 2 events. */#define TIM_TRIGGERPRESCALER_DIV4             TIM_ETRPRESCALER_DIV4             /*!< Prescaler for External ETR Trigger: Capture performed once every 4 events. */#define TIM_TRIGGERPRESCALER_DIV8             TIM_ETRPRESCALER_DIV8             /*!< Prescaler for External ETR Trigger: Capture performed once every 8 events. *//**  * @}  */

在这里插入图片描述

TriggerFilter(外部触发滤波器)

在这里插入图片描述

keil版本

初始化

/**  * @brief 捕获初始化  * @note 无 * @param {*}无 * @retval 无 */void CaptureInit(void){       /* 1.RCC时钟初始化 */    __HAL_RCC_TIM8_CLK_ENABLE();    /* 2.基本时钟初始化 */    TIM_HandleTypeDef htim8 = {   0};    htim8.Instance = TIM8;                                     //时钟为TIM8    htim8.Init.Prescaler = 1 - 1;                              //预分频为0    htim8.Init.Period = 0xFFFF;                                //使用最大值    htim8.Init.RepetitionCounter = 0;                          //无重复模式    htim8.Init.AutoReloadPreload = TIM_AUTOMATICOUTPUT_ENABLE; //支持影子寄存器    htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;         //不分频    htim8.Init.CounterMode = TIM_COUNTERMODE_UP;               //向上计数模式    HAL_TIM_IC_Init(&htim8);                                   //初始化TIM8    /* 3.输入通道配置设置 */    TIM_IC_InitTypeDef initTim8Ic = {   0};    initTim8Ic.ICFilter = 0;                                      //不用滤波    initTim8Ic.ICPrescaler = TIM_ICPSC_DIV1;                      //不分频    initTim8Ic.ICPolarity = TIM_ICPOLARITY_RISING;                //捕捉上升沿    initTim8Ic.ICSelection = TIM_ICSELECTION_DIRECTTI;            //使用默认捕捉源    HAL_TIM_IC_ConfigChannel(&htim8, &initTim8Ic, TIM_CHANNEL_1); //初始化TIM8通道1    initTim8Ic.ICPolarity = TIM_ICPOLARITY_FALLING;               //捕捉下降沿    initTim8Ic.ICSelection = TIM_ICSELECTION_INDIRECTTI;          //使用替换捕捉源    HAL_TIM_IC_ConfigChannel(&htim8, &initTim8Ic, TIM_CHANNEL_2); //初始化TIM8通道2    /* 4.设置SLAVE模式 */    TIM_SlaveConfigTypeDef configTim8Slave = {   0};    configTim8Slave.SlaveMode = TIM_SLAVEMODE_RESET;              //复位模式    configTim8Slave.TriggerFilter = 0;                            //不滤波    configTim8Slave.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1; //不预分频    configTim8Slave.InputTrigger = TIM_TS_TI1FP1;                 //触发源为TI1FP1    configTim8Slave.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING; //上升沿触发    HAL_TIM_SlaveConfigSynchro(&htim8, &configTim8Slave);         //配置TIM8的通道1位触发源    /* 5.启动定时器 */    HAL_TIM_IC_Start_IT(&htim8, TIM_CHANNEL_1); //启动通道1    HAL_TIM_IC_Start_IT(&htim8, TIM_CHANNEL_2); //启动通道2    __HAL_TIM_ENABLE_IT(&htim8, TIM_IT_UPDATE); //启动更新中断    __HAL_TIM_URS_ENABLE(&htim8);               //更新中断只有溢出时触发}

整个捕获初始化程序可以大致分成5个部分:

  • RCC时钟初始化
  • 基本时钟初始化
  • 输入通道配置设置
  • 设置SLAVE模式
  • 启动定时器

在基本时钟初始化中,不同于正点原子程序,本文同时使用通道1和通道2分别捕获PC6的上升沿和下降沿。对应的,在第5步中,启动定时器tim8的通道1和通道2。

在第4步中,设置RESET模式。使用到结构体TIM_SlaveConfigTypeDef。其具体定义如上文详解。

需要尤其注意的是,第5步中,__HAL_TIM_URS_ENABLE(&htim8)启动URS功能。该功能只能减少触发更新中断的中断源。只有当计数器溢出时,才会触发更新中断。

从模式设置

整个从模式设置,在HAL库中的调用顺序为:

HAL_TIM_SlaveConfigSynchro()//调用子函数,禁用Trigger的中断与DMATIM_SlaveTimer_SetConfig()//设置SMCR,根据触发源分别调用子函数TIM_TI1_ConfigInputStage()//

下面分别介绍:

HAL_TIM_SlaveConfigSynchro

/**  * @brief  Configures the TIM in Slave mode  * @param  htim TIM handle.  * @param  sSlaveConfig pointer to a TIM_SlaveConfigTypeDef structure that  *         contains the selected trigger (internal trigger input, filtered  *         timer input or external trigger input) and the Slave mode  *         (Disable, Reset, Gated, Trigger, External clock mode 1).  * @retval HAL status  */HAL_StatusTypeDef HAL_TIM_SlaveConfigSynchro(TIM_HandleTypeDef *htim, TIM_SlaveConfigTypeDef *sSlaveConfig){       /* 1.参数检测 */    /* Check the parameters */    assert_param(IS_TIM_SLAVE_INSTANCE(htim->Instance));    assert_param(IS_TIM_SLAVE_MODE(sSlaveConfig->SlaveMode));    assert_param(IS_TIM_TRIGGER_SELECTION(sSlaveConfig->InputTrigger));    __HAL_LOCK(htim);    htim->State = HAL_TIM_STATE_BUSY;        /* 2.调用子函数 */    if (TIM_SlaveTimer_SetConfig(htim, sSlaveConfig) != HAL_OK)    {           htim->State = HAL_TIM_STATE_READY;        __HAL_UNLOCK(htim);        return HAL_ERROR;    }    /* 3.禁用Trigger中断和DMA */    /* Disable Trigger Interrupt */    __HAL_TIM_DISABLE_IT(htim, TIM_IT_TRIGGER);    /* Disable Trigger DMA request */    __HAL_TIM_DISABLE_DMA(htim, TIM_DMA_TRIGGER);    htim->State = HAL_TIM_STATE_READY;    __HAL_UNLOCK(htim);    return HAL_OK;}

整体分成三个部分:

  1. 参数检测。
  2. 调用子函数
  3. 禁用Trigger中断和DMA。

其中在配置之前将定时器句柄上锁,且句柄的状态变为BUSY。

在配置之后,将定时器句柄解锁,且句柄状态变为READY。

TIM_SlaveTimer_SetConfig

/**  * @brief  Slave Timer configuration function  * @param  htim TIM handle  * @param  sSlaveConfig Slave timer configuration  * @retval None  */static HAL_StatusTypeDef TIM_SlaveTimer_SetConfig(TIM_HandleTypeDef *htim,                                                  TIM_SlaveConfigTypeDef *sSlaveConfig){       uint32_t tmpsmcr;    uint32_t tmpccmr1;    uint32_t tmpccer;    /* 1.设置SMCR */    /* Get the TIMx SMCR register value */    tmpsmcr = htim->Instance->SMCR;    /* Reset the Trigger Selection Bits */    tmpsmcr &= ~TIM_SMCR_TS;    /* Set the Input Trigger source */    tmpsmcr |= sSlaveConfig->InputTrigger; //设置触发源    /* Reset the slave mode Bits */    tmpsmcr &= ~TIM_SMCR_SMS;    /* Set the slave mode */    tmpsmcr |= sSlaveConfig->SlaveMode; //设置从模式    /* Write to TIMx SMCR */    htim->Instance->SMCR = tmpsmcr;    /* 2.设置触发分频,滤波器,极性 */    /* Configure the trigger prescaler, filter, and polarity */    switch (sSlaveConfig->InputTrigger)    {       case TIM_TS_ETRF:    {           /* Check the parameters */        assert_param(IS_TIM_CLOCKSOURCE_ETRMODE1_INSTANCE(htim->Instance));        assert_param(IS_TIM_TRIGGERPRESCALER(sSlaveConfig->TriggerPrescaler));        assert_param(IS_TIM_TRIGGERPOLARITY(sSlaveConfig->TriggerPolarity));        assert_param(IS_TIM_TRIGGERFILTER(sSlaveConfig->TriggerFilter));        /* Configure the ETR Trigger source */        TIM_ETR_SetConfig(htim->Instance,                          sSlaveConfig->TriggerPrescaler,                          sSlaveConfig->TriggerPolarity,                          sSlaveConfig->TriggerFilter);        break;    }    case TIM_TS_TI1F_ED:    {           /* Check the parameters */        assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));        assert_param(IS_TIM_TRIGGERFILTER(sSlaveConfig->TriggerFilter));        if (sSlaveConfig->SlaveMode == TIM_SLAVEMODE_GATED)        {               return HAL_ERROR;        }        /* Disable the Channel 1: Reset the CC1E Bit */        tmpccer = htim->Instance->CCER;        htim->Instance->CCER &= ~TIM_CCER_CC1E;        tmpccmr1 = htim->Instance->CCMR1;        /* Set the filter */        tmpccmr1 &= ~TIM_CCMR1_IC1F;        tmpccmr1 |= ((sSlaveConfig->TriggerFilter) << 4U);        /* Write to TIMx CCMR1 and CCER registers */        htim->Instance->CCMR1 = tmpccmr1;        htim->Instance->CCER = tmpccer;        break;    }    case TIM_TS_TI1FP1:    {           /* Check the parameters */        assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));        assert_param(IS_TIM_TRIGGERPOLARITY(sSlaveConfig->TriggerPolarity));        assert_param(IS_TIM_TRIGGERFILTER(sSlaveConfig->TriggerFilter));        /* Configure TI1 Filter and Polarity */        TIM_TI1_ConfigInputStage(htim->Instance,                                 sSlaveConfig->TriggerPolarity,                                 sSlaveConfig->TriggerFilter);        break;    }    case TIM_TS_TI2FP2:    {           /* Check the parameters */        assert_param(IS_TIM_CC2_INSTANCE(htim->Instance));        assert_param(IS_TIM_TRIGGERPOLARITY(sSlaveConfig->TriggerPolarity));        assert_param(IS_TIM_TRIGGERFILTER(sSlaveConfig->TriggerFilter));        /* Configure TI2 Filter and Polarity */        TIM_TI2_ConfigInputStage(htim->Instance,                                 sSlaveConfig->TriggerPolarity,                                 sSlaveConfig->TriggerFilter);        break;    }    case TIM_TS_ITR0:    case TIM_TS_ITR1:    case TIM_TS_ITR2:    case TIM_TS_ITR3:    {           /* Check the parameter */        assert_param(IS_TIM_CC2_INSTANCE(htim->Instance));        break;    }    default:        break;    }    return HAL_OK;}

函数整体分成两个部分:

  1. 设置SMCR寄存器
  2. 根据触发源不同分别调用子函数。

在设置SMCR寄存器中,实现了两个功能:

  1. 设置触发源
  2. 设置从模式的模式

TIM_TI1_ConfigInputStage

/**  * @brief  Configure the Polarity and Filter for TI1.  * @param  TIMx to select the TIM peripheral.  * @param  TIM_ICPolarity The Input Polarity.  *          This parameter can be one of the following values:  *            @arg TIM_ICPOLARITY_RISING  *            @arg TIM_ICPOLARITY_FALLING  *            @arg TIM_ICPOLARITY_BOTHEDGE  * @param  TIM_ICFilter Specifies the Input Capture Filter.  *          This parameter must be a value between 0x00 and 0x0F.  * @retval None  */static void TIM_TI1_ConfigInputStage(TIM_TypeDef *TIMx, uint32_t TIM_ICPolarity, uint32_t TIM_ICFilter){       uint32_t tmpccmr1;    uint32_t tmpccer;    /* Disable the Channel 1: Reset the CC1E Bit */    tmpccer = TIMx->CCER;    TIMx->CCER &= ~TIM_CCER_CC1E;    tmpccmr1 = TIMx->CCMR1;    /* Set the filter */    tmpccmr1 &= ~TIM_CCMR1_IC1F;    tmpccmr1 |= (TIM_ICFilter << 4U);    /* Select the Polarity and set the CC1E Bit */    tmpccer &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP);    tmpccer |= TIM_ICPolarity;    /* Write to TIMx CCMR1 and CCER registers */    TIMx->CCMR1 = tmpccmr1;    TIMx->CCER = tmpccer;}

该函数和TIM_TI1_SetConfig的功能基本一致,该函数参见博客<>。

函数TIM_TI1_ConfigInputStage的功能为:

  1. 禁用通道1.
  2. 设置通道1滤波器。
  3. 设置极性。
  4. 将临时值写入寄存器。

函数TIM_TI1_SetConfig 与之相比就是多了一个设置信号源功能。

CUBE版本

初始化函数

/**  * @brief TIM8 Initialization Function  * @param None  * @retval None  */static void MX_TIM8_Init(void){       /* USER CODE BEGIN TIM8_Init 0 */    /* USER CODE END TIM8_Init 0 */    TIM_ClockConfigTypeDef sClockSourceConfig = {   0};    TIM_SlaveConfigTypeDef sSlaveConfig = {   0};    TIM_MasterConfigTypeDef sMasterConfig = {   0};    TIM_IC_InitTypeDef sConfigIC = {   0};    /* USER CODE BEGIN TIM8_Init 1 */    /* USER CODE END TIM8_Init 1 */    htim8.Instance = TIM8;    htim8.Init.Prescaler = 0;    htim8.Init.CounterMode = TIM_COUNTERMODE_UP;    htim8.Init.Period = 0xffff;    htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;    htim8.Init.RepetitionCounter = 0;    htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;    if (HAL_TIM_Base_Init(&htim8) != HAL_OK)    {           Error_Handler();    }    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;    if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK)    {           Error_Handler();    }    if (HAL_TIM_IC_Init(&htim8) != HAL_OK)    {           Error_Handler();    }    sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET;    sSlaveConfig.InputTrigger = TIM_TS_TI1FP1;    sSlaveConfig.TriggerPolarity = TIM_INPUTCHANNELPOLARITY_RISING;    sSlaveConfig.TriggerFilter = 0;    if (HAL_TIM_SlaveConfigSynchro(&htim8, &sSlaveConfig) != HAL_OK)    {           Error_Handler();    }    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;    if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)    {           Error_Handler();    }    sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;    sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;    sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;    sConfigIC.ICFilter = 0;    if (HAL_TIM_IC_ConfigChannel(&htim8, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)    {           Error_Handler();    }    sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;    sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;    if (HAL_TIM_IC_ConfigChannel(&htim8, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)    {           Error_Handler();    }    /* USER CODE BEGIN TIM8_Init 2 */    /* USER CODE END TIM8_Init 2 */}

该函数总共调用了以下几个库函数:

  • HAL_TIM_Base_Init:基本时钟初始化
  • HAL_TIM_ConfigClockSource:时钟源
  • HAL_TIM_IC_Init:基本时钟初始化
  • HAL_TIM_SlaveConfigSynchro:从模式初始化
  • HAL_TIMEx_MasterConfigSynchronization:主模式初始化
  • HAL_TIM_IC_ConfigChannel:输入通道配置

其中,前三个步骤的代码其实是重复的。HAL_TIM_IC_Init函数中会自动调用HAL_TIM_Base_Init

为当选择内部时钟为时钟源时,第二步是没有意义的:

case TIM_CLOCKSOURCE_INTERNAL:    {         assert_param(IS_TIM_INSTANCE(htim->Instance));      break;    }

后面的代码与keil的版本相同,不再详细解释。

上一篇:STM32F429第二十三篇之电容按键
下一篇:C++之数组与指针

发表评论

最新留言

表示我来过!
[***.240.166.169]2025年04月24日 22时58分14秒