基於STM32F429和Cube的主從定時器多通道輸出固定個數的PWM波形

主從定時器的原理已在上篇博文:html

基於STM32F429+HAL庫編寫的定時器主從門控模式級聯輸出固定個數PWM脈衝的程序

講解了,這篇重點就講如何實現多通道的PWM級聯輸出。函數

1.軟件環境

   Keil5,Cube5.21post

2.Cube配置

選擇定時器3,打開通道1和通道2的PWM輸出,而後開啓主從模式,觸發方式爲上升沿觸發。url

頻率和佔空比的設置請看上篇博文。spa

 

生成的代碼 以下3d

   

void MX_TIM3_Init(void)
{
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 10;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 100-1;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 50;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_TIM_MspPostInit(&htim3);

}

 

 

 

 選擇定時器4,從模式爲門控模式,觸發時鐘爲TIM3,即ITR2,內部時鐘觸發code

 

生成的代碼以下:htm

/* TIM4 init function */
void MX_TIM4_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_SlaveConfigTypeDef sSlaveConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 0;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 0xffff;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_GATED;
  sSlaveConfig.InputTrigger = TIM_TS_ITR2;
  if (HAL_TIM_SlaveConfigSynchro(&htim4, &sSlaveConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }

}



 

 

 

STM32F429的定時器3通道1,2的PWM複用口blog

 

PA6 ------> TIM3_CH1
PA7 ------> TIM3_CH2 get

 3,程序介紹

 

(1)在主函數裏開啓定時器的中斷功能和PWM輸出

         TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING) ; // 捕獲比較1中斷使能 
         TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_2,TIM_ICPOLARITY_RISING) ; // 捕獲比較2中斷使能 
    
    
         
        __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,6400) ;                        // 輸入通道1的捕獲比較值CCR1 ,PWM個數爲6400個   
        __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,6400) ;                        // 輸入通道2的捕獲比較值CCR2    
         
          HAL_TIM_OC_Start_IT(&htim4,TIM_CHANNEL_1) ;                          //開啓定時器4通道1的輸入捕獲中斷
          HAL_TIM_OC_Start_IT(&htim4,TIM_CHANNEL_2) ;                          //開啓定時器4通道2的輸入捕獲中斷
         
          

         PostInit();                                                           //這個是爲了控制通道2的複用GPIO口PA7,可忽略
         
         HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_1);                           //開啓定時器3通道1的PWM輸出中斷         
         HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_2);                           //開啓定時器3通道2的PWM輸出中斷        

 

 

 

(2)在PWM中斷輪詢函數關閉定時器的中斷功能和PWM輸出

void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)                    //重寫PWM中斷輪詢弱函數
{ 

       if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET)                         //判斷是否生成中斷標誌位SR
         {
                if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) !=RESET)              //定時器中斷使能是否開啓
                {
                    
                     __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_CC1);                   //清除中斷標誌位SR
                    if(HAL_TIM_PWM_Stop_IT(&htim3, TIM_CHANNEL_1)==HAL_OK)         //關閉定時器3的通道1的PWM輸出
                    {
                      HAL_TIM_OC_Stop_IT(&htim4,TIM_CHANNEL_1) ;                   //關閉定時器4的通道1的輸入中斷捕獲
                      FLAG1_OK = 1;                                                //關閉標誌置1
                            
                    }
          
                } 
        }                                                                          //下面的通道2同理如此
         if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET)
         {
                if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) !=RESET)
                {
         
                    __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_CC2);                       //清除標誌位 
                    
                   PostDeInit();                                        //這個是爲了控制通道2的複用GPIO口PA7,可忽略
                   
                    if(HAL_TIM_PWM_Stop_IT(&htim3, TIM_CHANNEL_2)==HAL_OK)
                    {     
                        HAL_TIM_OC_Stop_IT(&htim4,TIM_CHANNEL_2) ;    
                              
                        FLAG2_OK = 1;            
                    }
           
                }                
            
         }

    
    if( FLAG1_OK == 1&&FLAG2_OK == 1)                                             
    {
        FLAG1_OK = 0;
        FLAG2_OK = 0;
        FLAG1_Static =2;
        
        __HAL_TIM_SET_COUNTER(&htim4,0);                                            //若是兩個通道都關閉好了,就把計數裝載值CNT清零
        
       TIM_CCxChannelCmd(TIM3,TIM_CHANNEL_2,TIM_CCx_ENABLE);                        //這個是爲了控制通道2的複用GPIO口PA7,可忽略
     
    //  
        //Delay100ms();
    }
    

}

 

重頭戲來了!!!若是你發現以上代碼,通道1,2的GPIO口只能輸出通道1的波形,說明你的中斷只是進了通道1的,但通道2也觸發了

緣由就是二者的中斷標誌位都被清零了,並且是HAL庫自動清零的。

兩個被註釋掉的函數就是HAL庫幫你清零的語句,你手動註釋掉就好了。

4.注意事項

   (1)當心使用延遲函數,定時器可能和延遲函數有衝突;

   (2)若是你發現你不能輸出超過255個波形,那就在初始化哪裏加個__HAL_TIM_SET_AUTORELOAD(&htim4, 0xffff) ,

            既往ARR裝載0xffff。

   (3)下圖的3個函數是用來調控PA7這個PWM複用口的,若是你發現你的PWM波形神奇的自動降低沿計數的話,就用來試下吧。

void PostDeInit(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
    
     __HAL_RCC_GPIOA_CLK_ENABLE();
    
        GPIO_InitStruct.Pin =GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
     // GPIO_InitStruct.Alternate = 0x00;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

void PostInit(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
    
     __HAL_RCC_GPIOA_CLK_ENABLE();
    
    
        GPIO_InitStruct.Pin =GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
      GPIO_InitStruct.Alternate = 0x02;
    
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

TIM_CCxChannelCmd(TIM3,TIM_CHANNEL_2,TIM_CCx_ENABLE);
相關文章
相關標籤/搜索