Màn hình OLED SSD1306 được sử dụng rất nhiều trong các ứng dụng nhúng: hiển thị đẹp mắt, tiết kiệm năng lượng và hỗ trợ chuẩn kết nối I2C, rất phù hợp với những ứng dụng nhỏ.
Bài này nằm trong Serie Học STM32 từ A tới Z
Màn hình Oled là gì?
Màn hình OLED (Organic Light Emitting Diodes) là màn hình dùng diode phát quang hữu cơ. Mỗi điểm ảnh là một lớp vật liệu hữu cơ mỏng, tự phát sáng khi có dòng điện chạy qua, nên OLED không cần đèn nền như LCD. Điểm ảnh nào tắt thì không tiêu thụ điện, vì vậy OLED hiển thị màu đen rất sâu và tiết kiệm năng lượng.

Cấu tạo của màn hình OLED
Về cơ bản, một màn hình OLED sẽ bao gồm 4 thành phần chính sau:
Tấm nền
Được chế tạo bằng thủy tinh hay nhựa, có chức năng nâng đỡ cho các bộ phận khác của OLED.
Anode
Điện cực dương, khi có dòng điện sẽ đưa các lỗ trống (điện tích dương) vào lớp hữu cơ.
Cathode
Ngược lại với Anode, Cathode là điện cực âm, đưa các electron vào lớp hữu cơ khi có dòng điện đi qua.
Lớp hữu cơ
Bao gồm hai lớp với chức năng riêng biệt: Lớp dẫn: cấu tạo từ các phân tử hữu cơ, giúp vận chuyển lỗ trống từ Anode. Lớp phát xạ: electron từ Cathode đi tới đây, gặp và tái hợp với lỗ trống, năng lượng giải phóng ra dưới dạng ánh sáng.
Thông số cơ bản về LCD Oled SSD1306
Màn hình OLED SSD1306 kích thước 0.96 inch cho khả năng hiển thị hình ảnh tốt với độ phân giải 128×64 pixel. Ngoài ra, màn hình còn tương thích với hầu hết các vi điều khiển hiện nay thông qua giao tiếp I2C. Màn hình sử dụng driver SSD1306 cùng thiết kế nhỏ gọn sẽ giúp bạn phát triển các sản phẩm DIY hoặc các ứng dụng khác một cách nhanh chóng.
Lưu ý: Trên thị trường có loại OLED dùng chip SH1106 nhìn bề ngoài gần như giống hệt SSD1306, nhưng RAM hiển thị là 132×64 và một số lệnh khác SSD1306. Dùng thư viện SSD1306 cho SH1106 sẽ thấy hình bị lệch 2 cột và có 1 dải nhiễu ở mép màn hình, nên các bạn hỏi kỹ người bán trước khi mua nhé.

Thông số kĩ thuật
- Driver: SSD1306
- Tương thích với Arduino, 8051, MSP430, STM32, CSR IC,…
- Tiêu thụ điện năng thấp: 0.08W (sáng toàn màn hình)
- Có thể điều chỉnh độ sáng và độ tương phản
- Chuẩn giao tiếp: I2C (thông qua 2 chân SCL, SDA)
- Điện áp hoạt động của module: 3V – 5V DC
- Nhiệt độ hoạt động: -30℃ – 70℃
- Kích thước màn hình: 0.96 inch (128×64 pixel)
- Kích thước module: 26.70 x 19.26 x 1.85mm (1.03 x 0.76 x 0.07 inch)
Trong bài viết này chúng ta dùng module OLED SSD1306 giao tiếp I2C với STM32.
Cách điều khiển LCD Oled SSD1306
Sơ đồ khối

Các giao thức điều khiển
Để chuẩn bị cho việc sử dụng OLED SSD1306, các bạn tải datasheet của nó về tại: https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
Chip SSD1306 có 8 chân dữ liệu D0 – D7 và 5 chân điều khiển: RES#, CS#, D/C#, E (RD#), R/W# (WR#).
Có 5 giao thức điều khiển SSD1306, được chọn bởi các bit BS[2:0], lần lượt là:
- Giao thức song song 8 bit: 8080
- Giao thức song song 8 bit: 6800
- Giao thức SPI 3 dây
- Giao thức SPI 4 dây
- Giao thức I2C

