Điều khiển LED với encoder

Điều khiển LED với encoder và hiển thị cường độ sáng của LED lên LCD

Trong bài hướng dẫn này ta sẽ học cách đọc dữ liệu từ encoder, từ đó xây dựng một ứng dụng đơn giản sử dụng encoder để tăng giảm độ sáng của bóng đèn LED RGB và xuất tín hiệu điều khiển lên màn hình LCD 16x2.

Các linh kiện cần chuẩn bị

Giới thiệu về rotary encoder

  • Rotary encoder là một loại cảm biến vị trí được sử dụng để xác định góc quay của trục.
  • Đầu ra encoder gồm 2 chân ra xung A, B và một nút nhấn.
  • Nguyên tắc làm việc:

    • Khi encoder xoay, 2 chân A và B sẽ được kéo xuống mức thấp, vì thế nên ta phải kéo điện trở lên VCC cho cả A và B.
    • Xung tạo ra từ A và B luôn luôn lệch pha nhau nhờ đó ta có thể xác định chiều quay của trục bằng cách xác định kênh nào sớm hoặc trễ pha hơn kênh còn lại.

Giới thiệu LCD 16x2

  • LCD 16x2 là một loại text LCD hiển thị chữ, số hoặc ký tự đơn giản trong bảng mã ASCII.
  • LCD bao gồm 2 dòng, mỗi dòng hiển thị tối đa 16 ký tự.
  • Mỗi ô ký tự được hiển thị bởi 5x8 điểm ảnh, bằng cách thay đổi sáng tắt các điểm ảnh này ta có thể hiển thị được ký tự mong muốn. Nhờ đó, ngoài những ký tự ASCII cơ bản, ta cũng có thể tự tạo nên những ký tự mong muốn để hiển thị lên màn hình này.

Module LED RGB

Module LED RGB là module tích hợp 3 LED green, blue và red ở bên trong. Bằng việc điều khiển cường độ sáng của 3 LED bên trong module, ta có thể tạo các các màu sắc tùy theo ý thích.

Kết nối rotary encoder với UnoX

Vì rotary encoder cần nhận biết xung từ 2 chân A và B để so sánh. Do đó, để đảm bảo tính chính xác cho việc đọc cảm biến, ta sử dụng 2 chân interrupt của UnoX (chân 2 và 3), với việc ngắt khi phát hiện cạnh lên từ 2 chân A và B.

Rotary encoderBoard UnoX
Chân GNDChân GND
Chân +Chân 5V
Chân SWChân 4
Chân A (DT)Chân 3
Chân B (CLK)Chân 2

Kết nối LCD 16x2 với UnoX

Có 2 phương pháp kết nối LCD: Kết nối bằng chân điều khiển và kết nối qua bộ chuyển đổi I2C. Trong nội dung bài hướng dẫn này, ta sử dụng phương pháp kết nối bằng chân điều khiển.

LCD 16x2Board UnoX
Chân VSSChân GND
Chân VDDChân 5V
Chân V0Biến trở
Chân RSChân 5
Chân RWChân GND
Chân EChân 6
Chân D4Chân 7
Chân D5Chân 8
Chân D6Chân 12
Chân D7Chân 13
Chân AChân 3V3
Chân KChân GND

Có 1 chân của biến trở không kết nối với UnoX, đây chính là chân đầu ra của biến trở, dùng để điều chỉnh độ phân giải của LCD.

Kết nối LED RGB với UnoX

  • Sơ đồ kết nối:
LED RGBBoard UnoX
Chân V/GChân GND
Chân RChân 9
Chân GBiến 10
Chân BChân 11

Đây là LED RGB có cathod chung nên, nên ta sẽ nối chân V/G xuống GND. Làm ngược lại với LED RGB có anod chung. Để điểu khiển màu sắc, 3 chân R, G, B phải nối với 3 chân PWM của UnoX (chân có dấu ~ trên UnoX).

Kết nối các linh kiện với UnoX

Từ các kết nối của các module đến UnoX, chúng ta có được mô hình tổng quát như hình bên

Ý tưởng xây dựng chương trình

  • Xoay encoder để tùy chọn LED cần được điều chỉnh.
  • Nhấn button trên encoder để vào bắt đấu điều chỉnh.
  • Xoay encoder để tăng giảm độ sáng LED.
  • Nhấn button để thoát khỏi trạng thái điều chỉnh.
  • LCD hiển thị tỉ lệ sáng của các led và giúp cho quá trình điều khiển đạt trạng thái tốt nhất.
  • Sử dụng thư viện:

    • Điều khiển LED RGB: điều khiển PWM.
    • Đọc dữ liệu từ encoder: Sử dụng ngắt từ 2 chân interrupt.
    • Hiển thị LCD 16x02: LiquidCrystal.h.

