STM32F系列驱动OLED屏幕(I2C/SPI接口)代码

1. OLED驱动头文件定义

1.1 OLED通用定义 (oled.h)

#ifndef __OLED_H
#define __OLED_H

#include "stm32f1xx_hal.h"
#include "fonts.h"
#include <string.h>
#include <stdarg.h>

// OLED参数定义
#define OLED_WIDTH          128
#define OLED_HEIGHT         64
#define OLED_PAGE_NUM       8      // OLED有8页,每页8行
#define OLED_BUFFER_SIZE    (OLED_WIDTH * OLED_PAGE_NUM)  // 128 * 8 = 1024字节

// 通信接口选择
#define OLED_USE_I2C        1      // 1:使用I2C, 0:使用SPI
#define OLED_USE_HARDWARE   1      // 1:硬件接口, 0:软件模拟

// 颜色定义
#define OLED_COLOR_WHITE    1
#define OLED_COLOR_BLACK    0

// 屏幕旋转方向
typedef enum {
    OLED_ROTATION_0 = 0,     // 0度
    OLED_ROTATION_90,        // 90度
    OLED_ROTATION_180,       // 180度
    OLED_RPTATION_270        // 270度
} OLED_Rotation;

// 显示模式
typedef enum {
    OLED_DISPLAY_NORMAL = 0,  // 正常显示
    OLED_DISPLAY_INVERT,      // 反色显示
    OLED_DISPLAY_OFF,         // 关闭显示
    OLED_DISPLAY_ON           // 开启显示
} OLED_DisplayMode;

// OLED控制命令
#define OLED_CMD_SET_COL_ADDR          0x21
#define OLED_CMD_SET_PAGE_ADDR         0x22
#define OLED_CMD_SET_START_LINE        0x40
#define OLED_CMD_SET_CONTRAST          0x81
#define OLED_CMD_CHARGE_PUMP           0x8D
#define OLED_CMD_SEG_REMAP             0xA0
#define OLED_CMD_DISPLAY_ALL_ON_RESUME 0xA4
#define OLED_CMD_DISPLAY_ALL_ON        0xA5
#define OLED_CMD_NORMAL_DISPLAY        0xA6
#define OLED_CMD_INVERT_DISPLAY        0xA7
#define OLED_CMD_SET_MULTIPLEX         0xA8
#define OLED_CMD_DISPLAY_OFF           0xAE
#define OLED_CMD_DISPLAY_ON            0xAF
#define OLED_CMD_SET_PAGE_START        0xB0
#define OLED_CMD_COM_SCAN_DIR          0xC0
#define OLED_CMD_SET_DISPLAY_OFFSET    0xD3
#define OLED_CMD_SET_DISPLAY_CLOCK     0xD5
#define OLED_CMD_SET_PRECHARGE         0xD9
#define OLED_CMD_SET_COM_PINS          0xDA
#define OLED_CMD_SET_VCOM_DESELECT     0xDB

// OLED结构体
typedef struct {
    uint8_t buffer[OLED_BUFFER_SIZE];  // 显示缓冲区
    uint16_t width;                    // 屏幕宽度
    uint16_t height;                   // 屏幕高度
    uint8_t rotation;                  // 旋转角度
    uint8_t invert_color;              // 反色标志
    uint8_t initialized;               // 初始化标志
    
    // 当前光标位置
    uint16_t current_x;
    uint16_t current_y;
    
    // 当前字体
    const FontDef* current_font;
    
    // 硬件接口
#if OLED_USE_I2C
    I2C_HandleTypeDef* hi2c;           // I2C句柄
    uint8_t i2c_addr;                  // I2C地址
#else
    SPI_HandleTypeDef* hspi;           // SPI句柄
    GPIO_TypeDef* cs_port;             // 片选端口
    uint16_t cs_pin;                   // 片选引脚
    GPIO_TypeDef* dc_port;             // 数据/命令选择端口
    uint16_t dc_pin;                   // 数据/命令选择引脚
    GPIO_TypeDef* res_port;            // 复位端口
    uint16_t res_pin;                  // 复位引脚
#endif
} OLED_HandleTypeDef;

// 函数声明
// 初始化函数
void OLED_Init(OLED_HandleTypeDef* hdev);
void OLED_DeInit(OLED_HandleTypeDef* hdev);
uint8_t OLED_IsInitialized(OLED_HandleTypeDef* hdev);

// 基本控制函数
void OLED_DisplayOn(OLED_HandleTypeDef* hdev);
void OLED_DisplayOff(OLED_HandleTypeDef* hdev);
void OLED_SetContrast(OLED_HandleTypeDef* hdev, uint8_t contrast);
void OLED_SetDisplayMode(OLED_HandleTypeDef* hdev, OLED_DisplayMode mode);
void OLED_SetRotation(OLED_HandleTypeDef* hdev, OLED_Rotation rotation);
void OLED_InvertDisplay(OLED_HandleTypeDef* hdev, uint8_t invert);

// 缓冲区操作函数
void OLED_ClearBuffer(OLED_HandleTypeDef* hdev, uint8_t color);
void OLED_UpdateScreen(OLED_HandleTypeDef* hdev);
void OLED_DrawPixel(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, uint8_t color);
void OLED_GetPixel(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y);

// 绘图函数
void OLED_DrawLine(OLED_HandleTypeDef* hdev, uint16_t x0, uint16_t y0, 
                   uint16_t x1, uint16_t y1, uint8_t color);
void OLED_DrawRectangle(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                       uint16_t width, uint16_t height, uint8_t color);
void OLED_DrawFilledRectangle(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                             uint16_t width, uint16_t height, uint8_t color);
void OLED_DrawCircle(OLED_HandleTypeDef* hdev, uint16_t x0, uint16_t y0, 
                    uint16_t radius, uint8_t color);
void OLED_DrawFilledCircle(OLED_HandleTypeDef* hdev, uint16_t x0, uint16_t y0, 
                          uint16_t radius, uint8_t color);
void OLED_DrawTriangle(OLED_HandleTypeDef* hdev, uint16_t x1, uint16_t y1,
                      uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint8_t color);
void OLED_DrawArc(OLED_HandleTypeDef* hdev, uint16_t x0, uint16_t y0, 
                 uint16_t radius, uint16_t start_angle, uint16_t end_angle, uint8_t color);

// 位图函数
void OLED_DrawBitmap(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                    const uint8_t* bitmap, uint16_t width, uint16_t height, uint8_t color);
void OLED_DrawImage(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                   const uint8_t* image, uint16_t width, uint16_t height);

// 文本显示函数
void OLED_SetFont(OLED_HandleTypeDef* hdev, const FontDef* font);
void OLED_SetCursor(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y);
void OLED_GetCursor(OLED_HandleTypeDef* hdev, uint16_t* x, uint16_t* y);
void OLED_PutChar(OLED_HandleTypeDef* hdev, char ch);
void OLED_WriteChar(OLED_HandleTypeDef* hdev, char ch, uint8_t color);
void OLED_WriteString(OLED_HandleTypeDef* hdev, const char* str);
void OLED_Printf(OLED_HandleTypeDef* hdev, const char* format, ...);

// 进度条函数
void OLED_DrawProgressBar(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                         uint16_t width, uint16_t height, uint8_t border, 
                         uint8_t progress, uint8_t color);
