Hướng dẫn dùng màn hình OLED 0.96 inch SSD1306 với Arduino Nano
Hướng dẫn nối màn hình OLED 0.96 inch SSD1306 (I2C) với Arduino Nano, cài thư viện Adafruit, hiện chữ nhiều cỡ, vẽ thanh mức theo điện áp và lưu ý về bộ nhớ RAM.
Màn hình OLED 0.96 inch nhỏ gọn, chữ sắc nét, chỉ cần bốn dây nối và rất hợp với Arduino Nano trên breadboard. Bài viết hướng dẫn nối màn hình OLED SSD1306 giao tiếp I2C với Arduino Nano, cài thư viện, hiện chữ với nhiều cỡ, vẽ thanh mức theo điện áp đo được và những lưu ý về bộ nhớ RAM, vốn là chỗ người mới hay vướng nhất khi dùng màn hình này với Nano.
1. Tìm hiểu màn hình OLED 0.96 inch
| Thông số | Giá trị |
|---|---|
| Kích thước, độ phân giải | 0.96 inch, 128 x 64 điểm ảnh |
| Chip điều khiển | SSD1306 |
| Giao tiếp | I2C, bốn chân GND, VCC, SCL, SDA |
| Địa chỉ I2C | 0x3C (một số màn hình dùng 0x3D) |
| Nguồn cấp | 3,3–5 V |
| Màu hiển thị | Hai vùng màu: 16 hàng trên màu vàng, phần còn lại màu xanh |
Mỗi điểm ảnh OLED tự phát sáng nên màn hình không cần đèn nền, nền đen sâu và nhìn rõ từ nhiều góc. Màu của từng vùng do tấm nền quyết định, chương trình chỉ bật hoặc tắt điểm ảnh chứ không chọn được màu.
2. Linh kiện cần chuẩn bị
- Arduino Nano và cáp USB có truyền dữ liệu. Nếu chưa từng nạp chương trình cho Nano, xem trước bài bắt đầu với Arduino Nano CH340.
- Màn hình OLED 0.96 inch SSD1306 giao tiếp I2C.
- Breadboard MB-102 và dây cắm test board. Muốn nối dây bằng cọc vít thay cho breadboard, có thể dùng đế ra chân terminal cho Arduino Nano.
- Một biến trở 10 kΩ cho chương trình đo điện áp ở mục 7.
- Máy tính đã cài Arduino IDE 2.x.
3. Sơ đồ nối màn hình với Arduino Nano
| OLED 0.96 inch | Arduino Nano | Ghi chú |
|---|---|---|
| VCC | 5V | Màn hình nhận nguồn 3,3–5 V. |
| GND | GND | Mass chung. |
| SCL | A5 | Xung clock I2C. |
| SDA | A4 | Dữ liệu I2C. |
Trên Arduino Nano, bus I2C cố định ở hai chân A4 (SDA) và A5 (SCL), không đổi sang chân khác được. Thứ tự bốn chân trên màn hình có thể khác nhau theo lô hàng, vì vậy luôn nối theo tên chân in trên mạch; cắm ngược VCC và GND có thể làm hỏng màn hình.
4. Cài thư viện
- Mở Tools > Manage Libraries, tìm Adafruit SSD1306 và bấm Install.
- Khi IDE hỏi cài thêm thư viện phụ thuộc, chọn Install All để cài kèm Adafruit GFX Library và Adafruit BusIO.
- Chọn Tools > Board > Arduino AVR Boards > Arduino Nano, chọn đúng Processor và cổng COM như đã làm trong bài bắt đầu với Nano.
Bài dùng Adafruit SSD1306 phiên bản 2.5.17, Adafruit GFX Library 1.12.6 và Adafruit BusIO 1.17.4.
5. Chương trình 1: hiện chữ với ba cỡ chữ
/*
PYWORLD.VN - Arduino Nano + màn hình OLED 0.96 inch SSD1306 (I2C): hiện chữ với ba cỡ chữ
OLED: VCC = 5V, GND = GND, SCL = A5, SDA = A4, địa chỉ 0x3C
Thư viện: Adafruit SSD1306, Adafruit GFX
*/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_ADDR 0x3C
Adafruit_SSD1306 oled(128, 64, &Wire, -1);
void setup() {
Serial.begin(9600);
// Lệnh begin() xin 1024 byte RAM làm bộ đệm hình; trả về false nếu không đủ RAM
if (!oled.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println(F("Khong khoi tao duoc OLED!"));
while (true) {}
}
oled.clearDisplay(); // Xóa bộ đệm
oled.setTextColor(SSD1306_WHITE);
oled.setTextSize(1); // Cỡ 1: mỗi ký tự 6 x 8 điểm ảnh
oled.setCursor(0, 4);
oled.print(F("Co chu 1 - 6x8 diem"));
oled.setTextSize(2); // Cỡ 2: lớn gấp đôi
oled.setCursor(0, 20);
oled.print(F("Co chu 2"));
oled.setTextSize(3); // Cỡ 3: lớn gấp ba
oled.setCursor(0, 40);
oled.print(F("Co 3"));
oled.display(); // Gửi bộ đệm ra màn hình
}
void loop() {
}
Sau khi nạp, màn hình hiện ba dòng chữ với ba cỡ khác nhau:
- Toạ độ: gốc (0, 0) ở góc trên bên trái; x tăng sang phải đến 127, y tăng xuống dưới đến 63.
setCursor(x, y)đặt góc trên bên trái của ký tự tiếp theo. - Cỡ chữ: ở cỡ 1 mỗi ký tự chiếm 6 x 8 điểm ảnh, nên một dòng chứa được 21 ký tự và màn hình chứa được 8 dòng. Cỡ 2 và cỡ 3 lớn gấp đôi và gấp ba.
- Bộ đệm: các lệnh
print()và lệnh vẽ chỉ ghi vào bộ đệm trong RAM. Hình chỉ xuất hiện khi gọioled.display(). - Chữ không dấu: bộ chữ mặc định của thư viện không có dấu tiếng Việt.
F("..."): giữ chuỗi trong bộ nhớ flash thay vì chép vào RAM. Với Nano nên dùng cho mọi chuỗi cố định.
6. Lưu ý quan trọng: bộ nhớ RAM của Nano
Vi điều khiển ATmega328P trên Arduino Nano chỉ có 2048 byte RAM. Bộ đệm hình của màn hình 128 x 64 cần 128 × 64 / 8 = 1024 byte, tức một nửa số RAM đó.
- Bộ đệm được cấp phát khi chương trình chạy đến lệnh
oled.begin(). Dòng Global variables use... mà Arduino IDE in ra sau khi kiểm tra chương trình chưa tính 1024 byte này. - Nếu không đủ RAM,
oled.begin()trả vềfalsevà màn hình không hiện gì. Vì vậy chương trình luôn kiểm tra giá trị trả về của lệnh này. - Để dành RAM cho màn hình: dùng
F()cho chuỗi cố định, tránh kiểuString, tránh khai báo mảng lớn. - Màn hình loại 128 x 32 chỉ cần bộ đệm 512 byte, phù hợp khi chương trình cần nhiều RAM cho việc khác.
7. Chương trình 2: hiện điện áp và thanh mức
Nối thêm biến trở 10 kΩ: hai chân ngoài vào 5V và GND, chân giữa vào A0. Chương trình đọc điện áp ở A0, hiện số đo cỡ lớn và vẽ một thanh mức dài theo điện áp:
/*
PYWORLD.VN - Arduino Nano + OLED 0.96 inch: đọc điện áp ở chân A0, hiện số và thanh mức
OLED: VCC = 5V, GND = GND, SCL = A5, SDA = A4, địa chỉ 0x3C
Biến trở 10 kΩ: hai chân ngoài nối 5V và GND, chân giữa nối A0
Thư viện: Adafruit SSD1306, Adafruit GFX
*/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_ADDR 0x3C
#define ANALOG_PIN A0
Adafruit_SSD1306 oled(128, 64, &Wire, -1);
void setup() {
Serial.begin(9600);
if (!oled.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println(F("Khong khoi tao duoc OLED!"));
while (true) {}
}
oled.setTextColor(SSD1306_WHITE);
}
void loop() {
int giaTri = analogRead(ANALOG_PIN); // 0-1023
float volt = giaTri * 5.0 / 1023.0; // Đổi sang vôn theo nguồn 5 V
int rongThanh = map(giaTri, 0, 1023, 0, 124); // Bề rộng phần tô của thanh mức
oled.clearDisplay();
oled.setTextSize(1);
oled.setCursor(0, 4);
oled.print(F("Dien ap chan A0"));
oled.setTextSize(3);
oled.setCursor(0, 20);
oled.print(volt, 2);
oled.setTextSize(2);
oled.setCursor(84, 28);
oled.print(F("V"));
oled.drawRect(0, 50, 128, 12, SSD1306_WHITE); // Khung của thanh mức
oled.fillRect(2, 52, rongThanh, 8, SSD1306_WHITE); // Phần tô theo điện áp
oled.display();
delay(200);
}
analogRead(A0)trả về 0–1023 ứng với 0–5 V; chương trình nhân với 5,0 / 1023 để đổi sang vôn.map(giaTri, 0, 1023, 0, 124)đổi giá trị đọc được thành bề rộng phần tô, tính bằng điểm ảnh.drawRect(x, y, rộng, cao, màu)vẽ khung;fillRect()vẽ hình chữ nhật tô kín. Thư viện còn códrawLine(),drawCircle(),drawBitmap()và nhiều lệnh vẽ khác.- Mỗi vòng lặp chương trình xóa bộ đệm, vẽ lại toàn bộ rồi mới gọi
display(), nên hình không bị chồng lên nhau.
Số đo dựa vào nguồn 5 V của Nano làm chuẩn. Khi cấp nguồn qua cổng USB, điện áp này thường thấp hơn 5 V một chút nên số đo có sai lệch nhỏ; chỉ đưa vào A0 điện áp trong khoảng 0–5 V.
8. Xử lý lỗi thường gặp
- Màn hình không hiện gì, Serial Monitor báo "Khong khoi tao duoc OLED!": thiếu RAM cho bộ đệm (mục 6). Bỏ bớt biến và chuỗi trong chương trình rồi thử lại.
- Màn hình không hiện gì và không có thông báo: kiểm tra bốn dây, nhất là SDA vào A4 và SCL vào A5. Nếu dây đúng, màn hình có thể dùng địa chỉ 0x3D; chạy chương trình quét I2C trong bài bắt đầu với Arduino Nano CH340 để biết địa chỉ.
- Hình bị lệch, có dải nhiễu ở mép: màn hình dùng chip SH1106 (thường gặp ở loại 1.3 inch) chứ không phải SSD1306, cần thư viện khác. Xem bài dùng màn hình OLED 1.3 inch SH1106 với ESP32.
- Hình cũ không mất, chữ chồng lên nhau: thiếu lệnh
clearDisplay()trước khi vẽ khung hình mới. - Đã gọi lệnh vẽ mà màn hình không đổi: thiếu lệnh
display(). - Chương trình chạy một lúc rồi treo hoặc hiện ký tự lạ: RAM bị tràn do dùng
Stringhoặc mảng lớn. Giảm lượng RAM sử dụng theo mục 6. - Không nạp được chương trình: chọn lại Processor (thử ATmega328P (Old Bootloader)) và cổng COM theo bài bắt đầu với Arduino Nano.
Xem thêm: dùng màn hình LCD 1602 I2C với Arduino Uno, dùng màn hình OLED SSD1306 với ESP8266 và dùng màn hình OLED 1.3 inch SH1106 với ESP32.
Xem thêm