2017-04-18 70 views
2

STM32Cube初期化コードジェネレータを使用して、初期化されたタイマ機能を生成しました。固定デューティサイクルの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(); 
    } 

} 

Iハードコード右の値がsConfigOC.Pulse = pulse_widthpulse_width値を交換する際にこれが上記のコメントに指定された固定デューティ・サイクルでPWMを実行するのに十分です。 別の関数では、グローバル変数pulse_widthを更新するアルゴリズムがあります。関数はadjust_PWM();と呼ばれます。アルゴリズムは、ADCから測定され、グローバル変数として格納された値を計算します。その関数はData_Update();と呼ばれます。 main()では、すべての関数が初期化された後です。私はそれを試してオシロスコープ上で奇妙な波形を得無限

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

これら3つの機能を呼び出し、それはかもしれないアルゴリズムによってデューティ・サイクルを妨害するフローティング測定を引き起こし、フローティングADCピンため。また、タイマーの初期化を連続的に呼び出すと、PWM信号が中断されます。グローバル変数を使用せずに、またはデューティサイクルを更新するたびにタイマを初期化せずに、コードを実行している間にデューティサイクルを変更するより良い方法はありますか?すべてのリンクが評価されます。

+1

最も良い方法は、ST "HAL" bloatwareを取り除き、レジスタを直接プログラムすることです。これにより、コードの半分が実際にはより少ない労力で節約されます。 – Olaf

+0

@Olafはレジスタを直接プログラムしますか?あなたはよりハードウェア指向の誰かのために精緻化できますか? – Nadim

+0

リファレンスマニュアルを読んでください。STのCMSISとレジスタ定義ヘッダーのみを含め、周辺モジュールのレジスタを直接書き込む/読み込みます。ハードウェア指向の人として、これはあなたにさらに適しているはずです。この方法では、このbloatware **と**ハードウェアを使用する必要はありませんが、ハードウェアのみを使用します。 – Olaf

答えて

2

設定を変更したいときにタイマーを再初期化しないで、HALと呼ばれる、その目的のために専用のマクロを持っています

タイマ1の場合
/** 
    * @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 - チャンネル2に

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は浮動小数点をサポートしていますが、組み込みコードの負担となります。少なくともそのようなコードでは使用しないでください。通常、最上位レベルのアプリケーションコードだけが浮動小数点数を処理し、**必要な場合は** – Olaf

+0

@Olaf浮動小数点は危険であり、避けるべき場合があります。これらの説明的なコードでは、彼らの目的を理解して役立てるのがはるかに簡単です。ソフトフロートが問題となる場合、[0; 100] DCは[0; 0xFFFFU]または固定小数点などにマップできます。これはハードウェア浮動小数点よりも遅くなりますが、後者はより高い精度を維持します。 – Flip

+0

フロート処理の速度は唯一の問題ではなく、私はハザードについて話しませんでした(これは2つの問題です)。これは教師のための場所ではありませんが、経験豊富なエンベデッドプログラマは、問題が非常に多い合理的な場所で浮動小数点を避けるでしょう。 – Olaf

関連する問題