• 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];
  • 相关阅读:
    javascript判断页面第一次加载还是刷新操作【转】
    vs 2008 不能切换到设计视图的解决办法
    sql update 触发器 获得被update的行的信息
    方便winform中的数据验证,制作一个使用正则表达式验证数据的复合控件
    求一个n选x的算法
    在html链接里执行js和使用标签事件执行的不同
    咸吃萝卜淡操心:导入xlsx文件表格新增数据
    我亲爱的你,有两副面孔:表格末尾添加新内容
    Torture:跨域访问的功臣:window.name
    那么轻,那么重:图片下载与压缩包下载
  • 原文地址:https://www.cnblogs.com/chenbeibei/p/11435396.html
Copyright © 2020-2023  润新知