Cách thức hoạt động của Rotary Encoder với Arduino

Cách thức hoạt động của Rotary Encoder với Arduino

Bạn biết gì về Rotary Encoder, đây là một module sử dụng khá phổ biến trong các ứng dụng như cánh tay Robot 4 bậc, máy in 3D và gần nhất sản phẩm được mình chế tạo là máy rót rượu tự động. Thông qua bài hướng dẫn này, mình sẽ giải thích rõ hơn về cách thức hoạt động cũng như là cấu tạo bên trong của Rotary Encoder Arduino.

Để tạo động lực cho Team Arduino KIT ra nhiều bài viết chất lượng hơn, các bạn có thể ủng hộ mình bằng cách Donate qua MoMo, Ngân hàng, Paypal…Nhấn vào link bên dưới nhé.

Linh kiện cần thiết cho dự án

TÊN LINH KIỆN SỐ LƯỢNG NƠI BÁN
Arduino Uno R3 1 Shopee | Cytron
Module Volume xoay Rotary Encoder 1 Shopee | Cytron
Breadboard 1 Shopee | Cytron
Servo SG90 1 Shopee | Cytron
Dây cắm (Đực – Đực) 10 – 20 Shopee | Cytron

Nguyên lý hoạt động của Rotary Encoder

Rotary Encoder là một thiết bị cơ học được sử dụng để ghi nhận và theo dõi sự thay đổi vị trí của một trục xoay. Nó hoạt động dựa trên nguyên lý của hai tín hiệu đầu vào: một tín hiệu A và một tín hiệu B.

Khi trục xoay của Rotary Encoder Arduino được quay, các đĩa có đặc tính quang học hoặc điện tử bên trong Encoder sẽ tạo ra các xung tín hiệu A và B. Các xung tín hiệu A và B có pha chênh lệch 90 độ với nhau. Khi quay thuận (theo chiều kim đồng hồ), tín hiệu A sẽ chạy trước tín hiệu B. Khi quay ngược (ngược chiều kim đồng hồ), tín hiệu B sẽ chạy trước tín hiệu A.

Nguyên lý hoạt động của Rotary Encoder dựa trên việc theo dõi sự thay đổi pha của các tín hiệu A và B để xác định hướng và tốc độ quay của trục xoay. Bằng cách theo dõi sự thay đổi pha và thứ tự của các xung tín hiệu, Encoder có thể xác định cả hướng và số lượng bước quay của trục xoay. Sự thay đổi vị trí được đọc thông qua các xung tín hiệu và được chuyển đổi thành các giá trị số để sử dụng trong việc kiểm soát hoặc hiển thị.

Các bạn có thể quan sát trạng thái của B khi trạng thái của A thay đổi:

  • Nếu B! = A, thì núm xoay theo chiều kim đồng hồ.
  • Nếu B = A thì xoay núm ngược chiều kim đồng hồ.

Sơ đồ chân Rotary Encoder

  • GND: Chân nối đất
  • VCC: Nguồn cấp (+) cho Rotary Encoder (Điện áp khuyến cáo từ 3.3 -5V)
  • SW: Là chân nút nhấn (hoạt động ở mức thấp).
  • DT: Chân dữ liệu, được sử dụng để đọc giá trị của vòng quay (Pha A)
  • CLK: Chân xung clock, được sử dụng để đọc giá trị của vòng quay (Pha B)

Sơ đồ đấu nối Rotary Encoder với Arduino

Arduino Uno R3 Rotary Encoder
5V +
GND GND
2 CLK
3 DT
4 SW

Code 1: Cách đọc Rotary Encoder

// Rotary Encoder Inputs
#define CLK 2
#define DT 3
#define SW 4

int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir ="";
unsigned long lastButtonPress = 0;

void setup() {
        
	// Set encoder pins as inputs
	pinMode(CLK,INPUT);
	pinMode(DT,INPUT);
	pinMode(SW, INPUT_PULLUP);

	// Setup Serial Monitor
	Serial.begin(9600);

	// Read the initial state of CLK
	lastStateCLK = digitalRead(CLK);
}

