Previous Tutorial | Tutorial 17 | Next Tutorial | |||||
STM32 Timer Encoder Mode – STM32 Rotary Encoder Interfacing | |||||||
STM32 Course Home Page ???? |
In this tutorial, we’ll discuss the STM32 Timer encoder mode. We’ll also do STM32 rotary encoder interfacing using the timer module in encoder mode. And we’ll use it to control the brightness of an LED in another LAB. This tutorial is going to be a quick one but fun to go through, so let’s get started!
[toc]
Required Components For LABs
All the example code/LABs/projects in the course are going to be done using those boards below.
- Nucleo32-L432KC (ARM Cortex-M4 @ 80MHz) or (eBay)
- Blue Pill STM32-F103 (ARM Cortex-M3 @ 72MHz) or (eBay)
- ST-Link v2 Debugger or (eBay)
QTY | Component Name | ???? Amazon.com | ???? eBay.com |
2 | BreadBoard | Amazon | eBay |
1 | LEDs Kit | Amazon Amazon | eBay |
1 | Resistors Kit | Amazon Amazon | eBay |
1 | Capacitors Kit | Amazon Amazon | eBay & eBay |
2 | Jumper Wires Pack | Amazon Amazon | eBay & eBay |
1 | 9v Battery or DC Power Supply | Amazon Amazon Amazon | eBay |
1 | Micro USB Cable | Amazon | eBay |
1 | Push Buttons | Amazon Amazon | eBay |
2 | Rotary Encoders | Amazon | eBay |
1 | USB-TTL Converter or FTDI Chip | Amazon Amazon | eBay eBay |
★ Check The Full Course Complete Kit List
Some Extremely Useful Test Equipment For Troubleshooting:
- My Digital Storage Oscilloscope (DSO): Siglent SDS1104 (on Amazon.com) (on eBay)
- FeelTech DDS Function Generator: KKMoon FY6900 (on Amazon.com) (on eBay)
- Logic Analyzer (on Amazon.com) (on eBay)
Affiliate Disclosure: When you click on links in this section and make a purchase, this can result in this site earning a commission. Affiliate programs and affiliations include, but are not limited to, the eBay Partner Network (EPN) and Amazon.com.
Rotary Encoder Interfacing
Encoders are electronic devices that are widely used in numerous applications. An encoder can be used as a sensor for motor speed and position sensing applications, for distances and length measurements, and more. And also an encoder can be used as an input device that the user can turn around with no limitations unlike the potentiometers. And you also (as a programmer) can detect how fast the user is turning the know, so your system can respond correspondingly.
You can see rotary encoders are being used in a variety of test equipment and consumer electronics. For example, the knobs in a typical DSO (like mine in the picture) are encoders and one of them can sense the speed of me turning it so that the cursor on the screen accelerates in response.
There exist different types of encoders like absolute and incremental types. An absolute Encoder maintains position information when power is removed from the encoder. The position of the encoder is available immediately on applying power. The relationship between the encoder value and the physical position of the controlled machinery is set at assembly. the system does not need to return to a calibration point to maintain position accuracy.
An incremental Encoder will immediately report changes in position, which is an essential capability in some applications. However, it does not report or keeps track of the absolute position. As a result, the mechanical system monitored by an incremental encoder may have to be moved to a fixed reference point to initialize absolute position measurements.
The rotary encoder which we’ll be using in this tutorial is an incremental encoder and it’s also called a Quadrature Encoder. Basically, it’s an incremental encoder with 2 out-of-phase output channels used in many automation applications wاere sensing the direction of movement is required. Each channel provides a specific number of equally spaced pulses per revolution (PPR) and the direction of motion is detected by the phase relationship of one channel leading or trailing the other channel.
When a higher resolution is needed, it is possible for the counter to count the leading and trailing edges of the quadrature encoder’s pulse train from one channel, which doubles (x2) the number of pulses per revolution. Counting both leading and trailing edges of both channels (A and B channels) of a quadrature encoder will quadruple (x4) the number of pulses per revolution.
STM32 Encoder Mode Preface
As we’ve discussed in an earlier tutorial, the timer modules can operate a variety of modes one of which is the Encoder mode. Where the timer gets clocked from external channels’ pins and the programmer (you) have the ability to select the counting edge polarity, Prescaler value, and the input filter cycles. The hardware of the STM32 timer in encoder mode provides a complete hardware solution for detecting signals and deciding the direction of counting up or down which significantly ease the process of firmware development for interfacing this kind of sensors.
STM32 Timers In Encoder Mode
The two inputs TI1 and TI2 are used to interface to an incremental encoder. The counter is clocked by each valid transition on TI1FP1 or TI2FP2 (TI1 and TI2 after input filter and polarity selection). The sequence of transitions of the two inputs is evaluated and generates count pulses as well as the direction signal.
Depending on the sequence the counter counts up or down, the DIR bit in the TIMx_CR1 register is modified by hardware accordingly. The DIR bit is calculated at each transition on any input (TI1 or TI2), whatever the counter is counting on TI1 only, TI2 only, or both TI1 and TI2.
Encoder interface mode acts simply as an external clock with direction selection. This means that the counter just counts continuously between 0 and the auto-reload value in the TIMx_ARR register.
In this mode, the counter is modified automatically following the speed and the direction of the incremental encoder, and its content, therefore, always represents the encoder’s position. The count direction corresponds to the rotation direction of the connected sensor. An external incremental encoder can be connected directly to the MCU without external interface logic.
STM32 Encoder Example LABs
LAB Number | 13 |
LAB Title | STM32 Timer Encoder Mode Basic LAB |
- Set up timer2 to operate in encoder mode with 2 input channels (combined)
- Set up a GPIO input pin to be connected to encoder’s SW switch button pin
- Set up UART1 module to operate in async mode @ 9600bps
- Read the timer2 counter register value and print the number via serial port as well as the button state
LAB Number | 14 |
LAB Title | STM32 Timer Encoder Mode – Rotary Encoder LED Dimmer |
- Set up timer2 to operate in encoder mode with 2 input channels (combined)
- Set up timer3 to operate in PWM mode with output channel1 (LED control signal)
- Read the timer2 counter value and map it to PWM duty cycle to control LED brightness
STM32 Rotary Encoder Example LAB13
In this LAB, our goal is to build a system that initialized timer2 in Encoder mode. Then read its counter value continuously and send it to the PC via serial port as well as the encoder’s push-button state. It’s going to be an easy LAB to set up and run. Just note that here I’m right-shifting the counter value by 2 in order to print 1 tick for each actual tick on the encoder, however, it’s not the content of the counter register which gets clocked by 4 clocks each tick. And you can instead set up the Prescaler by 4 or whatever.
And now, let’s build this system step-by-step
Step1: Open CubeMX & Create New Project
Step2: Choose The Target MCU & Double-Click Its Name
Step3: Configure Timer2 Peripheral To Operate In Encoder Mode With Combined Channels
Step4: Set The RCC External Clock Source
Step5: Go To The Clock Configuration
Step6: Set The System Clock To Be 72MHz
Step7: Name & Generate The Project Initialization Code For CubeIDE or The IDE You’re Using
Here is The Application Code For This LAB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#include "main.h" TIM_HandleTypeDef htim2; UART_HandleTypeDef huart1; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_TIM2_Init(void); static void MX_USART1_UART_Init(void); int main(void) { uint8_t MSG[50] = {'\0'}; HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM2_Init(); MX_USART1_UART_Init(); HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL); while (1) { if(HAL_GPIO_ReadPin (GPIOA, GPIO_PIN_2)) { sprintf(MSG, "Encoder Switch Released, Encoder Ticks = %d\n\r", ((TIM2->CNT)>>2)); HAL_UART_Transmit(&huart1, MSG, sizeof(MSG), 100); } else { sprintf(MSG, "Encoder Switch Pressed, Encoder Ticks = %d\n\r", ((TIM2->CNT)>>2)); HAL_UART_Transmit(&huart1, MSG, sizeof(MSG), 100); } HAL_Delay(100); } } |
Download The Basic Encoder LAB13 Project
The LAB Connections
The Result For LAB Testing (video)
STM32 Rotary Encoder Example Dimmer LAB14
In this LAB, our goal is to build a system that reads the encoder ticks and map it to the PWM duty cycle in order to control an LED’s brightness. Note that I’m multiplying the encoder ticks by 64 (equals left-shifting by 6) in order to achieve a faster duty cycle control as its range is from (0 up to 65535). And of course, you don’t want to make that number of ticks by turning the encoder’s knob nearly forever XD!
And now, let’s build this system step-by-step
Step1: Open CubeMX & Create New Project
Step2: Choose The Target MCU & Double-Click Its Name
Step3: Configure Timer2 Peripheral To Operate In Encoder Mode With Combined Channels
Step4: Configure Timer3 Peripheral To Operate In PWM Mode
Step5: Set The RCC External Clock Source
Step6: Go To The Clock Configuration
Step7: Set The System Clock To Be 72MHz
Step8: Name & Generate The Project Initialization Code For CubeIDE or The IDE You’re Using
Here is The Application Code For This LAB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include "main.h" TIM_HandleTypeDef htim2; TIM_HandleTypeDef htim3; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_TIM2_Init(void); static void MX_TIM3_Init(void); int main(void) { uint16_t LED_DutyCycle = 0; HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM2_Init(); MX_TIM3_Init(); HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL); HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); while (1) { if(TIM2->CNT < 1023) { LED_DutyCycle = ((TIM2->CNT)<<6); } TIM3->CCR1 = LED_DutyCycle; HAL_Delay(10); } } |
Download Rotary Encoder LED Dimmer LAB14 Project
The Result For LAB Testing (video)
Stay tuned for the upcoming tutorials and don’t forget to SHARE these tutorials. And consider SUPPORTING this work to keep publishing free content just like this!
Previous Tutorial | Tutorial 17 | Next Tutorial |