STM32F103RCT6 –Timer TIM3 reads the encoder

1. Encoder

An encoder is a common input device used to detect the position and orientation of a rotating object. Encoders usually consist of two parts: a fixed encoder disk and an encoder probe that rests on a rotating shaft. When the rotary shaft rotates, the encoder probe will scan the encoder scale on the encoder disc and generate corresponding pulse output, so that the position and direction of the rotary shaft can be calculated
The TIM module of the STM32 chip provides three encoder modes: Quadrature encoder mode, **Reverse encoder mode** and Counter mode. Among them, the quadrature encoder mode is the most commonly used one, which can realize the counting of forward rotation and reverse rotation of the encoder. In the quadrature encoder mode, the two input capture channels of the TIM module respectively receive the two pulse signals of the encoder, and automatically compare the phase difference, so that the current rotation direction and distance movement of the encoder can be determined.

It should be noted that when using the encoder mode, the correct counting mode and direction need to be configured to ensure that the counter can correctly count the number of pulses during the rotation of the encoder. Additionally, Encoder mode can be combined with other features such as DMA transfers and interrupts to meet specific application needs.

2. The following is an example of using the encoder mode based on the STM32 HAL library, using TIM3, and details how to configure the TIM module to read the rotation direction and amount of the encoder.

#include "stm32f1xx_hal.h"

TIM_HandleTypeDef htim3;