void OLED_DrawVerticalProgressBar(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                                 uint16_t width, uint16_t height, uint8_t border, 
                                 uint8_t progress, uint8_t color);

// 图表函数
void OLED_DrawHistogram(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                       uint16_t width, uint16_t height, const uint8_t* data, 
                       uint8_t data_count, uint8_t color);
void OLED_DrawWaveform(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                      uint16_t width, uint16_t height, const uint8_t* data, 
                      uint8_t data_count, uint8_t color);

// 菜单系统
typedef struct {
    char* text;
    void (*action)(void);
} OLED_MenuItem;

void OLED_DrawMenu(OLED_HandleTypeDef* hdev, const OLED_MenuItem* menu, 
                  uint8_t item_count, uint8_t selected_item);

// 动画函数
void OLED_ScrollRight(OLED_HandleTypeDef* hdev, uint8_t start_page, uint8_t end_page);
void OLED_ScrollLeft(OLED_HandleTypeDef* hdev, uint8_t start_page, uint8_t end_page);
void OLED_ScrollVerticalRight(OLED_HandleTypeDef* hdev, uint8_t offset);
void OLED_ScrollVerticalLeft(OLED_HandleTypeDef* hdev, uint8_t offset);
void OLED_StopScroll(OLED_HandleTypeDef* hdev);

#endif /* __OLED_H */

1.2 字体定义 (fonts.h)

#ifndef __FONTS_H
#define __FONTS_H

#include <stdint.h>

// 字体结构体
typedef struct {
    const uint8_t width;     // 字体宽度
    const uint8_t height;    // 字体高度
    const uint16_t* data;    // 字体数据指针
} FontDef;

// ASCII字符集 5x7字体
extern FontDef Font_5x7;
// ASCII字符集 7x10字体
extern FontDef Font_7x10;
// ASCII字符集 11x18字体
extern FontDef Font_11x18;
// ASCII字符集 16x26字体
extern FontDef Font_16x26;
// 中文字体 16x16
extern FontDef Font_16x16_CN;

// 获取字体宽度
#define GET_FONT_WIDTH(font) ((font)->width)
#define GET_FONT_HEIGHT(font) ((font)->height)

#endif /* __FONTS_H */

2. I2C接口驱动实现

2.1 I2C接口实现 (oled_i2c.c)

#include "oled.h"

#if OLED_USE_I2C

// I2C写命令
static void OLED_I2C_WriteCommand(OLED_HandleTypeDef* hdev, uint8_t cmd) {
    uint8_t data[2] = {0x00, cmd};  // 控制字节 + 命令
    HAL_I2C_Master_Transmit(hdev->hi2c, hdev->i2c_addr, data, 2, HAL_MAX_DELAY);
}

// I2C写数据
static void OLED_I2C_WriteData(OLED_HandleTypeDef* hdev, uint8_t* data, uint16_t size) {
    uint8_t buffer[129];  // 1字节控制字节 + 128字节数据
    buffer[0] = 0x40;     // 数据控制字节
    
    // 分批发送,每批128字节
    for(uint16_t i = 0; i < size; i += 128) {
        uint16_t chunk_size = (size - i) > 128 ? 128 : (size - i);
        
        // 拷贝数据
        for(uint16_t j = 0; j < chunk_size; j++) {
            buffer[j + 1] = data[i + j];
        }
        
        HAL_I2C_Master_Transmit(hdev->hi2c, hdev->i2c_addr, buffer, chunk_size + 1, HAL_MAX_DELAY);
    }
}

// 初始化I2C OLED
static void OLED_I2C_Init(OLED_HandleTypeDef* hdev) {
    // OLED初始化序列
    OLED_I2C_WriteCommand(hdev, OLED_CMD_DISPLAY_OFF);          // 关闭显示
    
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_DISPLAY_CLOCK);    // 设置显示时钟分频
    OLED_I2C_WriteCommand(hdev, 0x80);                          // 建议值
    
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_MULTIPLEX);        // 设置多路复用
    OLED_I2C_WriteCommand(hdev, 0x3F);                          // 0x3F for 128x64
    
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_DISPLAY_OFFSET);   // 设置显示偏移
    OLED_I2C_WriteCommand(hdev, 0x00);                          // 无偏移
    
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_START_LINE | 0x00); // 设置起始行
    
    OLED_I2C_WriteCommand(hdev, OLED_CMD_CHARGE_PUMP);          // 电荷泵设置
    OLED_I2C_WriteCommand(hdev, 0x14);                          // 启用电荷泵
    
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_MEMORY_MODE);      // 设置内存模式
    OLED_I2C_WriteCommand(hdev, 0x00);                          // 水平地址模式
    
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SEG_REMAP | 0x01);     // 段重映射
    OLED_I2C_WriteCommand(hdev, OLED_CMD_COM_SCAN_DIR | 0x08);  // 扫描方向
    
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_COM_PINS);         // 设置COM引脚
    OLED_I2C_WriteCommand(hdev, 0x12);                          // 0x12 for 128x64
    
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_CONTRAST);         // 设置对比度
    OLED_I2C_WriteCommand(hdev, 0xCF);                          // 默认对比度
    
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_PRECHARGE);        // 预充电周期
    OLED_I2C_WriteCommand(hdev, 0xF1);                          // 默认值
    
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_VCOM_DESELECT);    // VCOMH反压电平
    OLED_I2C_WriteCommand(hdev, 0x40);                          // 默认值
    
    OLED_I2C_WriteCommand(hdev, OLED_CMD_DISPLAY_ALL_ON_RESUME); // 全屏显示恢复
    OLED_I2C_WriteCommand(hdev, OLED_CMD_NORMAL_DISPLAY);        // 正常显示
    OLED_I2C_WriteCommand(hdev, OLED_CMD_DISPLAY_ON);            // 开启显示
    
    // 清屏
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_COL_ADDR);
    OLED_I2C_WriteCommand(hdev, 0);
    OLED_I2C_WriteCommand(hdev, 127);
    
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_PAGE_ADDR);
    OLED_I2C_WriteCommand(hdev, 0);
    OLED_I2C_WriteCommand(hdev, 7);
}

// 更新屏幕(I2C版本)
static void OLED_I2C_UpdateScreen(OLED_HandleTypeDef* hdev) {
    // 设置列地址
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_COL_ADDR);
    OLED_I2C_WriteCommand(hdev, 0);
    OLED_I2C_WriteCommand(hdev, 127);
    
    // 设置页地址
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_PAGE_ADDR);
    OLED_I2C_WriteCommand(hdev, 0);
    OLED_I2C_WriteCommand(hdev, 7);
    
    // 写入显示数据
    OLED_I2C_WriteData(hdev, hdev->buffer, OLED_BUFFER_SIZE);
}

#endif /* OLED_USE_I2C */

3. SPI接口驱动实现

3.1 SPI接口实现 (oled_spi.c)

#include "oled.h"

#if !OLED_USE_I2C

