0

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.

7
  • If not using the command it works fine, as you say, then what is the question? Commented Jul 12, 2021 at 1:41
  • Regardless of what actually happens the logic is incorrect, immediately after stopping the motor you start it again; it will never stop. Commented Jul 12, 2021 at 17:37
  • You don't actually do anything with the variables duty or puls or make any attempt to set a duty cycle at all. Moreover you assign duty with an integer expression which in both cases will result in zero. In both cases the values could be a compile time constant. If the motor moves at all, it is not because this code is in any meaningful way controlling it. Commented Jul 12, 2021 at 17:47
  • What in any case is the meaning of the calculation of duty or the value of puls. A PWM signal is characterised by frequency and duty cycle, it is anybody's guess here what your intent is with respect to either. Commented Jul 12, 2021 at 18:10
  • You need to have at least called HAL_TIM_PWM_ConfigChannel() is you want to set the duty cycle. It is a shame you have chosen to to use the HAL interface, it suck and does very little for you. It is by no means a "PWM command", it is simply an abstracted interface to the PWM generation hardware - the abstraction is only enough to make all STM32 PWM capable timers look more-or-less alike - you are supposed to build an API on top of that. Commented Jul 12, 2021 at 18:16

1 Answer 1

1

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).

Sign up to request clarification or add additional context in comments.

2 Comments

I would go much more than 20kHz. It can be heard by people and it will be very annoying for animals
@0___________ : Perhaps; the motor has to resonate to be audible, the mechanics of it are such that it is typically hard to get much audible energy into it at 20kHz in most cases. YMMV. For low clock speeds you might not get sufficient PWM resolution if the frequency is too high. On a APB1 clock of 60MHz, the reload is 3000, so you could go to 60kHz and still maintain the (arbitrary) 1000 step resolution I have chosen. Too high and all the power may be lost through the capacitor across the motor to reduce electrical noise. It's usually a trade off of multiple factors.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.