2017-04-18 378 views
2

我使用STM32Cube初始化代码生成器来生成初始化的Timer函数。要生成固定占空比PWM信号,我将HAL_TIM_Base_Start(&htim1); //Starts the TIM Base generationHAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1)//Starts the PWM signal generation添加到定时器初始化函数中,如下所示。使用STM32 HAL定时器和调整PWM信号的占空比

/* Private variables ---------------------------------------------------------*/ 
int pulse_width=0; 

/* TIM1 init function */ 
static void MX_TIM1_Init(void) 
{ 

    TIM_ClockConfigTypeDef sClockSourceConfig; 
    TIM_MasterConfigTypeDef sMasterConfig; 
    TIM_OC_InitTypeDef sConfigOC; 
    TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig; 

    htim1.Instance = TIM1; 
    htim1.Init.Prescaler = 0;//we want a max frequency for timer, so we set prescaller to 0   
    //And our timer will have tick frequency 
    htim1.Init.CounterMode = TIM_COUNTERMODE_UP; 
    htim1.Init.Period = 1066;//max value for timer is 16bit = 65535, TIM_Period = timer_tick_frequency/PWM_frequency - 1 
    //In our case, for 15Khz PWM_frequency, set Period to TIM_Period = 16MHz/15KHz - 1 = 1066 
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; 
    htim1.Init.RepetitionCounter = 0; 
    if (HAL_TIM_Base_Init(&htim1) != HAL_OK)/* to use the Timer to generate a simple time base for TIM1 */ 
    { 
    Error_Handler(); 
    } 

    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;//the default clock is the internal clock from the APBx, using this function 
    if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)//Initializes the TIM PWM Time Base according to the specified 
//parameters in the TIM_HandleTypeDef and create the associated handle. 
    { 
    Error_Handler(); 
    } 

    if (HAL_TIM_PWM_Init(&htim1) != HAL_OK) 
    { 
    Error_Handler(); 
    } 

    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; 
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; 
    if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) 
    { 
    Error_Handler(); 
    } 

    //sConfig: TIM PWM configuration structure 
    //set duty cycle: pulse_length = ((1066 + 1) * duty_cycle)/(100 - 1) 
    sConfigOC.OCMode = TIM_OCMODE_PWM1; 
    sConfigOC.Pulse = pulse_width;/* 50% duty cycle is 538, set to 0 initially*/// 
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; 
    sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; 
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; 
    sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; 
    sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; 
    if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) 
    { 
    Error_Handler(); 
    } 

    if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) 
    { 
    Error_Handler(); 
    } 

    sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE; 
    sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE; 
    sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_1; 
    sBreakDeadTimeConfig.DeadTime = 0; 
    sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE; 
    sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; 
    sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE; 
    if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK) 
    { 
    Error_Handler(); 
    } 

    HAL_TIM_MspPostInit(&htim1);//output pin assignment 
    HAL_TIM_Base_Start(&htim1); //Starts the TIM Base generation 
    if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1) != HAL_OK)//Starts the PWM signal generation 
    { 
    /* PWM Generation Error */ 
    Error_Handler(); 
    } 

    /* Start channel 2 */ 
    if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2) != HAL_OK) 
    { 
    /* PWM Generation Error */ 
    Error_Handler(); 
    } 

} 

这足以运行在上述评论指定的固定的占空比的PWM,当我硬编码权值,以在sConfigOC.Pulse = pulse_width替换pulse_width值。 在另一个函数中,我有一个算法可以更新pulse_width全局变量。该功能被称为:adjust_PWM();。该算法计算从ADC测得的值并存储为全局变量。该功能称为:Data_Update();。在main()之后,所有功能都被初始化。我叫这三个功能不休

Data_Update(); 
adjust_PWM(); 
MX_TIM1_Init(); 