// 定义控制引脚
#define OLED_CS_LOW()    HAL_GPIO_WritePin(hdev->cs_port, hdev->cs_pin, GPIO_PIN_RESET)
#define OLED_CS_HIGH()   HAL_GPIO_WritePin(hdev->cs_port, hdev->cs_pin, GPIO_PIN_SET)
#define OLED_DC_CMD()    HAL_GPIO_WritePin(hdev->dc_port, hdev->dc_pin, GPIO_PIN_RESET)
#define OLED_DC_DATA()   HAL_GPIO_WritePin(hdev->dc_port, hdev->dc_pin, GPIO_PIN_SET)
#define OLED_RES_LOW()   HAL_GPIO_WritePin(hdev->res_port, hdev->res_pin, GPIO_PIN_RESET)
#define OLED_RES_HIGH()  HAL_GPIO_WritePin(hdev->res_port, hdev->res_pin, GPIO_PIN_SET)

// SPI写命令
static void OLED_SPI_WriteCommand(OLED_HandleTypeDef* hdev, uint8_t cmd) {
    OLED_DC_CMD();
    OLED_CS_LOW();
    HAL_SPI_Transmit(hdev->hspi, &cmd, 1, HAL_MAX_DELAY);
    OLED_CS_HIGH();
}

// SPI写数据
static void OLED_SPI_WriteData(OLED_HandleTypeDef* hdev, uint8_t* data, uint16_t size) {
    OLED_DC_DATA();
    OLED_CS_LOW();
    HAL_SPI_Transmit(hdev->hspi, data, size, HAL_MAX_DELAY);
    OLED_CS_HIGH();
}

// 硬件复位
static void OLED_SPI_Reset(OLED_HandleTypeDef* hdev) {
    OLED_RES_LOW();
    HAL_Delay(10);
    OLED_RES_HIGH();
    HAL_Delay(10);
}

// 初始化SPI OLED
static void OLED_SPI_Init(OLED_HandleTypeDef* hdev) {
    // 硬件复位
    OLED_SPI_Reset(hdev);
    
    // OLED初始化序列
    OLED_SPI_WriteCommand(hdev, OLED_CMD_DISPLAY_OFF);
    
    OLED_SPI_WriteCommand(hdev, OLED_CMD_SET_DISPLAY_CLOCK);
    OLED_SPI_WriteCommand(hdev, 0x80);
    
    OLED_SPI_WriteCommand(hdev, OLED_CMD_SET_MULTIPLEX);
    OLED_SPI_WriteCommand(hdev, 0x3F);
    
    OLED_SPI_WriteCommand(hdev, OLED_CMD_SET_DISPLAY_OFFSET);
    OLED_SPI_WriteCommand(hdev, 0x00);
    
    OLED_SPI_WriteCommand(hdev, OLED_CMD_SET_START_LINE | 0x00);
    
    OLED_SPI_WriteCommand(hdev, OLED_CMD_CHARGE_PUMP);
    OLED_SPI_WriteCommand(hdev, 0x14);
    
    OLED_SPI_WriteCommand(hdev, 0x20);  // 内存地址模式
    OLED_SPI_WriteCommand(hdev, 0x00);  // 水平地址模式
    
    OLED_SPI_WriteCommand(hdev, OLED_CMD_SEG_REMAP | 0x01);
    OLED_SPI_WriteCommand(hdev, OLED_CMD_COM_SCAN_DIR | 0x08);
    
    OLED_SPI_WriteCommand(hdev, OLED_CMD_SET_COM_PINS);
    OLED_SPI_WriteCommand(hdev, 0x12);
    
    OLED_SPI_WriteCommand(hdev, OLED_CMD_SET_CONTRAST);
    OLED_SPI_WriteCommand(hdev, 0xCF);
    
    OLED_SPI_WriteCommand(hdev, OLED_CMD_SET_PRECHARGE);
    OLED_SPI_WriteCommand(hdev, 0xF1);
    
    OLED_SPI_WriteCommand(hdev, OLED_CMD_SET_VCOM_DESELECT);
    OLED_SPI_WriteCommand(hdev, 0x40);
    
    OLED_SPI_WriteCommand(hdev, OLED_CMD_DISPLAY_ALL_ON_RESUME);
    OLED_SPI_WriteCommand(hdev, OLED_CMD_NORMAL_DISPLAY);
    
    OLED_SPI_WriteCommand(hdev, OLED_CMD_DISPLAY_ON);
}

// 更新屏幕(SPI版本)
static void OLED_SPI_UpdateScreen(OLED_HandleTypeDef* hdev) {
    for(uint8_t i = 0; i < 8; i++) {
        OLED_SPI_WriteCommand(hdev, 0xB0 + i);  // 设置页地址
        OLED_SPI_WriteCommand(hdev, 0x00);      // 设置列地址低4位
        OLED_SPI_WriteCommand(hdev, 0x10);      // 设置列地址高4位
        
        // 写入该页的数据
        OLED_SPI_WriteData(hdev, &hdev->buffer[OLED_WIDTH * i], OLED_WIDTH);
    }
}

#endif /* !OLED_USE_I2C */

4. OLED核心驱动实现

4.1 核心驱动函数 (oled_core.c)

#include "oled.h"
#include "fonts.h"

// 全局字体定义
FontDef Font_5x7 = {5, 7, NULL};  // 实际字体数据需要定义
FontDef Font_7x10 = {7, 10, NULL};
FontDef Font_11x18 = {11, 18, NULL};
FontDef Font_16x26 = {16, 26, NULL};
FontDef Font_16x16_CN = {16, 16, NULL};

// 初始化OLED
void OLED_Init(OLED_HandleTypeDef* hdev) {
    if(hdev == NULL) return;
    
    // 初始化参数
    hdev->width = OLED_WIDTH;
    hdev->height = OLED_HEIGHT;
    hdev->rotation = OLED_ROTATION_0;
    hdev->invert_color = 0;
    hdev->current_x = 0;
    hdev->current_y = 0;
    hdev->initialized = 0;
    
    // 设置默认字体
    hdev->current_font = &Font_5x7;
    
    // 清空缓冲区
    memset(hdev->buffer, 0, OLED_BUFFER_SIZE);
    
    // 初始化硬件接口
#if OLED_USE_I2C
    OLED_I2C_Init(hdev);
#else
    OLED_SPI_Init(hdev);
#endif
    
    // 更新显示
    OLED_UpdateScreen(hdev);
    
    hdev->initialized = 1;
}

// 反初始化
void OLED_DeInit(OLED_HandleTypeDef* hdev) {
    if(hdev == NULL) return;
    
    OLED_DisplayOff(hdev);
    hdev->initialized = 0;
}

// 检查是否初始化
uint8_t OLED_IsInitialized(OLED_HandleTypeDef* hdev) {
    return (hdev != NULL) ? hdev->initialized : 0;
}

// 开启显示
void OLED_DisplayOn(OLED_HandleTypeDef* hdev) {
    if(hdev == NULL) return;
    
#if OLED_USE_I2C
    OLED_I2C_WriteCommand(hdev, OLED_CMD_DISPLAY_ON);
#else
    OLED_SPI_WriteCommand(hdev, OLED_CMD_DISPLAY_ON);
#endif
}

// 关闭显示
void OLED_DisplayOff(OLED_HandleTypeDef* hdev) {
    if(hdev == NULL) return;
    
#if OLED_USE_I2C
    OLED_I2C_WriteCommand(hdev, OLED_CMD_DISPLAY_OFF);
#else
    OLED_SPI_WriteCommand(hdev, OLED_CMD_DISPLAY_OFF);
#endif
}