void loop() {
        
	// Read the current state of CLK
	currentStateCLK = digitalRead(CLK);

	// If last and current state of CLK are different, then pulse occurred
	// React to only 1 state change to avoid double count
	if (currentStateCLK != lastStateCLK  && currentStateCLK == 1){

		// If the DT state is different than the CLK state then
		// the encoder is rotating CCW so decrement
		if (digitalRead(DT) != currentStateCLK) {
			counter --;
			currentDir ="CCW";
		} else {
			// Encoder is rotating CW so increment
			counter ++;
			currentDir ="CW";
		}

		Serial.print("Direction: ");
		Serial.print(currentDir);
		Serial.print(" | Counter: ");
		Serial.println(counter);
	}

	// Remember last CLK state
	lastStateCLK = currentStateCLK;

	// Read the button state
	int btnState = digitalRead(SW);

	//If we detect LOW signal, button is pressed
	if (btnState == LOW) {
		//if 50ms have passed since last LOW pulse, it means that the
		//button has been pressed, released and pressed again
		if (millis() - lastButtonPress > 50) {
			Serial.println("Button pressed!");
		}

		// Remember last button press event
		lastButtonPress = millis();
	}

	// Put in a slight delay to help debounce the reading
	delay(1);
}

Dưới đây là kết quả, được xuất ra Serial Monitor.

Giải thích code

#define CLK 2
#define DT 3
#define SW 4

Khai báo ba chân CLK, DT, SW kết nối với Arduino.

int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir ="";
unsigned long lastButtonPress = 0;
  • Biến counter được khởi tạo với giá trị ban đầu là 0. Biến này được sử dụng để theo dõi số lần quay của Rotary Encoder.
  • Biến currentStateCLK được sử dụng để lưu trữ trạng thái hiện tại của chân CLK.
  • Biến lastStateCLK được sử dụng để lưu trữ trạng thái trước đó của chân CLK.
  • Biến currentDir là một đối tượng kiểu String được khởi tạo với giá trị rỗng. Biến này sẽ chứa thông tin về hướng quay của Rotary Encoder (CW – Clockwise hoặc CCW – Counter Clockwise).
  • Biến lastButtonPress là một số nguyên không dấu (unsigned long) và được khởi tạo với giá trị 0. Biến này được sử dụng để lưu thời điểm lần nhấn nút cuối cùng trên Rotary Encoder Arduino.
pinMode(CLK,INPUT);
pinMode(DT,INPUT);
pinMode(SW, INPUT_PULLUP);

Serial.begin(9600);

lastStateCLK = digitalRead(CLK);

Đặt chân các chân CLK, DT, SW của Rotary Encoder là chế độ đầu vào (INPUT), Pull-up resistor được kích hoạt (INPUT_PULLUP) trên chân SW.

Khởi động giao tiếp Serial với tốc độ baud rate là 9600.

lastStateCLK = digitalRead(CLK); Đọc trạng thái hiện tại của chân CLK và lưu trữ vào biến lastStateCLK. Điều này giúp ghi nhớ trạng thái ban đầu của chân CLK để so sánh với trạng thái hiện tại trong quá trình xử lý dữ liệu từ Rotary Encoder.

currentStateCLK = digitalRead(CLK);

