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. 使用注意事项
- 电源要求:OLED屏幕需要3.3V供电,避免使用5V
- 上拉电阻:I2C接口需要4.7K上拉电阻
- 刷新速率:全屏刷新约需5-10ms
- 显示寿命:避免长时间显示静态图像
- 温度范围:工作温度-40℃~+85℃

浙公网安备 33010602011771号