// 设置对比度
void OLED_SetContrast(OLED_HandleTypeDef* hdev, uint8_t contrast) {
    if(hdev == NULL) return;
    
#if OLED_USE_I2C
    OLED_I2C_WriteCommand(hdev, OLED_CMD_SET_CONTRAST);
    OLED_I2C_WriteCommand(hdev, contrast);
#else
    OLED_SPI_WriteCommand(hdev, OLED_CMD_SET_CONTRAST);
    OLED_SPI_WriteCommand(hdev, contrast);
#endif
}

// 设置显示模式
void OLED_SetDisplayMode(OLED_HandleTypeDef* hdev, OLED_DisplayMode mode) {
    if(hdev == NULL) return;
    
    switch(mode) {
        case OLED_DISPLAY_NORMAL:
            hdev->invert_color = 0;
#if OLED_USE_I2C
            OLED_I2C_WriteCommand(hdev, OLED_CMD_NORMAL_DISPLAY);
#else
            OLED_SPI_WriteCommand(hdev, OLED_CMD_NORMAL_DISPLAY);
#endif
            break;
            
        case OLED_DISPLAY_INVERT:
            hdev->invert_color = 1;
#if OLED_USE_I2C
            OLED_I2C_WriteCommand(hdev, OLED_CMD_INVERT_DISPLAY);
#else
            OLED_SPI_WriteCommand(hdev, OLED_CMD_INVERT_DISPLAY);
#endif
            break;
            
        case OLED_DISPLAY_OFF:
            OLED_DisplayOff(hdev);
            break;
            
        case OLED_DISPLAY_ON:
            OLED_DisplayOn(hdev);
            break;
    }
}

// 设置旋转
void OLED_SetRotation(OLED_HandleTypeDef* hdev, OLED_Rotation rotation) {
    if(hdev == NULL) return;
    
    hdev->rotation = rotation;
    
    switch(rotation) {
        case OLED_ROTATION_0:
#if OLED_USE_I2C
            OLED_I2C_WriteCommand(hdev, OLED_CMD_SEG_REMAP | 0x01);
            OLED_I2C_WriteCommand(hdev, OLED_CMD_COM_SCAN_DIR | 0x08);
#else
            OLED_SPI_WriteCommand(hdev, OLED_CMD_SEG_REMAP | 0x01);
            OLED_SPI_WriteCommand(hdev, OLED_CMD_COM_SCAN_DIR | 0x08);
#endif
            break;
            
        case OLED_ROTATION_90:
#if OLED_USE_I2C
            OLED_I2C_WriteCommand(hdev, OLED_CMD_SEG_REMAP | 0x00);
            OLED_I2C_WriteCommand(hdev, OLED_CMD_COM_SCAN_DIR | 0x08);
#else
            OLED_SPI_WriteCommand(hdev, OLED_CMD_SEG_REMAP | 0x00);
            OLED_SPI_WriteCommand(hdev, OLED_CMD_COM_SCAN_DIR | 0x08);
#endif
            break;
            
        case OLED_ROTATION_180:
#if OLED_USE_I2C
            OLED_I2C_WriteCommand(hdev, OLED_CMD_SEG_REMAP | 0x00);
            OLED_I2C_WriteCommand(hdev, OLED_CMD_COM_SCAN_DIR | 0x00);
#else
            OLED_SPI_WriteCommand(hdev, OLED_CMD_SEG_REMAP | 0x00);
            OLED_SPI_WriteCommand(hdev, OLED_CMD_COM_SCAN_DIR | 0x00);
#endif
            break;
            
        case OLED_RPTATION_270:
#if OLED_USE_I2C
            OLED_I2C_WriteCommand(hdev, OLED_CMD_SEG_REMAP | 0x01);
            OLED_I2C_WriteCommand(hdev, OLED_CMD_COM_SCAN_DIR | 0x00);
#else
            OLED_SPI_WriteCommand(hdev, OLED_CMD_SEG_REMAP | 0x01);
            OLED_SPI_WriteCommand(hdev, OLED_CMD_COM_SCAN_DIR | 0x00);
#endif
            break;
    }
}

// 反色显示
void OLED_InvertDisplay(OLED_HandleTypeDef* hdev, uint8_t invert) {
    if(hdev == NULL) return;
    
    hdev->invert_color = invert;
    
    if(invert) {
        OLED_SetDisplayMode(hdev, OLED_DISPLAY_INVERT);
    } else {
        OLED_SetDisplayMode(hdev, OLED_DISPLAY_NORMAL);
    }
}

// 清空缓冲区
void OLED_ClearBuffer(OLED_HandleTypeDef* hdev, uint8_t color) {
    if(hdev == NULL) return;
    
    memset(hdev->buffer, (color == OLED_COLOR_WHITE) ? 0xFF : 0x00, OLED_BUFFER_SIZE);
}

// 更新屏幕
void OLED_UpdateScreen(OLED_HandleTypeDef* hdev) {
    if(hdev == NULL || !hdev->initialized) return;
    
#if OLED_USE_I2C
    OLED_I2C_UpdateScreen(hdev);
#else
    OLED_SPI_UpdateScreen(hdev);
#endif
}

// 绘制像素点
void OLED_DrawPixel(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, uint8_t color) {
    if(hdev == NULL || x >= hdev->width || y >= hdev->height) return;
    
    // 根据旋转调整坐标
    uint16_t actual_x = x, actual_y = y;
    
    switch(hdev->rotation) {
        case OLED_ROTATION_0:
            break;
        case OLED_ROTATION_90:
            actual_x = hdev->width - y - 1;
            actual_y = x;
            break;
        case OLED_ROTATION_180:
            actual_x = hdev->width - x - 1;
            actual_y = hdev->height - y - 1;
            break;
        case OLED_RPTATION_270:
            actual_x = y;
            actual_y = hdev->height - x - 1;
            break;
    }
    
    // 计算在缓冲区中的位置
    uint16_t page = actual_y / 8;
    uint16_t bit_pos = actual_y % 8;
    uint16_t byte_index = page * OLED_WIDTH + actual_x;
    
    if(byte_index >= OLED_BUFFER_SIZE) return;
    
    if(color == OLED_COLOR_WHITE) {
        hdev->buffer[byte_index] |= (1 << bit_pos);
    } else {
        hdev->buffer[byte_index] &= ~(1 << bit_pos);
    }
}

// 获取像素点
void OLED_GetPixel(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y) {
    // 实现类似DrawPixel的逻辑
    // 返回像素点状态
}

// 绘制直线(Bresenham算法)
void OLED_DrawLine(OLED_HandleTypeDef* hdev, uint16_t x0, uint16_t y0, 
                   uint16_t x1, uint16_t y1, uint8_t color) {
    if(hdev == NULL) return;
    
    int16_t dx = abs(x1 - x0);
    int16_t dy = abs(y1 - y0);
    int16_t sx = (x0 < x1) ? 1 : -1;
    int16_t sy = (y0 < y1) ? 1 : -1;
    int16_t err = dx - dy;
    int16_t e2;
    
    while(1) {
        OLED_DrawPixel(hdev, x0, y0, color);
        
        if(x0 == x1 && y0 == y1) break;
        
        e2 = 2 * err;
        if(e2 > -dy) {
            err -= dy;
            x0 += sx;
        }
        if(e2 < dx) {
            err += dx;
            y0 += sy;
        }
    }
}

