2017-04-18 2846 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