如何在STM32F7上使用PWM输入捕捉来测量变化的占空比

时间:2019-05-14 15:22:20

标签: freertos pwm stm32f7

我试图在运行FreeRTOS的STM32F7板上使用Timer12实现PWM输入捕获。作为概念证明,我尝试检测通常用于驱动伺服电机的PWM信号(整个周期为20 ms,脉冲为1ms,1.5ms或2 ms)。

我目前已设置Timer10以输出PWM信号。我有一个外部GPIO中断设置,每当我按板上的一个按钮时,就可以更改PWM信号的占空比(此中断实际上只是允许执行可更改占空比的FreeRTOS任务)。

我也将Timer12设置为PWM输入捕获。通道1设置为上升沿,以便可以检测信号的整个周期,而通道2设置为下降沿,以便可以检测信号的脉冲。但是,我希望此输入捕获是“可伸缩的”,以便可以将其用于许多不同周期的不同信号,因此我使输入捕获的周期非常小。通过这种方式,我可以使用PeriodElapsed回调函数来跟踪输入捕获周期已经经过了多少次。

int main(void)
{

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

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

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_USART1_UART_Init();
    MX_TIM10_Init();
    MX_TIM12_Init();

    HAL_UART_Transmit(&huart1, (uint8_t *)"start\r\n", 7, 100);
    HAL_TIM_PWM_Start_IT(&htim10, TIM_CHANNEL_1); // Start PWM signal

    if(xTaskCreate(vDisplayPWM, "PWM Display", 200, NULL, 3, &DisplayPWM) == pdPASS)
    {
        HAL_UART_Transmit(&huart1, (uint8_t *)"PWM display task created\r\n", 26, 100);
    }

    if(xTaskCreate(vChangePWMPeriod, "Period Change Display", 200, NULL, 3, &ChangePWMPeriod) == pdPASS)
    {
        HAL_UART_Transmit(&huart1, (uint8_t *)"Change period task created\r\n", 28, 100);
    }

    vTaskStartScheduler();

    /* Infinite loop */
    while (1)
    {
    }
}
static void MX_TIM10_Init(void)
{
    TIM_OC_InitTypeDef sConfigOC = {0};

    htim10.Instance = TIM10;
    htim10.Init.Prescaler = 1999;
    htim10.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim10.Init.Period = 2075;
    htim10.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim10.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    if (HAL_TIM_Base_Init(&htim10) != HAL_OK)
    {
        Error_Handler();
    }
    if (HAL_TIM_PWM_Init(&htim10) != HAL_OK)
    {
        Error_Handler();
    }
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 103;
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    if (HAL_TIM_PWM_ConfigChannel(&htim10, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
    {
        Error_Handler();
    }

    HAL_TIM_MspPostInit(&htim10);

}
static void MX_TIM12_Init(void)
{

    TIM_SlaveConfigTypeDef sSlaveConfig = {0};
    TIM_IC_InitTypeDef sConfigIC = {0};

    htim12.Instance = TIM12;
    htim12.Init.Prescaler = 0;
    htim12.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim12.Init.Period = 65535;
    htim12.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim12.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    if (HAL_TIM_Base_Init(&htim12) != HAL_OK)
    {
        Error_Handler();
    }
    if (HAL_TIM_IC_Init(&htim12) != 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(&htim12, &sSlaveConfig) != HAL_OK)
    {
        Error_Handler();
    }
    sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
    sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
    sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
    sConfigIC.ICFilter = 10;
    if (HAL_TIM_IC_ConfigChannel(&htim12, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
    {
        Error_Handler();
    }
    sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
    sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;
    if (HAL_TIM_IC_ConfigChannel(&htim12, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)
    {
        Error_Handler();
    }
    HAL_TIM_Base_Start_IT(&htim12);
    HAL_TIM_IC_Start_IT(&htim12, TIM_CHANNEL_1);
    HAL_TIM_IC_Start_IT(&htim12, TIM_CHANNEL_2);

}
void vDisplayPWM(void *pvParameters)
{
    uint32_t control = 0;
    uint32_t pwm_period_ticks = 0;
    uint32_t pwm_pulse_ticks = 0;
    for(;;)
    {
        if(ulTaskNotifyTake(pdTRUE, portMAX_DELAY) != 0)
        {
            control = ((float)pwm_pulse/(float)pwm_period) * 1000;
            pwm_period_ticks = pwm_period *  __HAL_TIM_GET_COMPARE(&htim12, TIM_CHANNEL_1);
            pwm_pulse_ticks = pwm_pulse *  __HAL_TIM_GET_COMPARE(&htim12, TIM_CHANNEL_2);
            switch(control)
            {
            case 48 ... 52: HAL_UART_Transmit(&huart1, (uint8_t *) "Mode 1\r\n", 8, 100);
            break;
            case 73 ... 77: HAL_UART_Transmit(&huart1, (uint8_t *) "Mode 2\r\n", 8, 100);
            break;
            case 98 ... 102: HAL_UART_Transmit(&huart1, (uint8_t *) "Mode 3\r\n", 8, 100);
            break;
            }
            sprintf(results, "period: %lu pulse: %lu input timer pulse: %lu\r\n", pwm_period_ticks, pwm_pulse_ticks, htim10.Instance->CCR1);
            HAL_UART_Transmit(&huart1, (uint8_t *) results, strlen(results), 100);
            //__HAL_TIM_SET_COUNTER(&htim12, 0);
            pwm_period = 0;
            pwm_pulse = 0;
            vTaskDelay(1000);
        }

    }
    vTaskDelete(NULL);
}
void vChangePWMPeriod(void *pvParameters)
{
        for(;;)
    {
        if(ulTaskNotifyTake(pdTRUE, portMAX_DELAY) != 0)
        {
            htim10.Instance->CCR1 += 52;
            if(htim10.Instance->CCR1 > 207)
            {
                htim10.Instance->CCR1 = 103;
            }
        }
        vTaskDelay(1000);
    }
    vTaskDelete(NULL);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM12)
    {
        pwm_period ++;
        if(pulse_flag) // If signal is high
        {
            pwm_pulse ++;
        }

    }
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    if(!pulse_flag) // Rising edge
    {
        pulse_flag = !pulse_flag;
        vTaskNotifyGiveFromISR(DisplayPWM,&xHigherPriorityTaskWoken);
        if(xHigherPriorityTaskWoken != pdFALSE)
        {
            portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
        }
    }
    else // Falling edge
    {
        pulse_flag = !pulse_flag;
    }

}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    HAL_GPIO_TogglePin(GPIOJ, GPIO_PIN_5);

    vTaskNotifyGiveFromISR(ChangePWMPeriod, &xHigherPriorityTaskWoken);
    if(xHigherPriorityTaskWoken != pdFALSE)
    {
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

我已经用示波器验证了Timer10的周期与我们的预期行为(20 ms周期,1ms 1.5ms或2 ms脉冲)匹配。但是,在串行监视器中监视反馈显示,从1ms脉冲到1.5ms脉冲,测量的脉冲值保持不变,然后对于2ms脉冲具有正确的值。任何反馈将不胜感激。

0 个答案:

没有答案