我想,和示波器获得怪异的波形,但可能是因为ADC引脚,其中浮动,造成浮地测量由算法占空比干涉。同时调用定时器的初始化会中断PWM信号。有没有更好的方法来在不使用全局变量的情况下运行代码时更改占空比,或者每次我想更新占空比时都没有初始化定时器,是否有更好的方法来改变占空比。任何链接将不胜感激。

+1

最好的方法是摆脱ST“HAL”英国媒体报道并直接编程寄存器。这实际上减少了一半的代码。 – Olaf

+0

@Olaf直接编程寄存器?你能详细说明一个更硬件导向的人吗? – Nadim

+0

阅读参考手册(无论如何),只包括来自ST的CMSIS和寄存器定义头,并直接写入/读取外设模块的寄存器。作为一个硬件导向的人,这也应该更适合你。这样你就不必摆弄这个英国媒体报道**和硬件,而只需要硬件。 – Olaf

回答

2

当你要更改设置,不要重新初始化定时器,HAL已经为目的的专用宏调用:

/** 
    * @brief Sets the TIM Capture Compare Register value on runtime without 
    *   calling another time ConfigChannel function. 
    * @param __HANDLE__: TIM handle. 
    * @param __CHANNEL__ : TIM Channels to be configured. 
    *   This parameter can be one of the following values: 
    *   @arg TIM_CHANNEL_1: TIM Channel 1 selected 
    *   @arg TIM_CHANNEL_2: TIM Channel 2 selected 
    *   @arg TIM_CHANNEL_3: TIM Channel 3 selected 
    *   @arg TIM_CHANNEL_4: TIM Channel 4 selected 
    * @param __COMPARE__: specifies the Capture Compare register new value. 
    * @retval None 
    */ 
#define __HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__) \ 
(*(__IO uint32_t *)(&((__HANDLE__)->Instance->CCR1) + ((__CHANNEL__) >> 2)) = (__COMPARE__)) 

定时器1 - 通道1和定时器1 - 通道二应该看起来像:

Data_Update(); 
adjust_PWM(); 

__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pulse_width); 
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, pulse_width); 
0

编写自己的函数来更新控制占空比的寄存器。您将不得不手动更新相应的CCRx寄存器(x是您使用的PWM通道,在您的情况下是CCR1)。

ARR寄存器是您在根据所需占空比计算CCR寄存器的新值时将参考的寄存器。

void adjust_PWM_DC(TIM_HandleTypeDef* const pwmHandle, const float DC) 
{ 
    assert(pwmHandle != NULL); 
    assert((DC >= 0.0F) && (DC <= 100.0F)); 

    /* The duty cycle value is a percentage of the reload register value (ARR). Rounding is used.*/ 
    uint32_t newRegVal = (uint32_t)roundf((float32_t)(pwmHandle->Instance->ARR) * (DC * 0.01F)); 

    /*In case of the DC being calculated as higher than the reload register, cap it to the reload register*/ 
    if(newRegVal > pwmHandle->Instance->ARR){ 
     newRegVal = pwmHandle->Instance->ARR); 
    } 

    /*Assign the new DC count to the capture compare register.*/ 
    pwmHandle->Instance->CCR1 = (uint32_t)(roundf(newRegVal)); /*Change CCR1 to appropriate channel, or pass it in with function.*/ 
} 
+0

尽管M4F和M7支持浮点,但它们仍然是嵌入代码的负担。不要使用它们,至少不要在这样的代码中使用它们。通常只有顶级应用程序代码应该处理浮点数,并且只有** iff **必需。 – Olaf

+0

@Olaf有些情况下浮点是危险的,应该避免。虽然他们在这段说明性代码中理解和服务他们的目的要简单得多。如果软浮点数是一个问题,那么[0; 100] DC可以映射到[0; 0xFFFFU]或固定点等。这虽然会比硬件浮点慢,后者也保留更高的精度。 – Flip

+0

浮动加工的速度不是唯一的问题,我没有谈论危害(这是两个问题)。这不是辅导的地方,但有经验的嵌入式程序员会避免在合理的情况下浮动,这是非常棘手的问题。 – Olaf