Source code

  //library control LCD display
  #include <LiquidCrystal.h>

  //define pin of lcd
  #define RSPin 5
  #define ENPin 6
  #define D4Pin 7
  #define D5Pin 8
  #define D6Pin 12
  #define D7Pin 13

  //define pin of encoder
  #define pinA 2
  #define pinB 3
  #define buttonPin 4

  //define pin of led RGB
  #define redPin 9
  #define greenPin 10
  #define bluePin 11

  bool menuChoice = 1;
  bool redChoice = 0;
  bool greenChoice = 0;
  bool blueChoice = 0;

  int menuLastCount = 0;
  int redLastCount = 0;
  int greenLastCount = 0;
  int blueLastCount = 0;

  int menuCount = 0;
  int redCount = 0;
  int greenCount = 0;
  int blueCount = 0;

  // Đọc hướng và bước của encoder
  // Nếu con trỏ đang ở Menu, xoay encoder để chọn hướng
  // Xoay encoder điều chỉnh gía trị cường độ sáng nếu
  // con trỏ vào chế độ chọn 1 trong 3 LED R,G,B
  void isr()
  {
    static unsigned long lastInterruptTime = 0;
    unsigned long interruptTime = millis();

    if (interruptTime - lastInterruptTime > 5)
    {
      if (digitalRead(pinB) == LOW)
      {
        if (menuChoice)
          menuCount--;
        else if (redChoice)
          redCount--;
        else if (greenChoice)
          greenCount--;
        else if (blueChoice)
          blueCount--;
      }
      else
      {
        if (menuChoice)
          menuCount++;
        else if (redChoice)
          redCount++;
        else if (greenChoice)
          greenCount++;
        else if (blueChoice)
          blueCount++;
      }

      menuCount = min(2, max(0, menuCount));
      redCount = min(255, max(0, redCount));
      greenCount = min(255, max(0, greenCount));
      blueCount = min(255, max(0, blueCount));

      lastInterruptTime = interruptTime;
    }
  }

  //setup LCD
  LiquidCrystal LCD(RSPin, ENPin, D4Pin, D5Pin, D6Pin, D7Pin);

  void setup()
  {
    //setup size of LCD
    LCD.begin(16, 2);
    //clear all digit of LCD
    LCD.clear();
    //setup pin of encoder
    pinMode(pinA, INPUT);
    pinMode(pinB, INPUT);
    pinMode(buttonPin, INPUT_PULLUP);

    //attach interrupt on pin A of encoder
    attachInterrupt(digitalPinToInterrupt(pinA), isr, LOW);

    //goto location of LCD
    LCD.setCursor(2, 0);
    //print string to LCD with location above
    LCD.print("IoT Maker VN");
    LCD.setCursor(0, 1);
    LCD.print(">R0   G0   B0  ");
  }

  void loop()
  {
    if ((!digitalRead(buttonPin)))
    {
      if (menuChoice)
      {
        menuChoice = 0;
        switch (menuCount)
          {
          case 0:
            redChoice = 1;
            break;
          case 1:
            greenChoice = 1;
            break;
          case 2:
            blueChoice = 1;
            break;
          }
      }
      else if (redChoice)
      {
        redChoice = 0;
        menuChoice = 1;
      }
      else if (greenChoice)
      {
        greenChoice = 0;
        menuChoice = 1;
      }
      else if (blueChoice)
      {
        blueChoice = 0;
        menuChoice = 1;
      }
      while (!digitalRead(buttonPin))
        delay(10);
    }

    if (menuChoice)
    {
      if (menuCount != menuLastCount)
      {
        switch (menuCount)
        {
        case 0:
          LCD.setCursor(0, 1);
          LCD.print(">");
          LCD.setCursor(5, 1);
          LCD.print(" ");
          LCD.setCursor(10, 1);
          LCD.print(" ");
          break;
        case 1:
          LCD.setCursor(0, 1);
          LCD.print(" ");
          LCD.setCursor(5, 1);
          LCD.print(">");
          LCD.setCursor(10, 1);
          LCD.print(" ");
          break;
        case 2:
          LCD.setCursor(0, 1);
          LCD.print(" ");
          LCD.setCursor(5, 1);
          LCD.print(" ");
          LCD.setCursor(10, 1);
          LCD.print(">");
          break;
        }
        menuLastCount = menuCount;
      }
    }

    if (redChoice)
    {
      if (redCount != redLastCount)
      {
        LCD.setCursor(2, 1);
        LCD.print("   ");
        LCD.setCursor(2, 1);
        LCD.print(redCount);
        analogWrite(redPin, redCount);
        redLastCount = redCount;
      }
    }

    if (greenChoice)
    {
      if (greenCount != greenLastCount)
      {
        LCD.setCursor(7, 1);
        LCD.print("   ");
        LCD.setCursor(7, 1);
        LCD.print(greenCount);
        analogWrite(greenPin, greenCount);
        greenLastCount = greenCount;
      }
    }

    if (blueChoice)
    {
      if (blueCount != blueLastCount)
      {
        LCD.setCursor(12, 1);
        LCD.print("   ");
        LCD.setCursor(12, 1);
        LCD.print(blueCount);
        analogWrite(bluePin, blueCount);
        blueLastCount = blueCount;
      }
    }
  }

Kết quả

  • Khi chọn vào menu và nhấn vào encoder sẽ hiện ra bảng chọn 1 trong 3 LED, RED, GREEN hoặc BLUE. Xoay encoder, nhấn vào 1 trong 3 màu, ta có thể điều chỉnh cường độ sáng của LED bằng cách xoay encoder.
  • Thoát ra khỏi mục đã chọn bằng cách nhấn vào encoder.

Ứng dụng mở rộng

  • Làm menu nhiều lớp để điều khiển bật, tắt nhiều thiết bị với encoder và LCD.