Library 26- Rotary encoder on STM32F4
A rotary encoder, also called a shaft encoder is an electro-mechanical device than converts the angular position or motion of a shaft to an analog or digital. There are 2 types of rotary encoders:
- Incremental – output indicates just rotation clockwise or counterclockwise
- Absolute – output indicates current position for encoder
For that purpose I made a one simple library. This library works for incremental rotary encoders. It uses an interrupt to handle rotations. On the rotary encoders inside are basically 2 pushbuttons. And because they are mehanical, you can also expect some debouncing. STM32F4 is a fast device and will handle this debouncing what you don’t want. For that you have to make a good filtering. I made a schematic. how to properly connect rotary encoder to STM32F4 to disable debouncing effect.
Library
Features
- Operate with up to 16 rotary encoders at a time.
- External interrupt based detection, not TIM’s input.
- Version 2.0 – March 22, 2015
- Library rewritten to support up to 16 rotary encoders
- It is not compatible with older versions
Dependencies
- CMSIS
- STM32F4xx
- STM32F4xx RCC
- STM32F4xx GPIO
- STM32F4xx EXTI
- STM32F4xx SYSCFG
- MISC
- TM
- defines.h
- TM EXTI
- TM GPIO
- defines.h
Rotary encoder has 3 pins. pins A, B and C (common). My library uses only A pin to be connected to interrupt, B can be whatever else.
You set your pins when you initialize your custom rotary encoder. And, if you need, you can use up to 16 rotary encoders. This number depends on EXTI feature. It supports 16 interrupt lines at a time, because rotary encoder uses one pin (typically pin A) for interrupt source.
Enumerations
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 |
/** * @brief Rotary encoder rotation status */ typedef enum { TM_RE_Rotate_Increment, /*!< Encoder was incremented */ TM_RE_Rotate_Decrement, /*!< Encoder was decremented */ TM_RE_Rotate_Nothing /*!< Encoder stop at it was before */ } TM_RE_Rotate_t; /** * @brief Rotary encoder mode selection for rotation */ typedef enum { TM_RE_Mode_Zero, /*!< Rotary encoder mode zero. It is used for direction when it will be increment od decrement, default used */ TM_RE_Mode_One /*!< Rotary encoder mode one. It is used for direction when it will be increment od decrement */ } TM_RE_Mode_t; /** * @brief Rotary main working structure */ typedef struct { int32_t Absolute; /*!< Absolute rotation from beginning, for public use */ int32_t Diff; /*!< Rotary difference from last check, for public use */ TM_RE_Rotate_t Rotation; /*!< Increment, Decrement or nothing, for public use */ TM_RE_Mode_t Mode; /*!< Rotary encoder mode selected */ uint8_t LastA; /*!< Last status of A pin when checking. Meant for private use */ int32_t RE_Count; /*!< Temporary variable to store data between rotation and user check */ GPIO_TypeDef* GPIO_A; /*!< Pointer to GPIOx for Rotary encode A pin. Meant for private use */ GPIO_TypeDef* GPIO_B; /*!< Pointer to GPIOx for Rotary encode B pin. Meant for private use */ uint16_t GPIO_PIN_A; /*!< GPIO pin for rotary encoder A pin. This pin is also set for interrupt */ uint16_t GPIO_PIN_B; /*!< GPIO pin for rotary encoder B pin. */ } TM_RE_t; |
Functions
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 |
/** * @brief Prepare Rotary Encoder to work * @param *data: Pointer to @ref TM_RE_t structure * @retval None */ void TM_RE_Init(TM_RE_t* data, GPIO_TypeDef* GPIO_A_Port, uint16_t GPIO_A_Pin, GPIO_TypeDef* GPIO_B_Port, uint16_t GPIO_B_Pin); /** * @brief Set rotary encoder custom mode * @param *data: Pointer to @ref TM_RE_t structure for specific rotary encoder input * @param mode: Rotary mode you will use. This parameter can be a value of @ref TM_RE_Mode_t enumeration * @retval None */ void TM_RE_SetMode(TM_RE_t* data, TM_RE_Mode_t mode); /** * @brief Checks and gets new values of rotary encoder * @param *data: Pointer to @ref TM_RE_t structure * @retval Member of @ref TM_RE_Rotate_t */ TM_RE_Rotate_t TM_RE_Get(TM_RE_t* data); /** * @brief Process function. * @note This function have to be called inside your interrupt handler. * @param *data: Pointer to rotary encoder @ret TM_RE_t data where interrupt occured * @retval None */ void TM_RE_Process(TM_RE_t* data); |
Example
This example uses default settings, PD0 and PD1 are in use.
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
/** * Keil project for rotary encoder * * Before you start, select your target, on the right of the "Load" button * * @author Tilen Majerle * @email tilen@majerle.eu * @website http://stm32f4-discovery.net * @ide Keil uVision 5 * @packs STM32F4xx Keil packs version 2.2.0 or greater required * @stdperiph STM32F4xx Standard peripheral drivers version 1.4.0 or greater required */ /* Include core modules */ #include "stm32f4xx.h" /* Include my libraries here */ #include "defines.h" #include "tm_stm32f4_ili9341.h" #include "tm_stm32f4_rotary_encoder.h" #include <stdio.h> /* Rotary encoder data */ TM_RE_t RE1_Data; TM_RE_t RE2_Data; int main(void) { char buf[15]; /* Initialize system */ SystemInit(); /* Initialize LCD */ TM_ILI9341_Init(); /* Rotate LCD */ TM_ILI9341_Rotate(TM_ILI9341_Orientation_Portrait_2); /* Initialize Rotary encoder 1, pin A = PD0, pin B = PD1 */ TM_RE_Init(&RE1_Data, GPIOD, GPIO_PIN_0, GPIOD, GPIO_PIN_1); /* Initialize Rotary encoder 2, pin A = PD3, pin B = PD5 */ TM_RE_Init(&RE2_Data, GPIOD, GPIO_PIN_3, GPIOD, GPIO_PIN_5); /* Set rotation mode for rotary 1 */ TM_RE_SetMode(&RE1_Data, TM_RE_Mode_One); while (1) { /* Get new rotation */ TM_RE_Get(&RE1_Data); /* Format & display on LCD */ sprintf(buf, "Absolute:\n%8d\n\n\nDifference from\nlast check:\n%8d", RE1_Data.Absolute, RE1_Data.Diff); /* Show on LCD */ TM_ILI9341_Puts(10, 10, buf, &TM_Font_11x18, 0x0000, 0xFFFF); /* Get new rotation */ TM_RE_Get(&RE2_Data); /* Format % display on LCD */ sprintf(buf, "Absolute:\n%8d\n\n\nDifference from\nlast check:\n%8d", RE2_Data.Absolute, RE2_Data.Diff); /* Show on LCD */ TM_ILI9341_Puts(10, 160, buf, &TM_Font_11x18, 0x0000, 0xFFFF); } } /* TM EXTI Handler for all EXTI lines */ void TM_EXTI_Handler(uint16_t GPIO_Pin) { /* Check RE pin 1 */ if (GPIO_Pin == RE1_Data.GPIO_PIN_A) { /* Process data */ TM_RE_Process(&RE1_Data); } if (GPIO_Pin == RE2_Data.GPIO_PIN_A) { /* Process data */ TM_RE_Process(&RE2_Data); } } |
View project on Github, download library below.
Recent comments