// 绘制矩形
void OLED_DrawRectangle(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                       uint16_t width, uint16_t height, uint8_t color) {
    if(hdev == NULL) return;
    
    // 绘制四条边
    OLED_DrawLine(hdev, x, y, x + width - 1, y, color);                    // 上边
    OLED_DrawLine(hdev, x, y + height - 1, x + width - 1, y + height - 1, color); // 下边
    OLED_DrawLine(hdev, x, y, x, y + height - 1, color);                    // 左边
    OLED_DrawLine(hdev, x + width - 1, y, x + width - 1, y + height - 1, color); // 右边
}

// 绘制填充矩形
void OLED_DrawFilledRectangle(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                             uint16_t width, uint16_t height, uint8_t color) {
    if(hdev == NULL) return;
    
    for(uint16_t i = 0; i < height; i++) {
        OLED_DrawLine(hdev, x, y + i, x + width - 1, y + i, color);
    }
}

// 绘制圆
void OLED_DrawCircle(OLED_HandleTypeDef* hdev, uint16_t x0, uint16_t y0, 
                    uint16_t radius, uint8_t color) {
    if(hdev == NULL) return;
    
    int16_t f = 1 - radius;
    int16_t ddF_x = 1;
    int16_t ddF_y = -2 * radius;
    int16_t x = 0;
    int16_t y = radius;
    
    // 绘制八个对称点
    OLED_DrawPixel(hdev, x0, y0 + radius, color);
    OLED_DrawPixel(hdev, x0, y0 - radius, color);
    OLED_DrawPixel(hdev, x0 + radius, y0, color);
    OLED_DrawPixel(hdev, x0 - radius, y0, color);
    
    while(x < y) {
        if(f >= 0) {
            y--;
            ddF_y += 2;
            f += ddF_y;
        }
        x++;
        ddF_x += 2;
        f += ddF_x;
        
        OLED_DrawPixel(hdev, x0 + x, y0 + y, color);
        OLED_DrawPixel(hdev, x0 - x, y0 + y, color);
        OLED_DrawPixel(hdev, x0 + x, y0 - y, color);
        OLED_DrawPixel(hdev, x0 - x, y0 - y, color);
        OLED_DrawPixel(hdev, x0 + y, y0 + x, color);
        OLED_DrawPixel(hdev, x0 - y, y0 + x, color);
        OLED_DrawPixel(hdev, x0 + y, y0 - x, color);
        OLED_DrawPixel(hdev, x0 - y, y0 - x, color);
    }
}

// 绘制填充圆
void OLED_DrawFilledCircle(OLED_HandleTypeDef* hdev, uint16_t x0, uint16_t y0, 
                          uint16_t radius, uint8_t color) {
    if(hdev == NULL) return;
    
    int16_t f = 1 - radius;
    int16_t ddF_x = 1;
    int16_t ddF_y = -2 * radius;
    int16_t x = 0;
    int16_t y = radius;
    
    // 绘制填充线
    OLED_DrawLine(hdev, x0 - radius, y0, x0 + radius, y0, color);
    
    while(x < y) {
        if(f >= 0) {
            y--;
            ddF_y += 2;
            f += ddF_y;
        }
        x++;
        ddF_x += 2;
        f += ddF_x;
        
        // 绘制填充线
        OLED_DrawLine(hdev, x0 - x, y0 + y, x0 + x, y0 + y, color);
        OLED_DrawLine(hdev, x0 - x, y0 - y, x0 + x, y0 - y, color);
        OLED_DrawLine(hdev, x0 - y, y0 + x, x0 + y, y0 + x, color);
        OLED_DrawLine(hdev, x0 - y, y0 - x, x0 + y, y0 - x, color);
    }
}

// 绘制三角形
void OLED_DrawTriangle(OLED_HandleTypeDef* hdev, uint16_t x1, uint16_t y1,
                      uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint8_t color) {
    if(hdev == NULL) return;
    
    OLED_DrawLine(hdev, x1, y1, x2, y2, color);
    OLED_DrawLine(hdev, x2, y2, x3, y3, color);
    OLED_DrawLine(hdev, x3, y3, x1, y1, color);
}

// 绘制圆弧
void OLED_DrawArc(OLED_HandleTypeDef* hdev, uint16_t x0, uint16_t y0, 
                 uint16_t radius, uint16_t start_angle, uint16_t end_angle, uint8_t color) {
    if(hdev == NULL) return;
    
    float start_rad = start_angle * 3.14159f / 180.0f;
    float end_rad = end_angle * 3.14159f / 180.0f;
    float step = 0.1f;  // 角度步长
    
    float angle = start_rad;
    float last_x = x0 + radius * cos(angle);
    float last_y = y0 + radius * sin(angle);
    
    while(angle <= end_rad) {
        angle += step;
        float x = x0 + radius * cos(angle);
        float y = y0 + radius * sin(angle);
        
        OLED_DrawLine(hdev, (uint16_t)last_x, (uint16_t)last_y, (uint16_t)x, (uint16_t)y, color);
        
        last_x = x;
        last_y = y;
    }
}

5. 位图和图像显示

5.1 位图显示函数 (oled_bitmap.c)

#include "oled.h"

// 绘制位图
void OLED_DrawBitmap(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                    const uint8_t* bitmap, uint16_t width, uint16_t height, uint8_t color) {
    if(hdev == NULL || bitmap == NULL) return;
    
    uint16_t byte_width = (width + 7) / 8;  // 计算每行需要的字节数
    
    for(uint16_t j = 0; j < height; j++) {
        for(uint16_t i = 0; i < width; i++) {
            // 计算字节索引和位索引
            uint16_t byte_index = j * byte_width + i / 8;
            uint8_t bit_index = i % 8;
            
            // 检查像素是否需要绘制
            if(bitmap[byte_index] & (0x80 >> bit_index)) {
                OLED_DrawPixel(hdev, x + i, y + j, color);
            } else if(color != OLED_COLOR_BLACK) {
                // 如果需要绘制反色背景
                OLED_DrawPixel(hdev, x + i, y + j, !color);
            }
        }
    }
}

// 绘制图像(直接数据)
void OLED_DrawImage(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                   const uint8_t* image, uint16_t width, uint16_t height) {
    if(hdev == NULL || image == NULL) return;
    
    // 直接复制图像数据到缓冲区
    for(uint16_t j = 0; j < height; j++) {
        uint16_t page = (y + j) / 8;
        uint16_t bit_pos = (y + j) % 8;
        
        for(uint16_t i = 0; i < width; i++) {
            uint16_t buffer_index = page * OLED_WIDTH + (x + i);
            uint8_t image_byte = image[j * width + i];
            
            if(buffer_index < OLED_BUFFER_SIZE) {
                hdev->buffer[buffer_index] = image_byte;
            }
        }
    }
}

6. 文本显示功能

6.1 文本显示函数 (oled_text.c)

#include "oled.h"
#include "fonts.h"

// 设置字体
void OLED_SetFont(OLED_HandleTypeDef* hdev, const FontDef* font) {
    if(hdev == NULL || font == NULL) return;
    hdev->current_font = font;
}