void TIM3_Init(void)
{
  TIM_Encoder_InitTypeDef sConfig = {0};
\t
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 0;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 65535;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  
  sConfig.EncoderMode = TIM_ENCODERMODE_TI12;
  sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
  sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC1Filter = 0;
  sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC2Filter = 0;
\t
  if (HAL_TIM_Encoder_Init( & amp;htim3, & amp;sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

int main(void)
{
  HAL_Init();
  TIM3_Init();
\t
  // Enable TIM3 counter
  HAL_TIM_Encoder_Start( &htim3, TIM_CHANNEL_ALL);
  
  while(1)
  {
    // Read the value of the TIM3 counter
    int16_t count = (int16_t)(htim3.Instance->CNT);
    if (count > 0) {
      // Forward
    } else if (count < 0) {
      // reverse
    } else {
      // stop
    }
  }
}

In the code, first configure the counter mode and encoder mode of TIM3 through the TIM_Encoder_InitTypeDef structure of the HAL library, and enable the counter. Then, read the value of the TIM3 counter in the main loop, and judge the rotation direction of the encoder (forward or reverse) according to its change. It should be noted that the counter value of TIM3 is a 16-bit signed integer, which can represent the range between -32768 and + 32767, so problems such as overflow and data type conversion need to be considered when using it.

3. HAL_TIM_Encoder_Init() is a function in the STM32 HAL library, which is used to initialize the encoder mode parameters of the TIM module.

The function prototype is as follows:

HAL_StatusTypeDef HAL_TIM_Encoder_Init(TIM_HandleTypeDef *htim, TIM_Encoder_InitTypeDef *sConfig);

Among them, htim is a pointer to the TIM_HandleTypeDef structure, which is used to specify the TIM instance to be initialized and its related parameters; sConfig is a pointer to the TIM_Encoder_InitTypeDef structure, which is used to specify the parameters of the encoder mode, including the encoder mode and IC input signal Polarity, selection and frequency divider etc.

The return value of the function is HAL_StatusTypeDef type, indicating the status of the function execution. If the return value is HAL_OK, it means the initialization is successful. If the return value is any other value, it means that the initialization failed.

It should be noted that before using the HAL_TIM_Encoder_Init() function, you need to call the HAL_TIM_Base_Init() function to configure the TIM basic parameters, such as counting mode, clock frequency division, etc. In addition, after the initialization is complete, you need to call the HAL_TIM_Encoder_Start() function to start the encoder mode, and read the current value of the encoder counter through htim->Instance->CNT.

4. The HAL_TIM_Encoder_Init function is the encapsulation and control of the TIM module configuration and control of the STM32 by the HAL library. Its implementation is divided into two parts: initializing the TIM register and starting the encoder mode.

First, the function initializes the TIM-related registers using the register configuration function inside the HAL library through the parameters passed in. Specifically, the code sets the corresponding bit field of the TIM register to the value required for encoder mode. For example:

/* select encoder mode */
htim->Instance->SMCR & amp;= ~(TIM_SMCR_SMS);
htim->Instance->SMCR |= (uint32_t)sConfig->EncoderMode;
    
/* Configure IC input signal polarity and selection */
htim->Instance->CCER & amp;= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP);
htim->Instance->CCER & amp;= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP);
htim->Instance->CCMR1 & amp;= ~(TIM_CCMR1_CC1S | TIM_CCMR1_CC2S);
\t
htim->Instance->CCER |= (uint32_t)sConfig->IC1Polarity | sConfig->IC2Polarity;
htim->Instance->CCMR1 |= (uint32_t)sConfig->IC1Selection | sConfig->IC2Selection;

Then, the function calls the startup function inside the HAL library to make the TIM enter the encoder mode and start counting, and the counter is automatically cleared. For example:

if(HAL_IS_BIT_SET(htim->Instance->CR1, TIM_CR1_DIR))
{
  htim->State = HAL_TIM_STATE_READY;
  return HAL_ERROR;
}
else
{
  TIM_ENCODER_SET_STATE(htim, HAL_TIM_STATE_BUSY);
  /* Reset the Encoder Data */
  __HAL_TIM_SET_COUNTER(htim, 0x0000U);
  
  /* Enable the encoder interface channels */
  htim->Instance->CCER |= (TIM_CCER_CC1E | TIM_CCER_CC2E);
  /* Enable the Counter */
  __HAL_TIM_ENABLE(htim);
\t
  TIM_ENCODER_RESET_HANDLE_STATE(htim);
\t
  return HAL_OK;
}

The HAL library is a code library officially provided by STM32, and its source code is not public.
It should be noted that before starting the encoder mode, it is necessary to judge whether the direction of the TIM counter is correct, otherwise an error status will be returned. After starting the encoder mode, the function will automatically clear the encoder counter, and by setting the relevant registers, the TIM will start to receive counting pulses from the IC input signal, and automatically update the counter value according to the number of pulses.

5. Code examples for forward, reverse and stop encoders are as follows:

5.1 Forward rotation:

After using the HAL_TIM_Encoder_Start function to start the encoder mode, just use the HAL_GPIO_WritePin function to set the direction pin of the encoder to the corresponding level to achieve forward rotation. For example, if the direction pin of the encoder is PA6, and the forward direction of the encoder needs to set this pin to high level, the following code can be executed:

// Start the encoder counting mode
HAL_TIM_Encoder_Start( &htim3, TIM_CHANNEL_ALL);

// Set the direction pin of the encoder to high level to achieve forward rotation
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);

5.2 Inversion:

Similar to forward rotation, you only need to set the direction pin of the encoder to the opposite level to achieve reverse rotation. For example, if the direction pin of the encoder is PA6, and the reverse direction of the encoder needs to set this pin low, the following code can be executed:

// Start the encoder counting mode
HAL_TIM_Encoder_Start( &htim3, TIM_CHANNEL_ALL);

// Set the direction pin of the encoder to low level to achieve inversion
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);

5.3 Discontinued:

There are two ways to stop the encoder, one is to use the HAL_TIM_Encoder_Stop function to stop the encoder counting mode, and the other is to set the direction pin of the encoder to a high-impedance state to stop its signal output. Here is sample code for both methods:

(1) Use the HAL_TIM_Encoder_Stop function to stop the encoder counting mode:

// Stop encoder counting mode
HAL_TIM_Encoder_Stop( & htim3, TIM_CHANNEL_ALL);

(2) Set the direction pin of the encoder to a high-impedance state:

// Set the direction pin of the encoder to a high-impedance state and stop its signal output
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_MODE_ANALOG);

The above code is only for the direction pin of the encoder. If the encoder has other control pins, remember to operate them accordingly. At the same time, if you need to read the encoder count value accurately, it is recommended to call the HAL_TIM_Encoder_GetCounter function to obtain the current encoder count value before stopping the encoder.