cembeddedmicrocontrollerstm32f4pwm

stm32 PWM command


I am a beginner in stm32 and new in this community I am trying this following program :

-run a DC motor (using PWM command) with speed "1" and wait 5 seconds then run with speed "2" and wait for 5 seconds then the motor stops .

The problem is that the motor stays in a loop : starts turning about 1 second and stops .

    #include "main.h"
    TIM_HandleTypeDef htim3;
    int puls ;
    float duty ;
    UART_HandleTypeDef huart2;
    void SystemClock_Config(void);
    static void MX_GPIO_Init(void);
    static void MX_USART2_UART_Init(void);
    static void MX_TIM3_Init(void);
    
    int main(void)
    {
      HAL_Init();
      SystemClock_Config();
      MX_GPIO_Init();
      MX_USART2_UART_Init();
      MX_TIM3_Init();
      /* USER CODE BEGIN 2 */
    HAL_TIM_Base_Start(&htim3);
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
      while (1)
      {puls=150 ; // motor with speed 1
       duty =(puls*100)/31999; 
            MX_TIM3_Init();
            HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
            HAL_Delay(5000);
    
      puls=300 ; //motor with  speed  2
        duty =(puls*100)/31999;
        MX_TIM3_Init();
        HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
        HAL_Delay(5000);
        HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_2);

    
      }
    
    }
static void MX_TIM3_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 31999;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 65535;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = puls;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  
  HAL_TIM_MspPostInit(&htim3);

}

I am using stm32f4.

motor pin C7 .

I've configured my project with STM32CubeIDE .

Thanks for your help.


Solution

  • Separate your initialisation from the duty cycle setting. Change:

    sConfigOC.Pulse = puls ;
    

    to

    sConfigOC.Pulse = 0 ;
    

    Then add a function to set the duty cycle, for example:

    int setDutyCycle( unsigned duty_cycle_pecent_X10 )
    {
        TIM_OC_InitTypeDef sConfigOC;
    
        sConfigOC.OCMode = TIM_OCMODE_PWM1;
        sConfigOC.Pulse = ((htim3.Init.Period + 1) * duty_cycle_pecent_X10) / 1000 ;
        sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
        sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    
        if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
        {
            Error_Handler();
        }
    }
    

    The global variable puls is no longer needed. In fact no global variables are needed or ever a good idea; the fact that the CubeMX generates code dependent on globals (such as htim3 in this case) is depressing, but that is a different issue - there is no need to exacerbate the problem with your own.

    The state of the output on HAL_TIM_PWM_Stop() is undefined, and coluld leave the motor on full speed. That does not happen in your code because after stopping the loop iterates and immediately starts it again. The correct way to stop running the motor is to set the duty cycle to zero.

    Then your main() can then be simplified:

    int main (void)
    {
        HAL_Init ();
        SystemClock_Config ();
        MX_GPIO_Init ();
        MX_USART2_UART_Init ();
        MX_TIM3_Init ();
        
        while (1)
        {
            // Duty cycle 20% for 5 seconds
            speed_percent_x10 = 200u ;           
            setDutyCycle( speed_percent_x10 ) ;
            HAL_Delay (5000u);
            
            // Duty cycle 50% for 5 seconds
            speed_percent_x10 = 500u ;           
            setDutyCycle( speed_percent_x10 ) ;
            HAL_Delay (5000u);
            
            // Duty cycle 0% (stop) for 5 seconds
            speed_percent_x10 = 0u ;             
            setDutyCycle( speed_percent_x10 ) ;
            HAL_Delay (5000u);
        }
        
        return 0 ;
    }
    

    That may not solve all the problems with the code; I am not able to test it, but I seriously doubt that your PWM frequency is high enough to correctly and stably drive the motor.

    The CubeMX code is particularly poor in this respect, and I would suggest modifying MX_TIM3_Init() as follows:

    htim3.Init.Prescaler = 0 ;  // run at SystemCoreClock / 2 (APB1 bus clock)
    htim3.Init.Period = SystemCoreClock / (2 * PWM_FREQ) ;
    

    Where PWM_FREQ is something sensible like:

    #define PWM_FREQ 20000u
    

    If you have precise motor data you can in theory calculate an optimal frequency, but it is usually sufficient to ensure it is not audible. Certainly not the sub-10Hz that your settings appear to use (depending on SystemCoreClock).