Unlocking STM32 Timer Potential: Mastering One-Pulse, PWM, and Input Capture Modes in Proteus

Things used in this project

Software apps and online services:

1- STMicroelectronics STM32CubeMX

2- STMicroelectronics STM32CubeIDE

3- Proteus 8

STM32 Timer Modes and Simulation with Proteus

This project is focused on exploring the different timer modes of the STM32 microcontroller and how to simulate them using Proteus software.The project explores three different timer modes: One-Pulse, PWM Output, and Input Capture.

Generating Single Pulses for Event Triggering:

In the One-Pulse mode generates a single pulse when the timer reaches a specific value, and it is used for generating events such as triggering a sensor or actuator.

Controlling Duty Cycle for LED Brightness or Motor Speed :

In the PWM Output mode generates a pulse-width modulated signal to control the duty cycle of an output signal, and it is used for controlling the brightness of an LED or the speed of a motor.

Measuring Period and Frequency of Input Signals :

Finally, in the Input Capture mode measures the period and frequency of an input signal and is used for detecting the frequency of an input signal or measuring the speed of a motor.

Through this project, we will learn how to configure the STM32 timer modes for different applications. Additionally, we will discover how to simulate our designs using Proteus software, enabling us to test our circuits before implementing them in hardware.

STM32CubeMX Configuration:

  • Open CubeMX & Create New Project Choose The Target MCU STM32F103C6 & Double-Click Its Name
  • Go To The Clock Configuration & Set The System Clock To 60MHz

Configuration for the TIMER One-Pulse Mode:

  • In the Categories tab, select the TIM3 then (enable Internal Clock & One Pulse Mode & PWM Generation Channel 3)
  • In the Parameter settings tab, set the (Prescaler = 6000 & Counter Peroid = 10) The purpose of this settings is to generate a periodic time event with a 1ms interval which represents the length of the pulse.

  • In the PWM Generaion Channel 3, set the (Mode = PWM mode 2 & Pulse 2=1)
  • In the NVIC setting tab, Enable TIM3 global interrupt

Configuration for the TIMER PWM Output Mode:

  • In the Categories tab, select the TIM2 then (enable Internal Clock & PWM Generation Channel 3 and 4)
  • In the Parameter settings tab, set the (Prescaler = 60 & Counter Peroid = 100)

Configuration for the TIMER Input Capture Mode:

  • In the Categories tab, select the TIM1 then (enable Internal Clock & Input Capture direct mode Channel 4)
  • In the Parameter settings tab, set the (Prescaler =60 & Counter Peroid= 65535)
  • In the Inpute Capture Channel 4 set Rising Edge
  • In the NVIC setting tab, Enable TIM1 capture compare interrupt
  • Generate The Initialization Code & Open The Project In CubeIDE
  • Write The Application Layer Code

STM32CubeIDE Configuration:

In file name :main.c

#include "main.h"

/* USER CODE BEGIN PFP */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim == &htim3)
  {
    pulseEND = 1 ;
  }

}
/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

#define TIMCLOCK   60000000
#define PRESCALAR  60
#define ERRUR  416 // ERRUR Simulation is not running in real time

uint32_t IC_Val1 = 0;
uint32_t IC_Val2 = 0;
uint32_t Difference = 0;
uint8_t MSG[50];

int Is_First_Captured = 0;
float frequency = 0;

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
   {
    if (Is_First_Captured==0) // if the first rising edge is not captured
      {
     IC_Val1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_4); // read the first value
     Is_First_Captured = 1;  // set the first captured as true
      }
   else   // If the first rising edge is captured, now we will capture the second edge
      {
       IC_Val2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_4);  // read second value
        if (IC_Val2 > IC_Val1)
        {
          Difference = IC_Val2-IC_Val1;
        }

        else if (IC_Val1 > IC_Val2)
        {
          Difference = (0xffffffff - IC_Val1) + IC_Val2;
        }

        float refClock = TIMCLOCK/(PRESCALAR);

        frequency = refClock/Difference;
        int x = frequency;
        x-=ERRUR;
        sprintf(MSG,"result = %d \n\r",x);
        HAL_UART_Transmit(&huart1,MSG, sizeof(MSG), 100);
          __HAL_TIM_SET_COUNTER(htim, 0);  // reset the counter
        Is_First_Captured = 0; // set it back to false
      }
    }
}
/* USER CODE END 0 */

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_USART1_UART_Init();

  while (1)
  {
    if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_13)==GPIO_PIN_SET)
    {
      HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3); //start the TIMER 3 in PWM MODE
      HAL_Delay(1000);                          //1 second delay
      TIM3->ARR = 1 ;                           // signal period of the PWM
      __HAL_TIM_ENABLE(&htim3);                 //ENable TIM3
      while(!pulseEND){};
      pulseEND=0;
    }
    else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14)==GPIO_PIN_SET)
    {
      HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); //start the TIMER 2 in PWM MODE
      uint32_t CH1;
      while (CH1 < 99 )
      {
        TIM2->CCR2 = CH1;
        CH1+= 1 ;
        HAL_Delay(1);
      }
      while (CH1 > 0 )
      {
       TIM2->CCR2 = CH1;
       CH1-= 1 ;
       HAL_Delay(1);
      }
   }
    else if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_15)==GPIO_PIN_SET)
    {
      TIM2->CCR3 = 50; //set the PWM duty cycle of TIMER2 to 50%
      HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //start the PWM signal on TIM2
      HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_4);//starts an interrupt input capture 
    }
    else
    {
      HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_2);
      HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_3);
      HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_2);
      HAL_TIM_IC_Stop_IT(&htim1, TIM_CHANNEL_4);
    }

  }
  /* USER CODE END 3 */
}

Proteus Configuration :

  • Open Proteus & Create New Project and click next

  • Click on Pick Device
  • Search for STM32F103C6 & SW-SPDT(switch) &LED_RED, ORANGE, YELLO
  • Click on Virtual Instruments Mode then choose (VIRTUAL TERMINAL & OSCILLOSCOPE)
  • Click on Terminal Mode then choose (DEFAULT & POWER &GROUND)
  • finally make the circuit below and start the simulation

That’s all!

If you have any questions or suggestions don’t hesitate to leave a comment below

Related posts

STM32-Driven LED Bar: Integration with 74HC595 Shift Register

How to Interface STM32 Microcontrollers with ADC128S102 via SPI

HC-SR04 Ultrasonic Sensor: Integrating with STM32 Microcontrollers Using TIMER