// 设置光标位置
void OLED_SetCursor(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y) {
    if(hdev == NULL) return;
    hdev->current_x = x;
    hdev->current_y = y;
}

// 获取光标位置
void OLED_GetCursor(OLED_HandleTypeDef* hdev, uint16_t* x, uint16_t* y) {
    if(hdev == NULL || x == NULL || y == NULL) return;
    *x = hdev->current_x;
    *y = hdev->current_y;
}

// 写入一个字符
void OLED_PutChar(OLED_HandleTypeDef* hdev, char ch) {
    OLED_WriteChar(hdev, ch, OLED_COLOR_WHITE);
}

// 写入一个字符(带颜色)
void OLED_WriteChar(OLED_HandleTypeDef* hdev, char ch, uint8_t color) {
    if(hdev == NULL || hdev->current_font == NULL) return;
    
    // 检查字符是否在可打印范围内
    if(ch < 32 || ch > 126) {
        ch = '?';  // 显示问号代替不可打印字符
    }
    
    uint8_t font_width = hdev->current_font->width;
    uint8_t font_height = hdev->current_font->height;
    
    // 获取字模数据
    const uint16_t* font_data = &hdev->current_font->data[(ch - 32) * font_width];
    
    // 逐像素绘制字符
    for(uint8_t i = 0; i < font_width; i++) {
        uint16_t line = font_data[i];
        
        for(uint8_t j = 0; j < font_height; j++) {
            if(line & (1 << j)) {
                OLED_DrawPixel(hdev, hdev->current_x + i, hdev->current_y + j, color);
            } else if(color != OLED_COLOR_BLACK) {
                // 绘制背景色
                OLED_DrawPixel(hdev, hdev->current_x + i, hdev->current_y + j, !color);
            }
        }
    }
    
    // 更新光标位置
    hdev->current_x += font_width + 1;  // 字符宽度 + 1像素间隔
    
    // 自动换行
    if(hdev->current_x + font_width > hdev->width) {
        hdev->current_x = 0;
        hdev->current_y += font_height + 1;
    }
}

// 写入字符串
void OLED_WriteString(OLED_HandleTypeDef* hdev, const char* str) {
    if(hdev == NULL || str == NULL) return;
    
    while(*str) {
        OLED_PutChar(hdev, *str++);
    }
}

// 格式化输出
void OLED_Printf(OLED_HandleTypeDef* hdev, const char* format, ...) {
    if(hdev == NULL || format == NULL) return;
    
    char buffer[128];
    va_list args;
    
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);
    
    OLED_WriteString(hdev, buffer);
}

参考代码 STM32F点亮OLED屏 www.youwenfan.com/contentcnv/71194.html

7. 进度条和图表

7.1 进度条和图表函数 (oled_chart.c)

#include "oled.h"

// 绘制水平进度条
void OLED_DrawProgressBar(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                         uint16_t width, uint16_t height, uint8_t border, 
                         uint8_t progress, uint8_t color) {
    if(hdev == NULL) return;
    
    // 绘制边框
    OLED_DrawRectangle(hdev, x, y, width, height, color);
    
    // 计算填充宽度
    uint16_t fill_width = (width - 2 * border) * progress / 100;
    
    // 绘制填充
    if(fill_width > 0) {
        OLED_DrawFilledRectangle(hdev, x + border, y + border, 
                                fill_width, height - 2 * border, color);
    }
}

// 绘制垂直进度条
void OLED_DrawVerticalProgressBar(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                                 uint16_t width, uint16_t height, uint8_t border, 
                                 uint8_t progress, uint8_t color) {
    if(hdev == NULL) return;
    
    // 绘制边框
    OLED_DrawRectangle(hdev, x, y, width, height, color);
    
    // 计算填充高度
    uint16_t fill_height = (height - 2 * border) * progress / 100;
    
    // 绘制填充
    if(fill_height > 0) {
        OLED_DrawFilledRectangle(hdev, x + border, y + height - border - fill_height, 
                                width - 2 * border, fill_height, color);
    }
}

// 绘制柱状图
void OLED_DrawHistogram(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                       uint16_t width, uint16_t height, const uint8_t* data, 
                       uint8_t data_count, uint8_t color) {
    if(hdev == NULL || data == NULL || data_count == 0) return;
    
    // 计算柱宽和间距
    uint8_t bar_width = (width - (data_count + 1) * 2) / data_count;
    uint8_t spacing = 2;
    
    // 绘制每个柱
    for(uint8_t i = 0; i < data_count; i++) {
        uint16_t bar_height = data[i] * height / 100;
        uint16_t bar_x = x + spacing + i * (bar_width + spacing);
        uint16_t bar_y = y + height - bar_height;
        
        OLED_DrawFilledRectangle(hdev, bar_x, bar_y, bar_width, bar_height, color);
    }
}

// 绘制波形图
void OLED_DrawWaveform(OLED_HandleTypeDef* hdev, uint16_t x, uint16_t y, 
                      uint16_t width, uint16_t height, const uint8_t* data, 
                      uint8_t data_count, uint8_t color) {
    if(hdev == NULL || data == NULL || data_count < 2) return;
    
    // 绘制背景网格
    uint8_t grid_spacing = 10;
    
    // 水平网格线
    for(uint16_t i = y; i <= y + height; i += grid_spacing) {
        OLED_DrawLine(hdev, x, i, x + width, i, color);
    }
    
    // 垂直网格线
    for(uint16_t i = x; i <= x + width; i += grid_spacing) {
        OLED_DrawLine(hdev, i, y, i, y + height, color);
    }
    
    // 绘制波形
    float x_step = (float)width / (data_count - 1);
    
    for(uint8_t i = 0; i < data_count - 1; i++) {
        uint16_t x0 = x + (uint16_t)(i * x_step);
        uint16_t y0 = y + height - (data[i] * height / 100);
        uint16_t x1 = x + (uint16_t)((i + 1) * x_step);
        uint16_t y1 = y + height - (data[i + 1] * height / 100);
        
        OLED_DrawLine(hdev, x0, y0, x1, y1, color);
    }
}

8. 菜单系统

8.1 菜单系统实现 (oled_menu.c)

#include "oled.h"

// 绘制菜单
void OLED_DrawMenu(OLED_HandleTypeDef* hdev, const OLED_MenuItem* menu, 
                  uint8_t item_count, uint8_t selected_item) {
    if(hdev == NULL || menu == NULL || item_count == 0) return;
    
    // 清屏
    OLED_ClearBuffer(hdev, OLED_COLOR_BLACK);
    
    // 计算每行高度
    uint8_t font_height = hdev->current_font->height;
    uint8_t line_height = font_height + 2;  // 2像素行间距
    
    // 绘制菜单项
    for(uint8_t i = 0; i < item_count; i++) {
        uint16_t y_pos = i * line_height;
        
        if(i == selected_item) {
            // 选中项高亮显示
            OLED_DrawFilledRectangle(hdev, 0, y_pos, hdev->width, line_height, OLED_COLOR_WHITE);
            OLED_SetCursor(hdev, 2, y_pos + 1);
            OLED_WriteString(hdev, menu[i].text);
            
            // 恢复背景色
            OLED_SetCursor(hdev, 0, 0);
        } else {
            OLED_SetCursor(hdev, 2, y_pos + 1);
            OLED_WriteString(hdev, menu[i].text);
        }
    }
    
    // 更新显示
    OLED_UpdateScreen(hdev);
}

