Lập Trình Hiển Thị Tốc Độ Trên Màn Hình LCD bằng Arduino và Rotary Encoder
Rotaty Encoder Module trông giống như biến trở nhưng có ngõ ra dạng xung số. Bằng việc xoay núm vặn, ngõ ra xung của 2 kênh sẽ thay đổi với 1 độ lệch pha xác định (90 độ) giúp phân biệt được chiều xoay.
Đếm số lượng xung ngõ ra sẽ cho biết vị trí góc xoay, vị trí này là không giới hạn. Đồng thời module cũng cung cấp 1 nút nhấn có thể được lập trình để trở thành 1 nút reset giá trị đếm.
Linh kiện cần chuẩn bị:
- Arduino UNO.
- Dây cắm breadboard.
- Module LCD 16x02 hoặc LCD 20x04.
- Module I2C cho LCD.
- Encoder quay như hình trên.
Encoder quay.
Thông số kỹ thuật:
• Điện áp cung cấp: 3.3V
• Độ phân giải 20 xung/vòng.
• Các chân tín hiệu:
+ : chân cấp nguồn dương
GND: chân cấp nguồn âm
CLK: phase A
DT: phase B
SW: button.
Để điều khiển số vòng quay hay vận tốc động cơ thì chúng ta nhất thiết phải đọc được góc quay của motor.
Encoder thường bao gồm kênh A, kênh B. Trong hình bạn thấy hãy chú ý một lỗ nhỏ bên phía trong của đĩa quay và một cặp phat-thu dành riêng cho lỗ nhỏ này. Cữ mỗi lần motor quay được một vòng. Bên ngoài đĩa quay được chia thành các rãnh nhỏ và một cặp thu-phát khác dành cho các rãnh này. Đây là kênh A của encoder.
Mỗi loại encoder có độ phân giải khác nhau, có khi trên mỗi đĩa chĩ có vài rãnh nhưng cũng có trường hợp đến hàng nghìn rãnh được chia. Để điều khiển động cơ, bạn phải biết độ phân giải của encoder đang dùng. Độ phân giải ảnh hưởng đến độ chính xác điều khiển và cả phương pháp điều khiển tuy nhiên trên các encoder còn có một cặp thu phát khác được đặt trên cùng đường tròn với
kênh A nhưng lệch một chút (lệch M+0,5 rãnh), đây là kênh B của encoder. Tín hiệu xung từ kênh B có cùng tần số với kênh A nhưng lệch pha 90 độ. Bằng cách phối hợp kênh A và B người đọc sẽ biết chiều quay của động cơ.
Hình trên thể hiện sự bộ trí của 2 cảm biến kênh A và B lệch pha nhau. Khi cảm biến A bắt đầu bị che thì cảm biến B hoàn toàn nhận được hồng ngoại xuyên qua, và ngược lại. Hình thấp là dạng xung ngõ ra trên 2 kênh. Xét trường hợp motor quay cùng chiều kim đồng hồ, tín hiệu “đi” từ trái sang phải.
Bạn hãy quan sát lúc tín hiệu A chuyển từ mức cao xuống thấp (cạnh xuống) thì kênh B đang ở mức thấp. Ngược lại, nếu động cơ quay ngược chiều kim đồng hồ, tín hiệu “đi” từ phải qua trái. Lúc này, tại cạnh xuống của kênh A thì kênh B đang ở mức cao.
Như vậy, bằng cách phối hợp 2 kênh A và B chúng ta không những xác định được góc quay (thông qua số xung) mà còn biết được chiều quay của động .
Cách đọc encoder bằng Arduino.
Sử dụng ngắt ngoài: đây là phương pháp dễ nhưng chính xác để đọc encoder và cũng là phương pháp được dùng trong bài học này. Ý tưởng của phương pháp rất đơn giản, chúng ta nối kênh A của encoder với 1 ngắt ngoài (INT2 chẳng hạn) và kênh B với một chân nào đó bất kỳ (không phải chân ngắt). Cứ mỗi lần ngắt ngoài xảy ra, tức có 1 xung xuất hiện trên ở kênh A thì trình phục vụ ngắt ngoài tự động được gọi. Trong trình phục vụ ngắt này chúng ta kiểm tra mức của kênh B, tùy theo mức của kênh B chúng ta sẽ tăng biến đếm xung lên 1 hoặc giảm đi 1. Tuy nhiên, bạn cần phải tính toán rất cẩn thận khi sử dụng phương pháp này.
Trong bài này, chúng ta chọn độ phân giải của encoder là 20 (20 xung trên mỗi vòng quay, loại encoder đơn giản nhất).
Module I2C cho LCD.
Trước tiên ta phải add thư viện I2C cho arduino IDE.
Tải thư viện theo link sau: http://www.mediafire.com/file/d401tink3h316vr/I2C.rar
Cách add thư viện cho Arduino IDE :
http://tdhshop.com.vn/huong-dan-cai-thu-vien-vao-arduino-ide-ho-tro-cho-viec-lap-trinh
Lắp mạch:
Hình ảnh thực tế:
Lập trình: ( Upload code cho arduino và cùng xem kết quả nhé )
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,16,2);
// Cách nối các chân trên Encoder quay
#define encoderPinA 2 // Tương ứng chân DT trên Encoder quay
#define encoderPinB 3 // Tương ứng chân CLK trên Encoder quay
// Chân + nối nguồn 3.3V và chân GND nối cực âm
volatile int encoderPos = 0; // Cho vị trí đầu bằng 0
int lastReportedPos = 1; // Vị trí cuối bằng 1
static boolean rotating=false; // Quản lý debounce (giống như là chống nhiễu)
// các biến cho trình phục vụ ngắt interrupt service routine vars
boolean A_set = false;
boolean B_set = false;
//Đo tốc độ
int newposition;
int oldposition=0;
long newtime;
long oldtime=0;
int vantoc = 0;
int ganvantoc = 0;
int ganxung = 0;
int sovong = 0;
void setup() {
lcd.begin(20,4);
lcd.init(); // initialize the lcd
lcd.backlight();
pinMode(encoderPinA, INPUT_PULLUP); // INPUT-PULLUP tương đương Mode INPUT và tự động nhận trạng thái HIGH hoặc LOW
pinMode(encoderPinB, INPUT_PULLUP);
// Chân encoder trên ngắt 0 (chân 2)
attachInterrupt(0, doEncoderA, CHANGE);
// Chân encoder trên ngắt 1 (chân 3)
attachInterrupt(1, doEncoderB, CHANGE);
Serial.begin(9600); // chuyển dữ liệu lên cổng Serial Port
lcd.setCursor(0,1);
lcd.print("SO VONG = ");
}
// Vòng lặp chính, công việc được thực hiện bởi trình phục vụ ngắt
void loop() {
delay(1000);
rotating = true; // Khởi động bộ debounce (có thể hiểu như bộ chống nhiễu)
newtime=millis();
newposition=encoderPos;
detachInterrupt(0);
detachInterrupt(1);
vantoc = (newposition-oldposition)*60/20;
Serial.print("vantoc=");
Serial.println(vantoc,DEC);
oldposition=newposition;
oldtime=newtime;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("TOC DO = ");
lcd.setCursor(11,0);
lcd.print(vantoc);
lcd.print(" RPM");
lcd.setCursor(0,1);
lcd.print("SO VONG = ");
lcd.setCursor(11,1);
lcd.print(sovong,DEC);
attachInterrupt(0, doEncoderA, CHANGE);
attachInterrupt(1, doEncoderB, CHANGE);
}
// Ngắt khi chuyển trạng thái của A
void doEncoderA(){
// debounce
if ( rotating ) delay (1); // Chờ 1 chút
// Kiểm tra việc chuyển đổi trạng thái, xem có thật sự thay đổi trạng thái chưa
if( digitalRead(encoderPinA) != A_set ) { // debounce một lần nữa
A_set = !A_set;
// Cộng 1 nếu có tín hiệu A rồi có tín hiệu B
if ( A_set && !B_set )
encoderPos += 1;
ganxung += 1;
sovong=encoderPos/20;
if (ganxung == 42){ganxung=0;}
rotating = false; // Không cần debounce nữa cho đến khi được nhấn lần nữa
}
}
// Ngắt khi thay đổi trạng thái ở B, tương tự như ở A
void doEncoderB(){
if ( rotating ) delay (1);
if( digitalRead(encoderPinB) != B_set ) {
B_set = !B_set;
// Trừ 1 nếu B rồi đến A
if( B_set && !A_set )
encoderPos -= 1;
rotating = false;
}
}
Web: tdhshop.com.vn
Email: tdhshop1991@gmail.com
Tel: 01695 304 802
Bình luận(3)