[Arduino cơ bản] Giao tiếp LCD HD44780

Thảo luận trong 'Arduino' bắt đầu bởi VuPhat.MCA, 17/8/19.

  1. VuPhat.MCA

    VuPhat.MCA New Member

    Bài này mình sẽ giới thiệu cho các bạn cách giao tiếp với hai loại màn hình LCD Text phổ biến đó là 0802, 1602, 2004. Mình sẽ lấy ví dụ với màn 1602.

    Chuẩn bị:
    a) Arduino UNO R3
    b) LCD 1602 xanh lá
    c) Biến trở tam giác 10k
    d) Trở vạch 220Ω

    Sơ đồ kết nối:
    Chân VSS (GND) và VDD (5V) là hai chân cấp nguồn của LCD chúng ta đấu với nguồn 5V của Arduino. Chân VE là chân điều chỉnh độ tương phản của LCD, được điều chỉnh bằng điện áp đặt tại điểm giữa của biến trở, các chân điều khiển RS, RW, EN lần lượt được nối với chân 2, 3, 4 của Arduino. Các chân dữ liệu D4 đến D7 lần lượt được nối với các chân 5, 6, 7, 8. Chúng ta sẽ giao tiếp 4 bit với LCD.
    [​IMG]

    Màn hình LCD HD44780:
    Trong những năm gần đây, màn hình LCD đang được sử dụng phổ biến thay thế cho Led 7 thanh. Với giá thành rẻ, khả năng hiển thị số, ký tự, đồ họa,… chúng là những lựa chọn tuyệt vời để dùng hiển thị. Dưới đây là loại LCD Text phổ biến sử dụng chip điều khiển của hãng Hitachi. Đầu tiên chúng ta sẽ xem xét các chân của màn hình này nhé!
    [​IMG]
    * VSS, VDD, VE – Trong khi VDD và VSS là hai chân cấp nguồn +5V và GND thì VE được sử dụng để chỉnh độ tương phản LCD.
    * RS (Register Select) – Nếu RS = 0, thanh ghi dòng lệnh được lựa chọn, cho phép người dùng gửi các câu lệnh, chẳng hạn như xóa hiển thị. Nếu RS = 1, thanh ghi dữ liệu được lựa chọn, cho phép người dùng gửi dữ liệu sẽ được hiển thị lên màn hình LCD.
    * RW (Read/Write) – Cho phép người dùng ghi hoặc đọc thông tin trên màn hình LCD. R/W = 1 để đọc, và R/W = 0 để ghi.
    * E (Enable) – Chân được dùng để chốt dữ liệu. Khi dữ liệu được cấp đến các chân từ D0 – D7, cần phải có một xung H-to-L dể chốt dữ liệu, xung phải có độ rộng tối thiểu là 450ns.
    * A, K – Là 2 chân đèn nền Black light cho LCD.
    * D0 – D7 – Là các chân dữ liệu 8-bit D0 – D7, được sử dụng để ghi hoặc đọc LCD. Để hiển thị ký tự và chữ số, chúng ta sẽ gửi mã ASCII ra các chân này trong khi RS = 1. Ngoài ra các chân này còn được dùng để gửi lệnh trong khi RS = 0. Bảng sau liệt kê một số mã câu lệnh thường được sử dụng.
    [​IMG]

    Khởi tạo màn hình:
    Để khởi tạo LCD font 5x7 và chế độ hoạt động 4-bit, đầu tiên chúng ta cần chờ tối thiểu 40ms, sau đó gửi 3, 4 lần 0x03 để khởi tạo, mỗi lần chờ khoảng 1ms. Cuối cùng là gửi các lệnh để cấu hình LCD. Quá trình này được mô tả như lưu đồ sau:
    [​IMG]

    Để biết thêm nhiều hơn về quá trình khởi tạo, cách gửi lệnh, dữ liệu, cách ghi DDRAM. Các bạn nên tham khảo datasheet để nắm rõ hơn nhé!

    Gửi lệnh tới LCD:
    Để gửi bất kỳ lệnh tới LCD, kéo chân RS và R/W = 0 và đẩy mã lệnh vào các chân D4 – D7 ở chế độ 4-bit (D0 – D7 ở chế độ 8-bit). Sau đó gửi xung H-to-L tại chân E để chốt dữ liệu vào LCD. Chú ý rằng bất kỳ lệnh nào cũng cần phải trờ 100us để LCD chạy lệnh, ngoại trừ một số lệnh như xóa màn hình LCD, quay lại vị trí home cần khoảng thời gian chờ là 2ms.

    Gửi dữ liệu tới LCD:
    Để gửi dữ liệu, kéo chân RS = 1 và R/W = 0 và đẩy dữ liệu vào các chân D4 – D7 ở chế độ 4-bit (D0 – D7 ở chế độ 8-bit). Sau đó gửi xung H-to-L tại chân E để chốt dữ liệu vào LCD. Chú ý rằng sau khi gửi dữ liệu, cần chờ 100us để module ghi dữ liệu lên màn hình.

    Chương trình:
    Mã:
    const int lcdRS = 2; // Chân Arduino nối với chân RS
    const int lcdRW = 3; // Chân Arduino nối với chân RW
    const int lcdEN = 4; // chân Arduino nối với chân EN
    const int lcdD4 = 5; // Chân Arduino nối với chân D4
    const int lcdD5 = 6; // Chân Arduino nối với chân D5
    const int lcdD6 = 7; // Chân Arduino nối với chân D6
    const int lcdD7 = 8; // Chân Arduino nối với chân D7
    
    void setup() {
      // Cấu hình chân nối với LCD là đầu ra
      pinMode(lcdRS, OUTPUT);
      pinMode(lcdRW, OUTPUT);
      pinMode(lcdEN, OUTPUT);
      pinMode(lcdD4, OUTPUT);
      pinMode(lcdD5, OUTPUT);
      pinMode(lcdD6, OUTPUT);
      pinMode(lcdD7, OUTPUT);
      // Gọi hàm khởi tạo LCD
      LCD_Init();
    }
    
    void loop() {
      // Đặt con trỏ tới vị trí hàng 0, cột 0
      LCD_SetPos(0, 0);
      // Gửi chuỗi HELLO WORLD ra màn hình
      LCD_String("HELLO WORLD!");
    }
    
    // Hàm tạo xung chốt gửi dữ liệu
    void LCD_PulseEnable(void) {
      // Kéo chân EN xuống mức thấp
      digitalWrite(lcdEN, LOW);
      // Trễ 10us
      delayMicroseconds(10);
      // Kéo chân EN lên mức cao
      digitalWrite(lcdEN, HIGH);
      // Trễ 10us
      delayMicroseconds(10);
      // Kéo chân EN xuống mức thấp
      digitalWrite(lcdEN, LOW);
      // Trễ 1ms
      delay(1);
    }
    
    // Hàm ghi 4 bit dữ liệu vào LCD
    void LCD_Write4Bits(unsigned char nb) {
      // Lấy và kiểm tra bit thấp nhất
      // nếu bit = 1 thì xuất D4 mức cao
      if (((nb >> 0) & 0x01) == 1) {
        digitalWrite(lcdD4, HIGH);
      // Ngược lại thì xuất D4 mức thấp
      } else {
        digitalWrite(lcdD4, LOW);
      }
    
      // Tương tự với các bit tiếp theo
      if (((nb >> 1) & 0x01) == 1) {
        digitalWrite(lcdD5, HIGH);
      } else {
        digitalWrite(lcdD5, LOW);
      }
      if (((nb >> 2) & 0x01) == 1) {
        digitalWrite(lcdD6, HIGH);
      } else {
        digitalWrite(lcdD6, LOW);
      }
      if (((nb >> 3) & 0x01) == 1) {
        digitalWrite(lcdD7, HIGH);
      } else {
        digitalWrite(lcdD7, LOW);
      }
     
      // Tạo xung chốt dữ liệu
      LCD_PulseEnable();
    }
    
    // Hàm gửi lệnh ra màn hình LCD
    void LCD_Command(unsigned char cmd) {
      // RS = 0 cho chế độ dòng lệnh
      digitalWrite(lcdRS, LOW);
      // RW = 0 cho phép ghi
      digitalWrite(lcdRW, LOW);
      // Gửi 4 bit cao trước
      LCD_Write4Bits(cmd >> 4);
      // gửi 4 bit thấp
      LCD_Write4Bits(cmd);
    }
    
    // Hàm gửi dữ liệu ra màn hình LCD
    void LCD_Data(unsigned char dt) {
      // RS = 1 cho chế độ dữ liệu
      digitalWrite(lcdRS, HIGH);
      // RW = 0 cho phép ghi
      digitalWrite(lcdRW, LOW);
      // Gửi 4 bit cao trước
      LCD_Write4Bits(dt >> 4);
      // Gửi 4 bit thấp
      LCD_Write4Bits(dt);
    }
    
    // Hàm gửi ký tự ra màn hình LCD
    void LCD_Char(char chr) {
      // Gửi ký tự ra màn hình LCD
      LCD_Data((unsigned char) chr);
    }
    
    // Hàm gửi chuỗi ký tự ra màn hình LCD
    void LCD_String(char * str) {
      // Biến vị trí ký tự
      unsigned char i = 0;
      // Trong khi ký tự thứ i khác 0 (null)
      while (str[i] != 0) {
        // Gửi ký tự ra màn hình
        LCD_Char(str[i]);
        // Tăng vị trí ký tự thêm 1
        i++;
      }
    }
    
    // Hàm đặt vị trí con trỏ
    void LCD_SetPos(unsigned char x, unsigned char y) {
      // Mảng ký tự vị trí DDRAM đầu dòng của các hàng
      unsigned char firstChar[] = {0x80, 0xC0, 0x94, 0xD4};
      // ghi vào DDRAM vị trí của con trỏ
      LCD_Command(firstChar[y] + x);
    }
    
    void LCD_Clear(void) {
      LCD_Command(0x01);
      delay(2);
    }
    
    // Hàm khởi tạo LCD
    void LCD_Init(void) {
      // Trễ 50ms
      delay(50);
     
      // Đặt các chân RS, EN, RW ban đầu mức thấp
      digitalWrite(lcdRS, LOW);
      digitalWrite(lcdEN, LOW);
      digitalWrite(lcdRW, LOW);
     
      // Gửi giá trị 0x03 để khởi tạo
      LCD_Write4Bits(0x03);
      // Trễ 5ms
      delay(5);
      // Gửi giá trị 0x03 để khởi tạo
      LCD_Write4Bits(0x03);
      // Trễ 5ms
      delay(5);
      // Gửi giá trị 0x03 để khởi tạo
      LCD_Write4Bits(0x03);
      // Trễ 1ms
      delay(1);
      // Gửi giá trị 0x02 để khởi tạo
      LCD_Write4Bits(0x02);
     
      // LCD hiển thị 2 dòng, font 5x7, chế độ 4-bit
      LCD_Command(0x28);
      // Bật hiển thị, tắt cursor
      LCD_Command(0x0C);
      // Gọi hàm xóa màn hình
      LCD_Clear();
      // Tự động tăng cursor (tự động dịch phải)
      LCD_Command(0x06);
    }
    
    Biên dịch và nạp vào board Arduino rồi xem kết quả.

    Kết quả:
    Quan sát màn hình LCD chúng ta thấy chuỗi ký tự đã hiện lên tại vị trí hàng đầu tiên cột đầu tiên.
     
    Last edited: 17/8/19

trang này