9. 动画和滚动

9.1 滚动和动画函数 (oled_anim.c)

#include "oled.h"

// 向右滚动
void OLED_ScrollRight(OLED_HandleTypeDef* hdev, uint8_t start_page, uint8_t end_page) {
    if(hdev == NULL) return;
    
#if OLED_USE_I2C
    OLED_I2C_WriteCommand(hdev, 0x26);  // 向右滚动
    OLED_I2C_WriteCommand(hdev, 0x00);  // 虚拟字节
    OLED_I2C_WriteCommand(hdev, start_page);
    OLED_I2C_WriteCommand(hdev, 0x00);  // 滚动速度
    OLED_I2C_WriteCommand(hdev, end_page);
    OLED_I2C_WriteCommand(hdev, 0x00);
    OLED_I2C_WriteCommand(hdev, 0xFF);
    OLED_I2C_WriteCommand(hdev, 0x2F);  // 启动滚动
#else
    OLED_SPI_WriteCommand(hdev, 0x26);
    OLED_SPI_WriteCommand(hdev, 0x00);
    OLED_SPI_WriteCommand(hdev, start_page);
    OLED_SPI_WriteCommand(hdev, 0x00);
    OLED_SPI_WriteCommand(hdev, end_page);
    OLED_SPI_WriteCommand(hdev, 0x00);
    OLED_SPI_WriteCommand(hdev, 0xFF);
    OLED_SPI_WriteCommand(hdev, 0x2F);
#endif
}

// 向左滚动
void OLED_ScrollLeft(OLED_HandleTypeDef* hdev, uint8_t start_page, uint8_t end_page) {
    if(hdev == NULL) return;
    
#if OLED_USE_I2C
    OLED_I2C_WriteCommand(hdev, 0x27);  // 向左滚动
    OLED_I2C_WriteCommand(hdev, 0x00);  // 虚拟字节
    OLED_I2C_WriteCommand(hdev, start_page);
    OLED_I2C_WriteCommand(hdev, 0x00);  // 滚动速度
    OLED_I2C_WriteCommand(hdev, end_page);
    OLED_I2C_WriteCommand(hdev, 0x00);
    OLED_I2C_WriteCommand(hdev, 0xFF);
    OLED_I2C_WriteCommand(hdev, 0x2F);  // 启动滚动
#else
    OLED_SPI_WriteCommand(hdev, 0x27);
    OLED_SPI_WriteCommand(hdev, 0x00);
    OLED_SPI_WriteCommand(hdev, start_page);
    OLED_SPI_WriteCommand(hdev, 0x00);
    OLED_SPI_WriteCommand(hdev, end_page);
    OLED_SPI_WriteCommand(hdev, 0x00);
    OLED_SPI_WriteCommand(hdev, 0xFF);
    OLED_SPI_WriteCommand(hdev, 0x2F);
#endif
}

// 停止滚动
void OLED_StopScroll(OLED_HandleTypeDef* hdev) {
    if(hdev == NULL) return;
    
#if OLED_USE_I2C
    OLED_I2C_WriteCommand(hdev, 0x2E);  // 停止滚动
#else
    OLED_SPI_WriteCommand(hdev, 0x2E);
#endif
}

10. 主程序示例

10.1 主程序示例 (main.c)

#include "main.h"
#include "oled.h"
#include "fonts.h"

// 全局变量
I2C_HandleTypeDef hi2c1;  // I2C句柄
OLED_HandleTypeDef hdev;  // OLED句柄

// 系统时钟配置
void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    // 配置HSE
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);
    
    // 配置系统时钟
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                  |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}

// GPIO初始化
static void MX_GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // 使能GPIO时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();
    
    // 配置I2C引脚
    // PB6 - I2C1_SCL
    // PB7 - I2C1_SDA
    GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

// I2C初始化
static void MX_I2C1_Init(void) {
    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 400000;  // 400kHz
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c1.Init.OwnAddress1 = 0;
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    HAL_I2C_Init(&hi2c1);
}

// 示例1:基本显示
void OLED_Example_Basic(void) {
    // 清屏
    OLED_ClearBuffer(&hdev, OLED_COLOR_BLACK);
    
    // 设置字体
    OLED_SetFont(&hdev, &Font_7x10);
    
    // 显示文本
    OLED_SetCursor(&hdev, 0, 0);
    OLED_WriteString(&hdev, "OLED Display Test");
    
    OLED_SetCursor(&hdev, 0, 12);
    OLED_WriteString(&hdev, "STM32F103C8T6");
    
    OLED_SetCursor(&hdev, 0, 24);
    OLED_WriteString(&hdev, "I2C Interface");
    
    OLED_SetCursor(&hdev, 0, 36);
    OLED_WriteString(&hdev, "128x64 Pixels");
    
    // 显示数字
    OLED_SetCursor(&hdev, 0, 48);
    OLED_Printf(&hdev, "Count: %d", 1234);
    
    // 更新显示
    OLED_UpdateScreen(&hdev);
}

// 示例2:图形绘制
void OLED_Example_Graphics(void) {
    // 清屏
    OLED_ClearBuffer(&hdev, OLED_COLOR_BLACK);
    
    // 绘制矩形
    OLED_DrawRectangle(&hdev, 5, 5, 118, 54, OLED_COLOR_WHITE);
    
    // 绘制填充矩形
    OLED_DrawFilledRectangle(&hdev, 10, 10, 20, 20, OLED_COLOR_WHITE);
    
    // 绘制圆形
    OLED_DrawCircle(&hdev, 60, 30, 20, OLED_COLOR_WHITE);
    
    // 绘制填充圆
    OLED_DrawFilledCircle(&hdev, 100, 30, 15, OLED_COLOR_WHITE);
    
    // 绘制直线
    OLED_DrawLine(&hdev, 10, 40, 110, 40, OLED_COLOR_WHITE);
    OLED_DrawLine(&hdev, 60, 10, 60, 50, OLED_COLOR_WHITE);
    
    // 绘制三角形
    OLED_DrawTriangle(&hdev, 80, 10, 100, 10, 90, 25, OLED_COLOR_WHITE);
    
    // 显示文本
    OLED_SetFont(&hdev, &Font_5x7);
    OLED_SetCursor(&hdev, 20, 55);
    OLED_WriteString(&hdev, "Graphics Demo");
    
    // 更新显示
    OLED_UpdateScreen(&hdev);
}

// 示例3:进度条
void OLED_Example_ProgressBar(void) {
    static uint8_t progress = 0;
    
    // 清屏
    OLED_ClearBuffer(&hdev, OLED_COLOR_BLACK);
    
    // 显示标题
    OLED_SetFont(&hdev, &Font_7x10);
    OLED_SetCursor(&hdev, 20, 0);
    OLED_WriteString(&hdev, "Progress Bar");
    
    // 绘制水平进度条
    OLED_SetCursor(&hdev, 0, 15);
    OLED_WriteString(&hdev, "Horizontal:");
    OLED_DrawProgressBar(&hdev, 10, 25, 100, 10, 1, progress, OLED_COLOR_WHITE);
    
    // 绘制垂直进度条
    OLED_SetCursor(&hdev, 0, 40);
    OLED_WriteString(&hdev, "Vertical:");
    OLED_DrawVerticalProgressBar(&hdev, 10, 50, 20, 40, 1, progress, OLED_COLOR_WHITE);
    
    // 显示进度值
    OLED_SetCursor(&hdev, 40, 55);
    OLED_Printf(&hdev, "Progress: %d%%", progress);
    
    // 更新进度
    progress += 5;
    if(progress > 100) progress = 0;
    
    // 更新显示
    OLED_UpdateScreen(&hdev);
}

