STM32CubeMX第六篇之捕获实验

文章目录

  • 前言
  • 结构体
    • SlaveMode(从模式)
    • InputTrigger(触发源)
    • TriggerPolarity(触发极性)
    • TriggerPrescaler(外部触发预分频)
    • TriggerFilter(外部触发滤波器)
  • keil版本
    • 初始化
    • 从模式设置
      • HAL_TIM_SlaveConfigSynchro
      • TIM_SlaveTimer_SetConfig
      • TIM_TI1_ConfigInputStage
  • CUBE版本
    • 初始化函数

前言

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

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

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

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

该工程的下载地址为:

  • keil版本:https://github.com/zhenhaiyang/keil
  • Cube版本:https://github.com/zhenhaiyang/STM32CUBE

结构体

/**
  * @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         */
/**
  * @}
  */

从模式的在寄存器上对应解释如下:
STM32CubeMX第六篇之捕获实验_第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                    */
/**
  * @}
  */

其对应寄存器解释为:
STM32CubeMX第六篇之捕获实验_第2张图片

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 */
/**
  * @}
  */

STM32CubeMX第六篇之捕获实验_第3张图片
STM32CubeMX第六篇之捕获实验_第4张图片

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. */
/**
  * @}
  */

STM32CubeMX第六篇之捕获实验_第5张图片

TriggerFilter(外部触发滤波器)

STM32CubeMX第六篇之捕获实验_第6张图片

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的中断与DMA
TIM_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的版本相同,不再详细解释。

你可能感兴趣的:(ARM,STM32,F429,ARM,捕获)