Bạn có thể tham khảo & mua linh kiện tại đây:
- Mạch Arduino UNO R3
- Màn hình Oled I2C SSD1360 0.96 inch
- Test board (Breadboard)
- Dây cắm test board
- Điện trở 4.7k ôm
Giới thiệu màn hình OLED 0.96 inch
Màn OLED (organic light-emitting diode ) mà chúng tôi sẽ sử dụng trong hướng dẫn này là model SSD1306: màn hình đơn sắc, 0,96 inch với 128 × 64 pixel như trong hình dưới đây.
Màn hình OLED không yêu cầu đèn nền, tuy nhiên nó vẫn hiển thị tốt trong tối.
Ngoài ra, các pixel của nó chỉ tiêu thụ năng lượng khi hoạt đồng, vì vậy màn hình OLED tiêu thụ ít năng lượng hơn khi so sánh với các màn hình khác.
Sơ đồ mà chúng tôi sử dụng ở đây chỉ có bốn chân và giao tiếp với Arduino bằng giao thức truyền thông I2C.
Có những sơ đồ đi kèm với một chân RESET thêm.
Pin | Nối với chân trong Arduino Uno |
Vin | 5V |
GND | GND |
SCL | A5 |
SDA | A4 |
Nếu bạn sử dụng một bo mạch Arduino khác, hãy đảm bảo bạn kiểm tra các chân I2C chính xác:
Để điều khiển màn hình OLED, bạn cần cài thư viện adafruit_SSD1306.h và thư viện adafruit_GFX.h nếu đã có sẵn thì bỏ qua bước này. Thực hiện theo các hướng dẫn bên dưới để cài đặt các thư viện.
1. Mở phần mềm Arduino IDE và vào Sketch > Include Library > Manage Libraries. Trình quản lý thư viện (Library Manager) sẽ mở.
2. Nhập vào “SSD1306”, trong hộp tìm kiếm và cài đặt thư viện SSD1306 từ Adafruit.
3. Sau khi cài đặt thư viện SSD1306 từ Adafruit, hãy nhập “GFX” trực tiếp vào hộp tìm kiếm và cài đặt thư viện.
4. Sau khi cài đặt các thư viện, hãy thoát và mở lại phần mềm Arduino IDE.
Mẹo viết văn bản bằng các thư viện này
Ở đây, một số chức năng sẽ giúp bạn xử lý thư viện màn hình OLED để viết văn bản hoặc vẽ đồ họa đơn giản.
- display.clearDisplay() – tắt tất cả các điểm ảnh (pixels)
- display.drawPixel(x,y, color) – vẽ một điểm ảnh theo tọa độ x, y
- display.setTextSize(n) – Đặt kích thước phông chữ, hỗ trợ kích thước từ 1 đến 8
- display.setCursor(x,y) – đặt tọa độ để bắt đầu viết văn bản
- display.print(“message”) – in các ký tự tại vị trí x, y
- display.display() – gọi phương thức này để thay đổi có hiệu lực
Kiểm tra màn hình OLED
Sau khi kết nối màn hình OLED với Arduino và cài đặt tất cả các thư viện cần thiết, bạn có thể sử dụng một ví dụ từ thư viện để xem màn hình có hoạt động tốt không.
Tiếp theo nên nạp đoạn code sau:
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define NUMFLAKES 10 // Number of snowflakes in the animation example
#define LOGO_HEIGHT 16
#define LOGO_WIDTH 16
static const unsigned char PROGMEM logo_bmp[] =
{ B00000000, B11000000,
B00000001, B11000000,
B00000001, B11000000,
B00000011, B11100000,
B11110011, B11100000,
B11111110, B11111000,
B01111110, B11111111,
B00110011, B10011111,
B00011111, B11111100,
B00001101, B01110000,
B00011011, B10100000,
B00111111, B11100000,
B00111111, B11110000,
B01111100, B11110000,
B01110000, B01110000,
B00000000, B00110000 };
void setup() {
Serial.begin(115200);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
// Show initial display buffer contents on the screen --
// the library initializes this with an Adafruit splash screen.
display.display();
delay(2000); // Pause for 2 seconds
// Clear the buffer
display.clearDisplay();
// Draw a single pixel in white
display.drawPixel(10, 10, WHITE);
// Show the display buffer on the screen. You MUST call display() after
// drawing commands to make them visible on screen!
display.display();
delay(2000);
// display.display() is NOT necessary after every single drawing command,
// unless that's what you want...rather, you can batch up a bunch of
// drawing operations and then update the screen all at once by calling
// display.display(). These examples demonstrate both approaches...
testdrawline(); // Draw many lines
testdrawrect(); // Draw rectangles (outlines)
testfillrect(); // Draw rectangles (filled)
testdrawcircle(); // Draw circles (outlines)
testfillcircle(); // Draw circles (filled)
testdrawroundrect(); // Draw rounded rectangles (outlines)
testfillroundrect(); // Draw rounded rectangles (filled)
testdrawtriangle(); // Draw triangles (outlines)
testfilltriangle(); // Draw triangles (filled)
testdrawchar(); // Draw characters of the default font
testdrawstyles(); // Draw 'stylized' characters
testscrolltext(); // Draw scrolling text
testdrawbitmap(); // Draw a small bitmap image
// Invert and restore display, pausing in-between
display.invertDisplay(true);
delay(1000);
display.invertDisplay(false);
delay(1000);
testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps
}
void loop() {
}
void testdrawline() {
int16_t i;
display.clearDisplay(); // Clear display buffer
for(i=0; i<display.width(); i+=4) {
display.drawLine(0, 0, i, display.height()-1, WHITE);
display.display(); // Update screen with each newly-drawn line
delay(1);
}
for(i=0; i<display.height(); i+=4) {
display.drawLine(0, 0, display.width()-1, i, WHITE);
display.display();
delay(1);
}
delay(250);
display.clearDisplay();
for(i=0; i<display.width(); i+=4) {
display.drawLine(0, display.height()-1, i, 0, WHITE);
display.display();
delay(1);
}
for(i=display.height()-1; i>=0; i-=4) {
display.drawLine(0, display.height()-1, display.width()-1, i, WHITE);
display.display();
delay(1);
}
delay(250);
display.clearDisplay();
for(i=display.width()-1; i>=0; i-=4) {
display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE);
display.display();
delay(1);
}
for(i=display.height()-1; i>=0; i-=4) {
display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE);
display.display();
delay(1);
}
delay(250);
display.clearDisplay();
for(i=0; i<display.height(); i+=4) {
display.drawLine(display.width()-1, 0, 0, i, WHITE);
display.display();
delay(1);
}
for(i=0; i<display.width(); i+=4) {
display.drawLine(display.width()-1, 0, i, display.height()-1, WHITE);
display.display();
delay(1);
}
delay(2000); // Pause for 2 seconds
}
void testdrawrect(void) {
display.clearDisplay();
for(int16_t i=0; i<display.height()/2; i+=2) {
display.drawRect(i, i, display.width()-2*i, display.height()-2*i, WHITE);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
}
delay(2000);
}
void testfillrect(void) {
display.clearDisplay();
for(int16_t i=0; i<display.height()/2; i+=3) {
// The INVERSE color is used so rectangles alternate white/black
display.fillRect(i, i, display.width()-i*2, display.height()-i*2, INVERSE);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
}
delay(2000);
}
void testdrawcircle(void) {
display.clearDisplay();
for(int16_t i=0; i<max(display.width(),display.height())/2; i+=2) {
display.drawCircle(display.width()/2, display.height()/2, i, WHITE);
display.display();
delay(1);
}
delay(2000);
}
void testfillcircle(void) {
display.clearDisplay();
for(int16_t i=max(display.width(),display.height())/2; i>0; i-=3) {
// The INVERSE color is used so circles alternate white/black
display.fillCircle(display.width() / 2, display.height() / 2, i, INVERSE);
display.display(); // Update screen with each newly-drawn circle
delay(1);
}
delay(2000);
}
void testdrawroundrect(void) {
display.clearDisplay();
for(int16_t i=0; i<display.height()/2-2; i+=2) {
display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i,
display.height()/4, WHITE);
display.display();
delay(1);
}
delay(2000);
}
void testfillroundrect(void) {
display.clearDisplay();
for(int16_t i=0; i<display.height()/2-2; i+=2) {
// The INVERSE color is used so round-rects alternate white/black
display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i,
display.height()/4, INVERSE);
display.display();
delay(1);
}
delay(2000);
}
void testdrawtriangle(void) {
display.clearDisplay();
for(int16_t i=0; i<max(display.width(),display.height())/2; i+=5) {
display.drawTriangle(
display.width()/2 , display.height()/2-i,
display.width()/2-i, display.height()/2+i,
display.width()/2+i, display.height()/2+i, WHITE);
display.display();
delay(1);
}
delay(2000);
}
void testfilltriangle(void) {
display.clearDisplay();
for(int16_t i=max(display.width(),display.height())/2; i>0; i-=5) {
// The INVERSE color is used so triangles alternate white/black
display.fillTriangle(
display.width()/2 , display.height()/2-i,
display.width()/2-i, display.height()/2+i,
display.width()/2+i, display.height()/2+i, INVERSE);
display.display();
delay(1);
}
delay(2000);
}
void testdrawchar(void) {
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font
// Not all the characters will fit on the display. This is normal.
// Library will draw what it can and the rest will be clipped.
for(int16_t i=0; i<256; i++) {
if(i == '\n') display.write(' ');
else display.write(i);
}
display.display();
delay(2000);
}
void testdrawstyles(void) {
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(WHITE); // Draw white text
display.setCursor(0,0); // Start at top-left corner
display.println(F("Hello, world!"));
display.setTextColor(BLACK, WHITE); // Draw 'inverse' text
display.println(3.141592);
display.setTextSize(2); // Draw 2X-scale text
display.setTextColor(WHITE);
display.print(F("0x")); display.println(0xDEADBEEF, HEX);
display.display();
delay(2000);
}
void testscrolltext(void) {
display.clearDisplay();
display.setTextSize(2); // Draw 2X-scale text
display.setTextColor(WHITE);
display.setCursor(10, 0);
display.println(F("scroll"));
display.display(); // Show initial text
delay(100);
// Scroll in various directions, pausing in-between:
display.startscrollright(0x00, 0x0F);
delay(2000);
display.stopscroll();
delay(1000);
display.startscrollleft(0x00, 0x0F);
delay(2000);
display.stopscroll();
delay(1000);
display.startscrolldiagright(0x00, 0x07);
delay(2000);
display.startscrolldiagleft(0x00, 0x07);
delay(2000);
display.stopscroll();
delay(1000);
}
void testdrawbitmap(void) {
display.clearDisplay();
display.drawBitmap(
(display.width() - LOGO_WIDTH ) / 2,
(display.height() - LOGO_HEIGHT) / 2,
logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
display.display();
delay(1000);
}
#define XPOS 0 // Indexes into the 'icons' array in function below
#define YPOS 1
#define DELTAY 2
void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
int8_t f, icons[NUMFLAKES][3];
// Initialize 'snowflake' positions
for(f=0; f< NUMFLAKES; f++) {
icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width());
icons[f][YPOS] = -LOGO_HEIGHT;
icons[f][DELTAY] = random(1, 6);
Serial.print(F("x: "));
Serial.print(icons[f][XPOS], DEC);
Serial.print(F(" y: "));
Serial.print(icons[f][YPOS], DEC);
Serial.print(F(" dy: "));
Serial.println(icons[f][DELTAY], DEC);
}
for(;;) { // Loop forever...
display.clearDisplay(); // Clear the display buffer
// Draw each snowflake:
for(f=0; f< NUMFLAKES; f++) {
display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, WHITE);
}
display.display(); // Show the display buffer on the screen
delay(200); // Pause for 1/10 second
// Then update coordinates of each flake...
for(f=0; f< NUMFLAKES; f++) {
icons[f][YPOS] += icons[f][DELTAY];
// If snowflake is off the bottom of the screen...
if (icons[f][YPOS] >= display.height()) {
// Reinitialize to a random position, just off the top
icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width());
icons[f][YPOS] = -LOGO_HEIGHT;
icons[f][DELTAY] = random(1, 6);
}
}
}
}
Nếu OLED của bạn không có chân RESET, bạn nên đặt biến OLED_RESET thành -1 như dưới đây:
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Nạp code vào board Arduino của bạn. Đừng quên chọn đúng board và cổng COM bên phải trong menu Tools
Nếu màn hình OLED của bạn không hiển thị bất cứ điều gì:
- Kiểm tra xem màn hình OLED có được kết nối đúng với Arduino không
- Kiểm tra kỹ địa chỉ I2C của màn hình OLED: với OLED được kết nối với Arduino, nạp lại mã này và kiểm tra địa chỉ I2C trong Serial Monitor
Bạn nên thay đổi địa chỉ OLED trong dòng sau, nếu cần. Trong trường hợp của chúng tôi, địa chỉ là 0x3C.
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Viết chữ trên màn hình OLED
Dòng code dưới đây để hiển thị chữ Hello, world! trên màn hình OLED
Trong trường hợp bạn sử dụng màn hình OLED khác, bạn có thể cần thay đổi địa chỉ OLED. Trong trường hợp của chúng tôi, địa chỉ là 0x3C.
Dòng code dưới đây để hiển thị chữ Hello, world! trên màn hình OLED
/*********
Rui Santos
Complete project details at https://randomnerdtutorials.com
*********/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
void setup() {
Serial.begin(115200);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 10);
// Display static text
display.println("Hello, world!");
display.display();
}
void loop() {
}
Sau khi nạp code, màn hình Oled sẽ hiển thị như hình dưới đây:
Cài đặt thư viện
Đầu tiên, bạn cần cài thư viện cần thiết. Thư viện Wire để sử dụng thư viện I2C và thư viện Adafruit để ghi vào màn hình: Adafruit_GFX và Adafruit_SSD1306.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Khởi tạo màn hình OLED
Sau đó, bạn xác định kích thước OLED của bạn. Trong ví dụ này, chúng ta sử dụng màn hình OLED 128 × 64. Nếu bạn sử dụng các kích thước khác, bạn có thể thay đổi nó trong các biến SCREEN_WIDTH và SCREEN_HEIGHT.
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Sau đó, khởi tạo một đối tượng hiển thị với kích thước được xác định trước đó với giao thức truyền thông I2C (&Wire).
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
Tham số (-1) có nghĩa là màn hình OLED của bạn không có chân RESET. Nếu màn hình OLED của bạn có chân RESET, thì nó sẽ được kết nối với GPIO. Trong trường hợp đó, bạn nên truyền số GPIO làm tham số.
Trong setup(), khởi chạy Serial Monitor với baud raute 115200 cho mục đích gỡ lỗi.
Serial.begin(115200);
Khởi tạo màn hình OLED bằng phương thức begin() như sau:
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("SSD1306 allocation failed");
for(;;); // Don't proceed, loop forever
}
Đoạn mã này cũng in một thông báo trên Serial Monitor, trong trường hợp chúng ta không thể kết nối với màn hình.
Serial.println("SSD1306 allocation failed");
Nếu địa chỉ này không hoạt động, bạn có thể chạy code quét I2C để tìm địa chỉ OLED của mình. Bạn có thể tải code quét địa chỉ I2C tại đây.
Sau khi khởi tạo màn hình, hãy thêm độ trễ màn 2 giây để OLED có đủ thời gian để khởi tạo trước khi viết văn bản:
delay(2000);
Xóa màn hình, đặt kích thước phông chữ, màu sắc và viết văn bản
display.clearDisplay();
Trước khi viết văn bản, bạn cần đặt kích thước văn bản, màu sắc và nơi văn bản sẽ được hiển thị trong OLED.
Đặt kích thước phông chữ bằng cách sử dụng hàm setTextSize():
display.setTextSize(1);
Đặt màu phông chữ bằng hàm setTextColor():
display.setTextColor(WHITE);
WHITE đặt phông chữ màu trắng và nền đen.
Xác định vị trí nơi văn bản bắt đầu sử dụng hàm setCursor(x,y). Trong trường hợp này, chúng tôi cài đặt văn bản để bắt đầu ở tọa độ (0,10).
display.setCursor(0,10);
Cuối cùng, bạn có thể hiển thị chữ lên màn hình bằng hàm println(), như sau:
display.println("Hello, world!");
Sau đó, bạn cần gọi hàm display() để thực sự hiển thị văn bản trên màn hình.
display.display();
Xem tiếp phần 2: Cách tạo một số hiệu ứng chữ dịch chuyển trên Oled, thay đổi font chữ và vẽ hình trên màn hình OLED.
Post a Comment