// 示例4:波形图
void OLED_Example_Waveform(void) {
    static uint8_t waveform_data[64];
    static uint8_t data_index = 0;
    
    // 生成波形数据
    waveform_data[data_index] = 30 + 20 * (data_index % 20) / 20.0;
    data_index = (data_index + 1) % 64;
    
    // 清屏
    OLED_ClearBuffer(&hdev, OLED_COLOR_BLACK);
    
    // 显示标题
    OLED_SetFont(&hdev, &Font_7x10);
    OLED_SetCursor(&hdev, 30, 0);
    OLED_WriteString(&hdev, "Waveform");
    
    // 绘制波形
    OLED_DrawWaveform(&hdev, 5, 15, 118, 40, waveform_data, 64, OLED_COLOR_WHITE);
    
    // 显示信息
    OLED_SetCursor(&hdev, 0, 55);
    OLED_Printf(&hdev, "Data: %d", waveform_data[data_index]);
    
    // 更新显示
    OLED_UpdateScreen(&hdev);
}

// 示例5:菜单系统
void OLED_Example_Menu(void) {
    // 定义菜单项
    static OLED_MenuItem menu_items[] = {
        {"1. Basic Display", NULL},
        {"2. Graphics Demo", NULL},
        {"3. Progress Bar", NULL},
        {"4. Waveform", NULL},
        {"5. System Info", NULL},
        {"6. Settings", NULL},
    };
    
    static uint8_t selected_item = 0;
    
    // 绘制菜单
    OLED_DrawMenu(&hdev, menu_items, 6, selected_item);
    
    // 模拟按键选择
    selected_item = (selected_item + 1) % 6;
}

// 示例6:动画效果
void OLED_Example_Animation(void) {
    static uint8_t ball_x = 0;
    static uint8_t ball_y = 0;
    static int8_t ball_dx = 2;
    static int8_t ball_dy = 1;
    
    // 清屏
    OLED_ClearBuffer(&hdev, OLED_COLOR_BLACK);
    
    // 移动小球
    ball_x += ball_dx;
    ball_y += ball_dy;
    
    // 边界检测
    if(ball_x <= 5 || ball_x >= OLED_WIDTH - 5) ball_dx = -ball_dx;
    if(ball_y <= 5 || ball_y >= OLED_HEIGHT - 5) ball_dy = -ball_dy;
    
    // 绘制小球
    OLED_DrawFilledCircle(&hdev, ball_x, ball_y, 5, OLED_COLOR_WHITE);
    
    // 显示坐标
    OLED_SetFont(&hdev, &Font_5x7);
    OLED_SetCursor(&hdev, 0, 0);
    OLED_Printf(&hdev, "X:%d Y:%d", ball_x, ball_y);
    
    // 更新显示
    OLED_UpdateScreen(&hdev);
}

// 主函数
int main(void) {
    // HAL库初始化
    HAL_Init();
    
    // 系统时钟配置
    SystemClock_Config();
    
    // GPIO初始化
    MX_GPIO_Init();
    
    // I2C初始化
    MX_I2C1_Init();
    
    // OLED初始化
#if OLED_USE_I2C
    hdev.hi2c = &hi2c1;
    hdev.i2c_addr = 0x78;  // OLED I2C地址
#endif
    
    OLED_Init(&hdev);
    
    // 主循环
    uint8_t example_index = 0;
    while(1) {
        switch(example_index) {
            case 0:
                OLED_Example_Basic();
                HAL_Delay(2000);
                break;
                
            case 1:
                OLED_Example_Graphics();
                HAL_Delay(2000);
                break;
                
            case 2:
                for(int i = 0; i < 20; i++) {
                    OLED_Example_ProgressBar();
                    HAL_Delay(100);
                }
                break;
                
            case 3:
                for(int i = 0; i < 100; i++) {
                    OLED_Example_Waveform();
                    HAL_Delay(50);
                }
                break;
                
            case 4:
                OLED_Example_Menu();
                HAL_Delay(1000);
                break;
                
            case 5:
                for(int i = 0; i < 200; i++) {
                    OLED_Example_Animation();
                    HAL_Delay(20);
                }
                break;
        }
        
        example_index = (example_index + 1) % 6;
    }
}

11. 硬件连接

11.1 I2C连接方式

OLED屏幕    STM32F103C8T6
--------------------------------
VCC   ->   3.3V
GND   ->   GND
SCL   ->   PB6
SDA   ->   PB7

11.2 SPI连接方式

OLED屏幕    STM32F103C8T6
--------------------------------
VCC   ->   3.3V
GND   ->   GND
D0    ->   PA5 (SCK)
D1    ->   PA7 (MOSI)
RES   ->   PA0
DC    ->   PA1
CS    ->   PA4

12. 字体文件示例

12.1 字体数据 (fonts_data.c)

#include "fonts.h"

// 5x7 ASCII字体
const uint16_t Font5x7_Data[] = {
    // 空格 (ASCII 32)
    0x00, 0x00, 0x00, 0x00, 0x00,
    // !
    0x00, 0x00, 0x5F, 0x00, 0x00,
    // "
    0x00, 0x07, 0x00, 0x07, 0x00,
    // # 等等...
    // 完整的ASCII字符集
};

// 7x10 ASCII字体
const uint16_t Font7x10_Data[] = {
    // 字体数据
};

// 字体定义
FontDef Font_5x7 = {5, 7, Font5x7_Data};
FontDef Font_7x10 = {7, 10, Font7x10_Data};

13. 编译配置

13.1 Keil工程配置

# 包含路径
INCLUDE_PATHS = \
    ../Inc \
    ../Drivers/STM32F1xx_HAL_Driver/Inc \
    ../Drivers/CMSIS/Device/ST/STM32F1xx/Include \
    ../Drivers/CMSIS/Include \
    ../OLED

# 源文件
SOURCE_FILES = \
    Src/main.c \
    Src/stm32f1xx_it.c \
    Src/stm32f1xx_hal_msp.c \
    Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.c \
    Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c \
    Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c \
    OLED/oled.c \
    OLED/oled_i2c.c \
    OLED/oled_text.c \
    OLED/oled_bitmap.c \
    OLED/oled_chart.c \
    OLED/oled_menu.c \
    OLED/oled_anim.c \
    OLED/fonts_data.c

14. 使用注意事项

  1. 电源要求:OLED屏幕需要3.3V供电,避免使用5V
  2. 上拉电阻:I2C接口需要4.7K上拉电阻
  3. 刷新速率:全屏刷新约需5-10ms
  4. 显示寿命:避免长时间显示静态图像
  5. 温度范围:工作温度-40℃~+85℃
posted @ 2026-05-20 11:59  hczyydqq  阅读(15)  评论(0)    收藏  举报