Lập Trình Hiển Thị Tốc Độ Trên Màn Hình LCD bằng Arduino và Rotary Encoder

Bởi nguyenthanhphi (19/03/2018) 1 Bình luận

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.

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.

sơ đồ chân encoder quay

Để đ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.

sơ đồ chân encoder

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ơ.

sơ đồ chân encoder quay

    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.

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:

hiển thị tốc độ lên màn hình lcd bằng ardunio

Hình ảnh thực tế:

đo tốc độ bằng encoder và arduino

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

 

Đóng góp ý kiến

Bình luận(1)

  • Bình luận bởi Lê ngọc hùng
    Khi mình dùng PID điều chỉnh động cơ, thì việc dùng ngắt ngoài nó ảnh hưởng đáng kể, do vậy có giải pháp gì để vừa điều chỉnh động cơ sử dụng thuật toán PID và hiển thị đọc tốc độ động cơ lên LCD ko nhỉ? Thân!