STM32 PWM輸入模式采用DMA方式測量頻率和占空比


測試平台: STM32F030C8T6

固件庫: STM32F0xx_HAL_Driver

固件庫中提供了一個通過PWM輸入模式測量頻率和占空比的Demo,采用定時器中斷實現,測量頻率時中斷過於頻繁,雖然可以通過設置多個待測信號周期產生一次定時器中斷,來降低中斷頻率,但是這種方式測量出來的頻率和占空比會出現跳動,數據不是很穩定。

改進方案:用PWM輸入模式,將IC1和IC2的獲取,由定時器中斷方式,改為DMA方式。可以降低頻繁中斷引起的系統開銷,同時測量的數據更穩定。

代碼中使用的宏定義如下

#define TIMx                           TIM1
#define TIMx_CLK_ENABLE()              __HAL_RCC_TIM1_CLK_ENABLE()
#define DMAx_CLK_ENABLE                __HAL_RCC_DMA1_CLK_ENABLE

#define TIMx_CHANNEL_GPIO_PORT()       __HAL_RCC_GPIOA_CLK_ENABLE()
#define GPIO_PORT                      GPIOA
#define GPIO_PIN_CHANNEL2              GPIO_PIN_9
#define GPIO_AF_TIMx                   GPIO_AF2_TIM1

#define GPIO_PIN_CHANNEL1              GPIO_PIN_8

1. 配置並初始化TIM

TimHandle.Instance = TIMx;
TimHandle.Init.Period            = 0xFFFF;
TimHandle.Init.Prescaler         = 0;
TimHandle.Init.ClockDivision     = 0;
TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_IC_Init(&TimHandle) != HAL_OK)
{
    Error_Handler();
}

HAL_UART_Init會調用HAL_TIM_IC_MspInit,可在HAL_TIM_IC_MspInit的實現中配置硬件資源。

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
    GPIO_InitTypeDef   GPIO_InitStruct;
    DMA_HandleTypeDef  hdma_tim_ch1;
    DMA_HandleTypeDef  hdma_tim_ch2;

    TIMx_CLK_ENABLE();  
    DMAx_CLK_ENABLE();
    TIMx_CHANNEL_GPIO_PORT();
    
    /* Configure  (TIMx_Channel) in Alternate function, push-pull and High speed */
    GPIO_InitStruct.Pin = GPIO_PIN_CHANNEL2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF_TIMx;
    HAL_GPIO_Init(GPIO_PORT, &GPIO_InitStruct);
    
      
    GPIO_InitStruct.Pin = GPIO_PIN_CHANNEL1;
    HAL_GPIO_Init(GPIO_PORT, &GPIO_InitStruct);
    
    hdma_tim_ch1.Instance = DMA1_Channel2;
    hdma_tim_ch1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_tim_ch1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tim_ch1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tim_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_tim_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_tim_ch1.Init.Mode = DMA_CIRCULAR;
    hdma_tim_ch1.Init.Priority = DMA_PRIORITY_HIGH;
    if (HAL_DMA_Init(&hdma_tim_ch1) != HAL_OK)
    {
        Error_Handler();
    }
    __HAL_LINKDMA(htim, hdma[1], hdma_tim_ch1);
    
    hdma_tim_ch2.Instance = DMA1_Channel3;
    hdma_tim_ch2.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_tim_ch2.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tim_ch2.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tim_ch2.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_tim_ch2.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_tim_ch2.Init.Mode = DMA_CIRCULAR;
    hdma_tim_ch2.Init.Priority = DMA_PRIORITY_HIGH;
    if (HAL_DMA_Init(&hdma_tim_ch2) != HAL_OK)
    {
        Error_Handler();
    }
    __HAL_LINKDMA(htim, hdma[2], hdma_tim_ch2);
}

2. 配置輸入捕獲通道

/* Common configuration */
sConfig.ICPrescaler = TIM_ICPSC_DIV1;
sConfig.ICFilter = 0;

/* Configure the Input Capture of channel 1 */
sConfig.ICPolarity = TIM_ICPOLARITY_FALLING;
sConfig.ICSelection = TIM_ICSELECTION_INDIRECTTI;
if (HAL_TIM_IC_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_1) != HAL_OK)
{
    Error_Handler();
}

/* Configure the Input Capture of channel 2 */
sConfig.ICPolarity = TIM_ICPOLARITY_RISING;
sConfig.ICSelection = TIM_ICSELECTION_DIRECTTI;
if (HAL_TIM_IC_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_2) != HAL_OK)
{
    Error_Handler();
}

3. 配置從模式

sSlaveConfig.SlaveMode        = TIM_SLAVEMODE_RESET;
sSlaveConfig.InputTrigger     = TIM_TS_TI2FP2;
sSlaveConfig.TriggerPolarity  = TIM_TRIGGERPOLARITY_NONINVERTED;
sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;
sSlaveConfig.TriggerFilter    = 0;
if (HAL_TIM_SlaveConfigSynchronization(&TimHandle, &sSlaveConfig) != HAL_OK)
{
    Error_Handler();
}

4. 啟動輸入捕獲DMA

uint32_t PWM_IN[2]={0,0};

if(HAL_TIM_IC_Start_DMA(&TimHandle,TIM_CHANNEL_1,(uint32_t *)&PWM_IN[0],1) != HAL_OK)
{
    Error_Handler();
}

/* 捕獲通道1的DMA啟動之后,State狀態變為HAL_TIM_STATE_BUSY,修改之后,捕獲通道2才能啟動 */
TimHandle.State = HAL_TIM_STATE_READY;

if(HAL_TIM_IC_Start_DMA(&TimHandle,TIM_CHANNEL_2,(uint32_t *)&PWM_IN[1],1) != HAL_OK)
{
    Error_Handler();
}

5. 計算頻率及占空比

int freq, duty;

freq = HAL_RCC_GetHCLKFreq() / PWM_IN1[1];
duty = PWM_IN1[0] * 1000 / PWM_IN1[1];


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM