top of page

8-STM32 DC MOTOR CONTROL-PWM

Updated: May 22, 2024



Previous Tutorial

Tutorial 8

Next Tutorial



This project demonstrates how to control a DC motor using PWM (Pulse Width Modulation) with the STM32L476RG microcontroller. The motor driver L293D is used to interface the DC motor with the microcontroller. PWM signals are used to control the speed of the motor. This project provides an introduction to basic motor control applications and illustrates how to generate and utilize PWM signals.



L293D and STM32 PWM Method with HAL Functions

The L293D is a dual H-bridge motor driver IC that can control two DC motors or one bipolar stepper motor. PWM signals from the STM32L476RG microcontroller are applied to the input pins of the L293D to control the motor speed.


The HAL (Hardware Abstraction Layer) library for STM32 provides functions to generate PWM signals. This library offers a hardware-independent API, making it easy to generate PWM signals using the microcontroller's hardware resources.


Understanding HAL PWM Duty Cycle Functions

Pulse Width Modulation (PWM) is a technique used to control the amount of power delivered to a device by switching it on and off at a high frequency. The proportion of time the signal is on compared to the total period of the signal is called the duty cycle. In STM32 microcontrollers, the HAL (Hardware Abstraction Layer) library provides functions to configure and control PWM signals.


Here’s an explanation of the key HAL functions used to manage the PWM duty cycle:

HAL_TIM_PWM_Init
HAL_TIM_PWM_ConfigChannel
HAL_TIM_PWM_Start
__HAL_TIM_SET_COMPARE

1. HAL_TIM_PWM_Init

This function initializes the TIM (timer) peripheral for PWM generation.

HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim);
  • htim: A pointer to the TIM handle structure.

  • This function configures the timer for PWM mode but does not start the PWM signal.


2. HAL_TIM_PWM_ConfigChannel

This function configures the PWM channel of the timer.

HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim, TIM_OC_InitTypeDef *sConfig, uint32_t Channel);
  • htim: A pointer to the TIM handle structure.

  • sConfig: A pointer to the TIM_OC_InitTypeDef structure that contains the configuration information for the PWM channel.

  • Channel: Specifies the TIM channel to be configured (e.g., TIM_CHANNEL_1).


3. HAL_TIM_PWM_Start

This function starts the PWM signal generation.

HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
  • %htim: A pointer to the TIM handle structure.

  • Channel: Specifies the TIM channel to start (e.g., TIM_CHANNEL_1).


4. __HAL_TIM_SET_COMPARE

This macro sets the compare value for the PWM duty cycle. The compare value determines the duty cycle of the PWM signal.

__HAL_TIM_SET_COMPARE(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t Compare);
  • htim: A pointer to the TIM handle structure.

  • Channel: Specifies the TIM channel to set the compare value (e.g., TIM_CHANNEL_1).

  • Compare: Specifies the compare value. This value determines the duty cycle.


The HAL library functions make it straightforward to initialize and configure PWM signals for controlling devices like motors. By setting the appropriate compare value, you can control the duty cycle of the PWM signal, which in turn controls the speed of the motor. The example provided demonstrates the basic setup and usage of these functions.


Required Parts For Example:

  1. STM32L476RG Nucleo Board

  2. L293D Motor Driver IC

  3. DC Motor

  4. Power Supply (suitable voltage for the motor)

  5. Jumper Wires

  6. Breadboard


CUBEIDE Configuration Steps:

  1. Create a Project:

  • Open STM32CubeIDE and create a new project for STM32L476RG.

  1. Pin Configuration:

  • Select a timer and corresponding GPIO pins for PWM output (e.g., TIM2_CH1, PA0).

  1. Timer Settings:

  • Configure the timer in PWM mode.

  • Set the frequency and duty cycle.

  1. GPIO Settings:

  • Ensure the pin used for PWM output is set to alternate function mode.

  1. Generate and Compile Code:

  • Use the code generation wizard to create necessary HAL functions and compile the project.

Success is walking from failure to failure with no loss of enthusiasm."- Winston Churchill

CODE:


#include "main.h"

TIM_HandleTypeDef htim2;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_TIM2_Init();

    // Start the PWM signal
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);

    // Initially set duty cycle to 50%
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, htim2.Init.Period / 2);

    while (1) {
        // Adjust the duty cycle to control motor speed
        for (int i = 0; i < htim2.Init.Period; i++) {
            __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, i);
            HAL_Delay(10);
        }
    }
}

void SystemClock_Config(void) {
    // System clock configuration
}

static void MX_GPIO_Init(void) {
    // GPIO configuration
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

static void MX_TIM2_Init(void) {
    // TIM2 configuration
    __HAL_RCC_TIM2_CLK_ENABLE();
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 79;
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 999;
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) {
        Error_Handler();
    }

    TIM_OC_InitTypeDef sConfigOC = {0};
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 0;
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) {
        Error_Handler();
    }
}

void Error_Handler(void) {
    // Error handling
    while (1) {}
}


Result


