Trong các dự án nhúng, đặc biệt là với Arduino và màn hình OLED, việc xây dựng một giao diện đơn giản để người dùng lựa chọn các tùy chọn là rất cần thiết. Bài viết này sẽ hướng dẫn bạn cách tạo một menu cuộn trên màn hình OLED sử dụng thư viện Adafruit_SSD1306, kết hợp với nút nhấn vật lý để điều hướng.
Linh kiện cần có
-
1 x Arduino Uno/Nano
-
1 x Màn hình OLED 128x64 (giao tiếp I2C, địa chỉ 0x3C)
-
2 x Nút nhấn (cho UP/DOWN)
-
Dây nối
Sơ đồ kết nối
Code Arduino
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Kích thước màn hình OLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// Cấu hình màn hình OLED
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Cấu hình nút nhấn
#define BUTTON_UP 2
#define BUTTON_DOWN 3
int currentLine = 0; // Vị trí con trỏ trên menu
int topLine = 0; // Vị trí dòng đầu tiên đang hiển thị
const int menuItems = 16; // Tổng số mục menu
// Các mục menu
const char* menu[menuItems] = {
"Option 1",
"Option 2",
"Option 3",
"Option 4",
"Option 5",
"Option 6",
"Option 7",
"Option 8",
"Option 9",
"Option 10",
"Option 11",
"Option 12",
"Option 13",
"Option 14",
"Option 15",
"Option 16"
};
void setup() {
Serial.begin(9600);
pinMode(BUTTON_UP, INPUT_PULLUP);
pinMode(BUTTON_DOWN, INPUT_PULLUP);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Dừng chương trình nếu không tìm thấy màn hình
}
display.clearDisplay();
display.display();
delay(2000);
}
// Hàm vẽ mũi tên
void drawArrow(int x, int y) {
display.fillTriangle(x, y, x, y + 8, x + 6, y + 4, SSD1306_WHITE);
}
void loop() {
// Đọc trạng thái nút nhấn
if (digitalRead(BUTTON_UP) == LOW) {
currentLine = (currentLine - 1 + menuItems) % menuItems; // Lùi lại
if (currentLine < topLine) {
topLine = currentLine; // Cập nhật dòng đầu tiên
} else if (currentLine >= topLine + 6) {
topLine = currentLine - 5;
}
delay(200);
}
if (digitalRead(BUTTON_DOWN) == LOW) {
currentLine = (currentLine + 1) % menuItems; // Tiến tới
if (currentLine >= topLine + 6) {
topLine = currentLine - 5; // Cập nhật dòng đầu tiên
} else if (currentLine < topLine) {
topLine = currentLine;
}
delay(200);
}
displayMenu();
}
void displayMenu() {
display.clearDisplay();
// Vẽ thanh cuộn bên phải
int scrollHeight = map(menuItems, 6, 16, 10, 40); // Chiều cao thanh cuộn
int scrollY = map(topLine, 0, menuItems - 6, 0, 64 - scrollHeight);
display.fillRect(123, scrollY, 3, scrollHeight, SSD1306_WHITE);
// Hiển thị menu
for (int i = 0; i < 6; i++) {
int menuIndex = topLine + i;
if (menuIndex < menuItems) {
if (menuIndex == currentLine) {
// Vẽ mũi tên
drawArrow(0, i * 10);
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Dòng được chọn
} else {
display.setTextColor(SSD1306_WHITE);
}
display.setCursor(15, i * 10); // Căn lề cho tên mục
display.println(menu[menuIndex]);
}
}
display.display();
}
Giải thích code
Khởi tạo OLED và nút nhấn
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define BUTTON_UP 2
#define BUTTON_DOWN 3
OLED có độ phân giải 128x64. Nút nhấn được gán vào chân số 2 và 3, dùng INPUT_PULLUP
.
Danh sách menu
const char* menu[menuItems] = { "Option 1", ..., "Option 16" };
Gồm 16 tùy chọn, mỗi lần hiển thị 6 dòng trên màn hình.
Vẽ mũi tên chỉ dòng đang chọn
void drawArrow(int x, int y) {
display.fillTriangle(x, y, x, y + 8, x + 6, y + 4, SSD1306_WHITE);
}
Tạo một mũi tên tam giác chỉ dòng hiện tại.
Xử lý sự kiện nhấn nút
if (digitalRead(BUTTON_UP) == LOW) { ... }
if (digitalRead(BUTTON_DOWN) == LOW) { ... }
Cho phép cuộn lên/xuống giữa các dòng. Nếu vượt quá phạm vi hiển thị, menu tự động cập nhật topLine
để cuộn danh sách.
Hiển thị menu và thanh cuộn
void displayMenu() {
...
display.fillRect(123, scrollY, 3, scrollHeight, SSD1306_WHITE);
...
}
Thanh cuộn giúp người dùng biết vị trí hiện tại trong danh sách menu dài.
Trải nghiệm giao diện
-
Giao diện đơn giản, hiển thị 6 dòng menu cùng lúc.
-
Dòng đang được chọn có nền trắng, chữ đen và có mũi tên chỉ vào.
-
Dễ dàng điều hướng bằng 2 nút nhấn (lên/xuống).
-
Thanh cuộn động hiển thị trực quan vị trí của menu.
Demo
Click vào nút nhấn để tương tác nhé
Mở rộng thêm
Bạn có thể nâng cấp thêm:
-
Thêm nút Enter để chọn một tùy chọn.
-
Thực hiện hành động tương ứng khi chọn menu.
-
Hiển thị submenu hoặc cài đặt con.
-
Lưu tùy chọn vào EEPROM để ghi nhớ lần sau.
Nhận xét