EC11 Rotary Encoder
A rotary encoder is a rotary sensor that converts rotational displacement into a series of digital pulse signals. These pulses are used to control angular displacement. The reading system usually adopts a differential method, which compares two signals with the same waveform but a phase difference of 180°, in order to improve the quality and stability of the output signal. The reading is formed based on the difference between the two signals, thereby eliminating interference.
Module Source
Purchase link: https://item.taobao.com/item.htm?spm=a1z10.3-c-s.w4002-24706531953.10.211a6a4bFbOotE&id=522555699841 Materials download link: https://pan.baidu.com/s/18pp1KaT2V_llizWvdIXtKA?pwd=8889 Materials extraction code: 8889
Specifications
Operating voltage: 5V Operating current: 1MA Module size: 18 x 25 mm Rotation angle: 360 degrees Communication protocol: Phase difference Number of pins: 5 Pin (2.54mm pitch header) For the information on the left, please refer to the manufacturer's document 2.2-1 Product Specification.
Principle Analysis
The rotary encoder determines the rotation direction through the phase difference of two pins (the CLK pin is hereafter referred to as phase A, and the DT pin as phase B). When rotating clockwise, phase A leads phase B by 90 degrees, that is, when phase A is on a falling edge, phase B is at a low level; when phase A is on a rising edge, phase B is at a high level. When rotating counterclockwise, phase B leads phase A by 90 degrees, that is, when phase A is on a falling edge, phase B is at a high level; when phase A is on a rising edge, phase B is at a low level.
The output behavior of the EC11 rotation can be divided into two types. One type is that rotating two notches outputs a complete pulse on terminals A and B (rotating one notch only changes from low level -> high level or from high level -> low level); The other type is that rotating one notch outputs a complete pulse on terminals A and B relative to terminal C.
Therefore, we only need to detect when a high/low level transition occurs on phase A or phase B, and then check the state of the other phase to determine the rotation direction. According to the following truth table, we can find:
- When both phases are rising edges or both are falling edges simultaneously, it is clockwise;
- When both phases are not rising edges or not falling edges simultaneously, it is counterclockwise;
The rotary encoder has a mechanical structure, and mechanical structures inevitably have bouncing during rotation or pressing. Here, a timer is used to scan the encoder every 10ms to check whether there is any action, achieving debouncing within 10ms.
Porting Process
Pin Selection
This module has 5 pins. For specific pin connections, see Table 2.4.1-1 Pin Connections.
Port to Project
Our goal is to port the example to the ESP32-S3 dev board. Complete driver code has been provided for you. Follow the steps below to complete the porting. For detailed instructions on creating folders and new .c and .h files, refer to section 1.4.2 in the [DHT11 Temperature and Humidity Sensor] chapter; we will not repeat it here. Just note that here we change the file name bsp_dht11 to bsp_ec11, and the folder name to EC11.
Write Code
In the bsp_ec11.c file, write:
/*
* LCSC-Openkits (LCKFB) software and hardware materials and related expansion board software and hardware materials are all open source on the official website.
* Dev board official website: www.lckfb.com
* Technical support resides on the forum; any technical questions are welcome for exchange and learning at any time.
* LCKFB Forum: club.szlcsc.com
* Follow our Bilibili account: [LCSC-Openkits (LCKFB)] to keep up with our latest updates!
* We do not make money by selling boards; we take cultivating engineers as our mission.
* Change Logs:
* Date Author Notes
* 2023-11-02 LCKFB-yzh first version
*/
#include "bsp_ec11.h"
#include "stdio.h"
#include "stdlib.h"
#include "rom/ets_sys.h"
void delay_ms(unsigned int ms)
{
vTaskDelay(ms / portTICK_PERIOD_MS);
}
void delay_us(unsigned int us)
{
ets_delay_us(us);
}
/******************************************************************
* Function Name: Encoder_GPIO_Init
* Function Description: Rotary encoder pin initialization
* Function Parameters: None
* Function Return: None
* Author: LC
* Notes:
******************************************************************/
void Encoder_GPIO_Init(void)
{
gpio_config_t ec11_config = {
.pin_bit_mask = (1ULL<<EC11_PIN_SW)|(1ULL<<EC11_PIN_CLK)|(1ULL<<EC11_PIN_DT), //Configure pins
.mode =GPIO_MODE_INPUT, //Input mode
.pull_up_en = GPIO_PULLUP_ENABLE, //Enable pull-up
.pull_down_en = GPIO_PULLDOWN_DISABLE, //Disable pull-down
.intr_type = GPIO_INTR_DISABLE //Disable pin interrupt
};
gpio_config(&ec11_config);
}
/******************************************************************
* Function Name: Encoder_Scanf
* Function Description: Determine whether the rotary encoder has rotated in which direction
* Function Parameters: None
* Function Return: 1=forward rotation 2=reverse rotation
* Author: LC
* Notes: Which side is forward and which is reverse doesn't matter much, it's up to you
******************************************************************/
char Encoder_Scanf(void)
{
static unsigned char EC11_CLK_Last = 0; //Last state of EC11 LCK pin (Phase A)
static unsigned char EC11_DT_Last = 0; //Last state of EC11 DT pin (Phase B)
char ScanResult = 0;
//When A transitions, sample the current state of B and compare it with the last state of B.
if(GET_CLK_STATE !=EC11_CLK_Last)
{ //If A 0->1, B 1->0 forward; if A 1->0, B 0->1 forward;
//If A 0->1, B 0->1 reverse; if A 1->0, B 1->0 reverse
if(GET_CLK_STATE == 1) //Compared with the last state, EC11_A is rising edge
{
//Compared with the last state, EC11_B is falling edge
if((EC11_DT_Last == 1)&&(GET_DT_STATE == 0))
ScanResult = 1; //Forward
//Compared with the last state, EC11_B is rising edge
if((EC11_DT_Last == 0)&&(GET_DT_STATE == 1))
ScanResult = 2; //Reverse
//>>>>>>>>>>>>>>>>Below is the processing for forward once then reverse or reverse once then forward<<<<<<<<<<<<<<<<//
//When A is rising edge, the sampled B is unchanged and is 0
if((EC11_DT_Last == GET_DT_STATE)&&(GET_DT_STATE == 0))
ScanResult = 1; //Forward
//When A is rising edge, the sampled B is unchanged and is 1
if((EC11_DT_Last == GET_DT_STATE)&&(GET_DT_STATE == 1))
ScanResult = 2; //Reverse
}
else //Compared with the last state, EC11_A is falling edge
{
//Compared with the last state, EC11_B is falling edge
if((EC11_DT_Last == 1)&&(GET_DT_STATE == 0))
ScanResult = 2; //Reverse
//Compared with the last state, EC11_B is rising edge
if((EC11_DT_Last == 0)&&(GET_DT_STATE == 1))
ScanResult = 1; //Forward
//>>>>>>>>>>>>>>>>Below is the processing for forward once then reverse or reverse once then forward<<<<<<<<<<<<<<<<//
//When A is rising edge, the sampled B is unchanged and is 0
if((EC11_DT_Last == GET_DT_STATE)&&(GET_DT_STATE == 0))
ScanResult = 2; //Reverse
//When A is rising edge, the sampled B is unchanged and is 1
if((EC11_DT_Last == GET_DT_STATE)&&(GET_DT_STATE == 1))
ScanResult = 1; //Forward
}
EC11_CLK_Last = GET_CLK_STATE; //Update the encoder previous state temporary variable
EC11_DT_Last = GET_DT_STATE; //Update the encoder previous state temporary variable
return ScanResult; //Return value: 0: no action; 1: forward; 2: reverse;
}
return 0;
}
/******************************************************************
* Function Name: Encoder_Sw_Down
* Function Description: Determine whether the encoder is pressed
* Function Parameters: None
* Function Return: 0=not pressed 1=pressed
* Author: LC
* Notes: Please pay attention to debouncing
******************************************************************/
unsigned char Encoder_Sw_Down(void)
{
//Not pressed
if( gpio_get_level(EC11_PIN_SW) == 1 )
{
delay_ms(100);//Debounce
return 0;
}
else//Pressed
{
delay_ms(100);//Debounce
// printf("down\r\n");
return 1;
}
}
/******************************************************************
* Function Name: Encoder_Rotation_left
* Function Description: Left rotation service function. Operations to be executed when the encoder rotates left
* Function Parameters: None
* Function Return: Number of left rotations
* Author: LC
* Notes: None
******************************************************************/
int Encoder_Rotation_left(void)
{
static int left_num = 0;//Number of left turns
left_num++;
/* Your code is written here */
printf("left num = %d\r\n",left_num);
/* Your code is written here */
return left_num;
}
/******************************************************************
* Function Name: Encoder_Rotation_left
* Function Description: Right rotation service function. Operations to be executed when the encoder rotates right
* Function Parameters: None
* Function Return: Number of right rotations
* Author: LC
* Notes: None
******************************************************************/
int Encoder_Rotation_right(void)
{
static int right_num = 0;//Number of right turns
right_num++;
/* Your code is written here */
printf("right num = %d\r\n",right_num);
/* Your code is written here */
return right_num;
}
/************************************************
Function Name : BSP_TIMER_IRQHandler
Function : None
Parameters : None
Return Value : None
Author : LC
*************************************************/
void BSP_TIMER_IRQHANDLER(void)
{
static char dat = 0;
dat = Encoder_Scanf();//Scan whether the encoder is twisted
if( dat != 0 )//If there is rotation
{
if( dat == 2 )
{
Encoder_Rotation_left();
}
else
{
Encoder_Rotation_right();
}
}
}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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
In the bsp_ec11.h file, write:
#ifndef _BSP_ENCODER_H_
#define _BSP_ENCODER_H_
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_rom_sys.h"
#include "esp_timer.h"
#include "driver/uart.h"
#include "rom/ets_sys.h"
#include "esp_system.h"
#include "driver/gptimer.h"
#include "esp_log.h"
#include "freertos/queue.h"
#include "driver/spi_master.h"
#include "nvs_flash.h"
//SW pin
#define EC11_PIN_SW 1
//CLK pin
#define EC11_PIN_CLK 3
//DT pin
#define EC11_PIN_DT 2
//Get the status of the CLK pin
#define GET_CLK_STATE gpio_get_level(EC11_PIN_CLK)
//Get the status of the DT pin
#define GET_DT_STATE gpio_get_level(EC11_PIN_DT)
void delay_us(unsigned int us);
void delay_ms(unsigned int ms);
void Encoder_GPIO_Init(void);//Rotary encoder initialization
unsigned char Encoder_Sw_Down(void);//Whether the encoder is pressed
int Encoder_Rotation_left(void);//Left rotation service function
int Encoder_Rotation_right(void);//Right rotation service function
void BSP_TIMER_IRQHANDLER(void);
#endif2
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
The porting is now complete. Please proceed to section 2.5 for porting verification.
Porting Verification
Enter the following code in main.c:
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_timer.h"
#include "freertos/FreeRTOSConfig.h"
#include "esp_task_wdt.h"
#include "bsp_ec11.h"
void app_main(void)
{
Encoder_GPIO_Init(); // Initialization
while(1)
{
BSP_TIMER_IRQHANDLER();
if( Encoder_Sw_Down() == 1 )//Rotary encoder is pressed
{
printf("Encoder down\r\n");
delay_ms(100);
}
delay_ms(10);
}
}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
Power-on effect:
Driver code (polling):
File Download
📌 Materials Download Center (Click to Jump)
📌 In the Materials Download Center -> Module Porting Materials Download, inside the compressed package of this chapter.