In this example, the speed of a DC motor is controlled using PWM signals generated by the STM32L476RG microcontroller. The L293D motor driver IC is used to control the motor's direction and speed. This project demonstrates basic techniques for generating PWM signals and controlling motor speed. By following these steps, you can control the speed and direction of a DC motor, learn how to generate and use PWM signals, and gain a solid foundation for more complex motor control systems and robotic projects.


DC MOTOR CONTROL WITH LIBRARY

Step 1: Project Setup

First, use STM32CubeMX to configure the basic setup:

  1. Configure GPIO and PWM Pins:

  • Select two GPIO pins for motor direction control.

  • Select one PWM pin for motor speed control.

  • Configure a timer (TIM) for PWM output.

Step 2: Create Library Files

Create two main files: dc_motor.h and dc_motor.c.

dc_motor.h

#ifndef DC_MOTOR_H
#define DC_MOTOR_H

#include "stm32l4xx_hal.h"

// Enumeration for motor direction
typedef enum {
    MOTOR_STOP,
    MOTOR_FORWARD,
    MOTOR_BACKWARD
} MotorDirection;

// Motor control structure
typedef struct {
    TIM_HandleTypeDef* htim; // PWM Timer handle
    uint32_t pwm_channel; // PWM channel number
    GPIO_TypeDef* dir_port; // GPIO port for direction control
    uint16_t dir_pin1; // GPIO pin for direction control 1
    uint16_t dir_pin2; // GPIO pin for direction control 2
} DC_Motor_HandleTypeDef;

// Function prototypes for motor library
void DC_Motor_Init(DC_Motor_HandleTypeDef* motor);
void DC_Motor_SetDirection(DC_Motor_HandleTypeDef* motor, MotorDirection direction);
void DC_Motor_SetSpeed(DC_Motor_HandleTypeDef* motor, uint8_t speed);

#endif // DC_MOTOR_H

dc_motor.c

#include "dc_motor.h"

void DC_Motor_Init(DC_Motor_HandleTypeDef* motor) {
    // Start PWM
    HAL_TIM_PWM_Start(motor->htim, motor->pwm_channel);
}

void DC_Motor_SetDirection(DC_Motor_HandleTypeDef* motor, MotorDirection direction) {
    switch (direction) {
        case MOTOR_FORWARD:
            HAL_GPIO_WritePin(motor->dir_port, motor->dir_pin1, GPIO_PIN_SET);
            HAL_GPIO_WritePin(motor->dir_port, motor->dir_pin2, GPIO_PIN_RESET);
            break;
        case MOTOR_BACKWARD:
            HAL_GPIO_WritePin(motor->dir_port, motor->dir_pin1, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(motor->dir_port, motor->dir_pin2, GPIO_PIN_SET);
            break;
        case MOTOR_STOP:
        default:
            HAL_GPIO_WritePin(motor->dir_port, motor->dir_pin1, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(motor->dir_port, motor->dir_pin2, GPIO_PIN_RESET);
            break;
    }
}

void DC_Motor_SetSpeed(DC_Motor_HandleTypeDef* motor, uint8_t speed) {
    // Speed is expected to be in the range 0-100
    // Calculate pulse length based on timer's period
    uint32_t pulse_length = (motor->htim->Init.Period * speed) / 100;
    __HAL_TIM_SET_COMPARE(motor->htim, motor->pwm_channel, pulse_length);
}

Step 3: Use the Motor Library in Main Code

To use this library to control the motor, follow these steps in your main code file:

  1. Include necessary header files and define the motor structure in main.c:

#include "main.h"
#include "dc_motor.h"

DC_Motor_HandleTypeDef motor;
  1. Initialize and control the motor in main.c:

int main(void) {
    // HAL and GPIO initialization code
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_TIM2_Init(); // Initialize PWM timer

    // Motor configuration
    motor.htim = &htim2; // PWM timer handle
    motor.pwm_channel = TIM_CHANNEL_1; // PWM channel
    motor.dir_port = GPIOB; // GPIO port for direction pins
    motor.dir_pin1 = GPIO_PIN_0; // Direction pin 1
    motor.dir_pin2 = GPIO_PIN_1; // Direction pin 2

    // Initialize motor
    DC_Motor_Init(&motor);

    while (1) {
        // Set motor to move forward and set speed
        DC_Motor_SetDirection(&motor, MOTOR_FORWARD);
        DC_Motor_SetSpeed(&motor, 50); // 50% speed

        HAL_Delay(2000); // Wait for 2 seconds

        // Set motor to move backward and set speed
        DC_Motor_SetDirection(&motor, MOTOR_BACKWARD);
        DC_Motor_SetSpeed(&motor, 50); // 50% speed

        HAL_Delay(2000); // Wait for 2 seconds

        // Stop the motor
        DC_Motor_SetDirection(&motor, MOTOR_STOP);
        DC_Motor_SetSpeed(&motor, 0); // Set speed to 0

        HAL_Delay(2000); // Wait for 2 seconds
    }
}

Now it's your turn.
DC MOTOR speed control with Potantiometer.



Previous Tutorial

Tutorial 8

Next Tutorial





 
 
 

Recent Posts

See All

Comments


bottom of page