Trong bài này mình chỉ đề cập tới giao thức I2C, các giao thức khác các bạn tham khảo trong datasheet nhé.
Giao thức I2C điều khiển ssd1306
Trong giao thức này chân D2 là SDA out, D1 là SDA in, D0 là SCL (trên module 4 chân, D1 và D2 đã được nối chung thành chân SDA). Nếu các bạn chỉ ghi vào OLED thì chỉ cần sử dụng chân SDA in và SCL là đủ. Các chân I2C này bắt buộc phải có điện trở kéo lên VCC theo đúng chuẩn I2C.
Khi truyền địa chỉ để giao tiếp I2C chúng ta sẽ truyền 1 byte như sau:
b7 b6 b5 b4 b3 b2 b1 b0
0 1 1 1 1 0 SA0 R/W#
Chân SA0 sẽ chọn địa chỉ cho SSD1306: SA0 = 0 thì địa chỉ 7 bit là 0x3C, SA0 = 1 thì là 0x3D. Vì vậy chúng ta có thể giao tiếp với 2 màn OLED trên cùng 1 bus I2C.
Bit b0 sẽ quy định việc đọc hoặc ghi vào OLED.
Lưu ý: Khi dùng HAL, địa chỉ truyền vào hàm HAL_I2C_Master_Transmit() phải là địa chỉ 7 bit đã dịch trái 1 bit, tức là 0x78 (0x3C << 1). Truyền 0x3C trực tiếp thì màn hình sẽ không phản hồi. Một số module in sẵn chữ “0x78” ở mặt sau chính là địa chỉ đã dịch này.

Các bước giao tiếp như sau:
- Điều kiện bắt đầu (Start) được thiết lập bằng cách kéo SDA từ CAO xuống THẤP trong khi SCL vẫn CAO
- Ngay sau đó Master gửi 8 bit gồm 7 bit địa chỉ + 1 bit R/W để quy định việc đọc hoặc ghi. Chế độ ghi thì bit R/W = 0
- Nếu SSD1306 nhận đúng địa chỉ sẽ kéo SDA xuống 0 để trả lời (bit ACK)
- Sau khi nhận ACK, Master truyền 1 byte điều khiển (control byte) gồm bit Co, bit D/C# và 6 bit 0. Nếu Co = 0 thì các byte phía sau chỉ chứa dữ liệu. Nếu D/C# = 0 là truyền lệnh cho SSD1306, nếu D/C# = 1 là truyền dữ liệu vào GDDRAM (hiển thị ra màn hình). Địa chỉ ô nhớ GDDRAM tự động tăng mỗi khi ghi 1 byte dữ liệu.
- Bit ACK sẽ được tạo ra mỗi khi truyền xong 1 byte
- Cuối cùng điều kiện dừng (Stop) được thiết lập bằng cách kéo SDA từ THẤP lên CAO trong khi SCL vẫn ở mức CAO
Bảng sau đây sẽ định nghĩa điều kiện bắt đầu/kết thúc:

Nhìn chung SSD1306 giao tiếp theo đúng chuẩn I2C, quan trọng là các bạn biết phải truyền gì vào trong đó.
Display RAM và cách hiển thị của ssd1306
Màn hình OLED SSD1306 có độ phân giải 128×64 điểm, RAM hiển thị được chia thành 8 Page, từ Page0 tới Page7, mỗi Page cao 8 điểm.
Mỗi Page lại được chia thành các cột Segment từ SEG0 tới SEG127. Mỗi byte ghi vào sẽ điều khiển 1 cột 8 điểm theo chiều dọc của Page đó (bit 0 ở trên cùng, bit 7 ở dưới cùng).

Khi bắt đầu ghi vào OLED, con trỏ sẽ ở SEG0 và PAGE0 (nếu không có lệnh xoay màn hình).
Mỗi khi một byte được ghi vào GDDRAM, con trỏ cột (Column) sẽ tăng lên 1 đơn vị. Ở chế độ Horizontal Addressing, khi hết 1 Page con trỏ sẽ tự động nhảy xuống Page phía dưới, nên dữ liệu được quét từ trái qua phải, từ trên xuống dưới. Còn ở chế độ Page Addressing (mặc định sau reset), hết 1 Page con trỏ quay lại cột 0 của chính Page đó, muốn sang Page khác phải gửi lệnh đặt lại Page.

Các lệnh và khởi tạo oled ssd1306
Chi tiết về tập lệnh cho SSD1306 các bạn tham khảo mục 10 COMMAND DESCRIPTIONS trong datasheet nhé.
Để khởi tạo cho SSD1306 hoạt động, chúng ta làm theo flow chart sau:

Lập trình STM32 điều khiển LCD ssd1306
Cấu hình trên cubemx
Trong CubeMX chọn STM32F103C8, tab SYS chọn Debug Serial Wire. RCC chọn thạch anh ngoài và trong Clock Configuration các bạn để tần số hệ thống 72MHz nhé.
Trong tab I2C1 chọn I2C để enable lên.

Sau đó Gen code như các bài trước.
Kết nối phần cứng: OLED GND → GND, VCC → 3.3V, SCL → PB6, SDA → PB7 (chân mặc định của I2C1).
Download thư viện và lập trình
Sau khi Gen code chúng ta sẽ mở bằng Keil C. Để download thư viện các bạn hãy đọc bài viết: Hướng dẫn download thư viện STM32
Sau khi tải về, các bạn chỉnh đường dẫn tới thư viện Device.

Trong project click chuột phải -> Add file. Thêm các file ssd1306 chứa thư viện, fonts chứa bộ font chữ, và test chứa các hàm test cho màn hình.

Thêm các thư viện vào main.c gồm:
- Thư viện SSD1306
- Font chữ cho màn hình
- File logo Nike đã convert
- Ảnh động 1 – 9.

Tạo một biến struct SSD1306

Khởi tạo SSD1306 với phương thức giao tiếp là I2C1

Hiển thị văn bản và các hình cơ bản trong LCD
Để vẽ các hình cơ bản chúng ta sử dụng các hàm đồ họa như: DrawLine, DrawCircle, DrawRectangle….
Để viết chữ chúng ta sử dụng hàm Puts và truyền vào chuỗi text, loại font và màu sắc.
Lưu ý: Mỗi khi sử dụng các hàm vẽ thì dữ liệu chỉ được ghi vào bộ nhớ đệm (buffer) trong RAM của STM32. Để hiển thị lên màn hình chúng ta phải gọi hàm UpdateScreen nhé!

Hiển thị ảnh với ssd1306
Tương tự, để hiển thị ảnh chúng ta sử dụng hàm DrawBitmap, truyền vào tọa độ bắt đầu, kích thước ảnh, mảng chứa dữ liệu bitmap và màu sắc.

Hiển thị ảnh động GIF với ssd1306
Ảnh động thực ra là chuỗi các ảnh được hiển thị liên tục, giống như cuốn sách lật trang vẽ hình (flipbook) vậy. Chúng ta sẽ cho nó vào 1 vòng while với số lần lặp lại được quy định trong biến loop.

Cách chuyển ảnh sang mảng để hiển thị
Tải ảnh cần convert, chỉnh lại kích thước theo đúng mong muốn bằng Photoshop. Chúng ta có thể dùng công cụ Image Size (phóng to thu nhỏ theo kích thước) và Canvas Size (thêm hoặc cắt ảnh theo kích thước).


Download công cụ Image2LCD tại đây: https://www.fshare.vn/file/Q8NDJBO9ZU2F
Mở phần mềm:
- Nhấn Open, mở ảnh vừa chỉnh trong Photoshop
- Chọn các tùy chọn như hình gồm: kiểu quét, chế độ màu, độ phân giải, các tùy chọn khác
- Nhấn Save, lưu thành file .h, nhớ trỏ vào trong thư mục Inc trong project của bạn nhé.

Trong main.c thêm #include "Tên_File.h" là có thể sử dụng được rồi.
Đây là kết quả của mình.
Kết
Màn hình OLED SSD1306 rất phù hợp dùng trong các ứng dụng nhỏ gọn, độ phân giải và chất lượng hiển thị của nó cũng tương đối ổn. Ngoài I2C, SSD1306 còn có thể giao tiếp theo các phương thức khác như SPI, giúp tốc độ cập nhật màn hình nhanh hơn rất nhiều.
Nếu thấy bài viết này hay, hãy chia sẻ tới những người bạn học hay đồng nghiệp của mình. Và nếu thắc mắc điều gì, hãy để lại bình luận nhé.
Và cùng gia nhập những người nghiện lập trình tại đây nhé: Hội anh em nghiện lập trình


minh làm theo nhưng không được, màn hình hiển thị lấm tấm. Code arduino chạy được, hình như phần i2c bị treo, nếu được nhờ tác giả chỉ dẩn