if (currentStateCLK != lastStateCLK  && currentStateCLK == 1){

currentStateCLK = digitalRead(CLK); Đọc trạng thái hiện tại của chân CLK và lưu trữ vào biến currentStateCLK. Điều này cho phép biết trạng thái hiện tại của chân CLK (HIGH hoặc LOW).

if (currentStateCLK != lastStateCLK && currentStateCLK == 1) Kiểm tra xem trạng thái hiện tại của chân CLK có khác với trạng thái trước đó (lastStateCLK) và trạng thái hiện tại của chân CLK là HIGH (1) hay không. Điều kiện này chỉ đúng khi có sự thay đổi trạng thái từ LOW sang HIGH trên chân CLK, cho biết rằng đã xảy ra một xung từ Rotary Encoder.

if (digitalRead(DT) != currentStateCLK) {
    counter --;
    currentDir ="CCW";
} else {
    counter ++;
    currentDir ="CW";
}

digitalRead(DT) != currentStateCLK Kiểm tra trạng thái của chân DT (data) có khác với trạng thái hiện tại của chân CLK (clock) hay không. Điều này giúp xác định hướng quay của Rotary Encoder.

  • Nếu trạng thái của chân DT khác với trạng thái hiện tại của chân CLK, có nghĩa là Rotary Encoder đang quay ngược chiều kim đồng hồ (Counter-Clockwise – CCW). Trong trường hợp này, giảm giá trị của biến counter đi 1 và gán giá trị “CCW” cho biến currentDir.
  • Ngược lại, nếu trạng thái của chân DT giống với trạng thái hiện tại của chân CLK, có nghĩa là Rotary Encoder Arduino đang quay theo chiều kim đồng hồ (Clockwise – CW). Trong trường hợp này, tăng giá trị của biến counter lên 1 và gán giá trị “CW” cho biến currentDir.
Serial.print("Direction: ");
Serial.print(currentDir);
Serial.print(" | Counter: ");
Serial.println(counter);

Hiển thị thông tin về hướng quay và giá trị đếm của Rotary Encoder trên Serial Monitor.

lastStateCLK = currentStateCLK;

lastStateCLK được gán giá trị của currentStateCLK để lưu trữ trạng thái trước đó của tín hiệu đầu vào của chân CLK.

int btnState = digitalRead(SW);

if (btnState == LOW) {
    if (millis() - lastButtonPress > 50) {
        Serial.println("Button pressed!");
    }
    lastButtonPress = millis();
}

Đoạn code trên, dùng để đọc trạng thái của nút bấm (SW) bằng cách sử dụng hàm digitalRead(SW) và lưu giá trị đó vào biến btnState.

Sau đó, kiểm tra xem giá trị của btnState có bằng LOW hay không. Nếu giá trị này bằng LOW, điều đó có nghĩa là nút bấm đã được nhấn.

Trong điều kiện này, kiểm tra thời gian từ lần nhấn trước đó của nút bấm (lastButtonPress) đến thời điểm hiện tại (millis()) để kiểm tra xem đã trôi qua ít nhất 50ms kể từ lần nhấn trước đó hay chưa. Nếu điều kiện này được đáp ứng, in ra thông báo “Button pressed!” sử dụng hàm Serial.println().

Cuối cùng, cập nhật thời điểm lần nhấn cuối cùng của nút bấm bằng cách gán giá trị của millis() cho biến lastButtonPress. Điều này giúp tính toán thời gian từ lần nhấn trước đó cho lần nhấn tiếp theo.

Code 2: Điều khiển động cơ Servo với Rotary Encoder

Sơ đồ đấu nối

Arduino Uno R3 Rotary Encoder Động cơ Servo SG90
5V +
GND GND Nâu
2 CLK
3 DT
4 SW
9 Vàng

Xem thêm: Hướng dẫn sử dụng động cơ Servo SG90 với Arduino

Code

// Include the Servo Library
#include <Servo.h>

// Rotary Encoder Inputs
#define CLK 2
#define DT 3

Servo servo;
int counter = 0;
int currentStateCLK;
int lastStateCLK;

void setup() {

	// Set encoder pins as inputs
	pinMode(CLK,INPUT);
	pinMode(DT,INPUT);
	
	// Setup Serial Monitor
	Serial.begin(9600);
	
	// Attach servo on pin 9 to the servo object
	servo.attach(9);
	servo.write(counter);
	
	// Read the initial state of CLK
	lastStateCLK = digitalRead(CLK);
}

void loop() {
        
	// Read the current state of CLK
	currentStateCLK = digitalRead(CLK);
	
	// If last and current state of CLK are different, then pulse occurred
	// React to only 1 state change to avoid double count
	if (currentStateCLK != lastStateCLK  && currentStateCLK == 1){
		
		// If the DT state is different than the CLK state then
		// the encoder is rotating CCW so decrement
		if (digitalRead(DT) != currentStateCLK) {
			counter --;
			if (counter<0)
				counter=0;
		} else {
			// Encoder is rotating CW so increment
			counter ++;
			if (counter>179)
				counter=179;
		}
		// Move the servo
		servo.write(counter);
		Serial.print("Position: ");
		Serial.println(counter);
	}
	
	// Remember last CLK state
	lastStateCLK = currentStateCLK;
}

Bài viết liên quan

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments