Hướng dẫn điều khiển màn hình OLED với STM32F103 và chip SSD1306

Giới thiệu về màn hình OLED và giao tiếp với STM32

Màn hình OLED (Organic Light Emitting Diode) là công nghệ hiển thị sử dụng vật liệu hữu cơ phát quang. Module OLED thường được tích hợp sẵn chip điều khiển, phổ biến nhất là SSD1306, với ưu điểm độ tương phản cao, thời gian đáp ứng nhanh, góc nhìn rộng và tiết kiệm năng lượng. Module này thích hợp cho các thiết bị nhúng như đồng hồ thông minh, thiết bị đeo, thiết bị đo lường di động và IoT.

Thông sốMô tả
Độ phân giảiSố pixel, ví dụ 128x64, 128x32
Màu sắcĐơn sắc, hai màu hoặc toàn màu
Kích thước vật lýVí dụ 0.96 inch, 1.3 inch
Giao tiếpSPI, I2C hoặc song song
Điện áp hoạt độngThường 3.3V hoặc 5V
Nhiệt độ hoạt động-40°C đến 85°C
Góc nhìnLên tới 170°
Điều chỉnh độ sángQua phần mềm hoặc PWM

Giao tiếp SPI và I2C với SSD1306

Chip SSD1306 hỗ trợ cả giao tiếp SPI và I2C. Mặc định nhiều module sử dụng SPI, nhưng có thể chuyển sang I2C bằng cách thay đổi vị trí điện trở trên bo mạch (thường là R3 sang R1). SPI sử dụng 3 đường chính: SCK (clock), MOSI (Master Out Slave In), MISO (Master In Slave Out) và thêm chân chip select (CS). I2C chỉ cần hai dây SDA và SCL, giúp tiết kiệm chân GPIO.

Hiển thị chữ và ký tự lên OLED

Để hiển thị chữ, cần có dữ liệu điểm ảnh (bitmap) của từng ký tự. Công cụ phổ biến là PCtoLCD2002, cho phép tạo mã điểm ảnh cho chữ cái, số và tiếng Trung với nhiều kích thước khác nhau (ví dụ 8x16 cho chữ Anh, 16x16 cho chữ Hán).

Các bước cơ bản:

  • Mở phần mềm, chọn chế độ Character Mode.
  • Cài đặt thông số: kích thước chữ (Width và Height), kiểu font, và các tùy chọn khác (thường để mặc định).
  • Nhập ký tự hoặc chuỗi cần tạo mã, nhấn Generate.
  • Sao chép mảng dữ liệu nhị phân vào file header (ví dụ oledfont.h) trong project.

Kết nối phần cứng STM32F103 với OLED SSD1306 (I2C)

Kết nối I2C điển hình:

  • SCL (OLED) -> PB6 (STM32 I2C1_SCL)
  • SDA (OLED) -> PB7 (STM32 I2C1_SDA)
  • VCC -> 3.3V
  • GND -> GND

Thư viện điều khiển OLED cho STM32

File header OLED.h định nghĩa các hàm cơ bản:

#ifndef __OLED_H
#define __OLED_H

void OLED_Init(void);
void OLED_Clear(void);
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowHZ(uint8_t Line, uint8_t Column, uint8_t Index); // hiển thị chữ Hán đã lưu trong mảng

#endif

Ví dụ hàm hiển thị số:

void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length) {
    uint8_t i;
    for (i = 0; i < Length; i++) {
        OLED_ShowChar(Line, Column + i, '0' + (Number / pow10(Length - i - 1)) % 10);
    }
}

Ví dụ 1: Hiển thị mã số sinh viên và tên

#include "stm32f10x.h"
#include "Delay.h"
#include "OLED.h"

int main(void) {
    OLED_Init();
    OLED_ShowHZ(1, 1, 12);   // hiển thị chữ Hán thứ 12 trong mảng
    OLED_ShowHZ(1, 3, 14);
    OLED_ShowHZ(1, 5, 16);
    OLED_ShowString(2, 1, "632107030112");
    while (1);
}

Ví dụ 2: Hiển thị nhiệt độ và độ ẩm từ cảm biến AHT20

#include "stm32f10x.h"
#include "Delay.h"
#include "OLED.h"
#include "dht20.h"

extern unsigned int rec_data[4];

int main(void) {
    OLED_Init();
    uart_init(9600);
    DHT20_Init();
    OLED_ShowHZ(2, 5, 0);  // "Nhiệt"
    OLED_ShowHZ(2, 7, 2);  // "độ"
    OLED_ShowChar(2, 9, ':');
    OLED_ShowHZ(2, 12, 6); // "°C"
    OLED_ShowHZ(4, 5, 8);  // "Độ"
    OLED_ShowHZ(4, 7, 10); // "ẩm"
    OLED_ShowChar(4, 9, ':');
    OLED_ShowChar(4, 12, '%');
    while (1) {
        Delay_ms(1000);
        DHT20_ReadData();
        OLED_ShowNum(2, 10, rec_data[2], 2);
        OLED_ShowNum(4, 10, rec_data[0], 2);
    }
}

Ví dụ 3: Cuộn chữ ngang (horizontal scroll)

void OLED_Scroll_Setup(void) {
    OLED_WriteCmd(0x2E);   // tắt cuộn
    OLED_WriteCmd(0x27);   // cuộn ngang phải (0x26 là trái)
    OLED_WriteCmd(0x00);   // dummy byte
    OLED_WriteCmd(0x00);   // trang bắt đầu (page 0)
    OLED_WriteCmd(0x07);   // tốc độ cuộn
    OLED_WriteCmd(0x07);   // trang kết thúc (page 7)
    OLED_WriteCmd(0x00);   // dummy
    OLED_WriteCmd(0xFF);   // dummy
    // Hiển thị nội dung cần cuộn
    OLED_ShowString(0, 0, "Dong chu that dai can cuon ngang tren man hinh OLED");
    OLED_WriteCmd(0x2F);   // bắt đầu cuộn
}

Mẹo: Di chuyển ký tự thủ công thay vì cuộn

Có thể tạo hiệu ứng chạy chữ bằng cách liên tục xóa và vẽ lại ở vị trí mới:

int main(void) {
    OLED_Init();
    while (1) {
        for (int i = 1; i <= 8; i++) {
            OLED_ShowHZ(2, i, 18);
            OLED_ShowHZ(2, i+2, 20);
            OLED_ShowString(3, i, "Hello!");
            Delay_ms(50);
            OLED_Clear();
        }
    }
}

Cách này tuy đơn giản nhưng tốn thời gian xử lý và có thể gây nhấp nháy nếu không tối ưu.

So sánh phương pháp điều khiển OLED

Phương phápƯu điểmNhược điểm
Gửi lệnh trực tiếpKiểm soát chi tiết, không phụ thuộc thư việnMã dài, dễ sai, tốn CPU
Sử dụng thư viện/driverMã gọn, dễ bảo trì, tối ưu hơnPhải hiểu API, kích thước firmware lớn hơn

Thẻ: STM32F103 SSD1306 OLED I2C SPI

Đăng vào ngày 18 tháng 6 lúc 08:30