本文基于STM32硬件I2C驱动SSD1306 OLED屏幕,提供完整的代码实现及关键注意事项,适用于128x32或128x64分辨率屏幕。代码通过模块化设计,支持显示字符、数字、汉字及位图,并优化了显存刷新机制。
零、完整代码
完整代码:
1)oled.c
/**
* @file oled.c
* @brief OLED显示驱动层,支持SSD1306控制器
* @details 提供OLED初始化、基本绘图、字符显示、显存刷新等功能
* @note 本驱动针对128x32分辨率和128x64OLED屏适配,需要修改106-110行的启动参数
*/
#include "oledfont.h"
#include "string.h"
#include "oled.h"
#include "stdlib.h"
#include "main.h"
extern I2C_HandleTypeDef hi2c1; ///< I2C外设句柄
/**
* @brief OLED绘制位图
* @param x0 起始列坐标(0~127)
* @param y0 起始页号(0~3)
* @param x1 结束列坐标(需大于x0)
* @param y1 结束页号(需大于y0)
* @param BMP 位图数据数组指针
* @note 页号与屏幕行的对应关系:每页8行,128x32屏共4页
*/
void OLED_DrawBMP(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char BMP[])
{
unsigned int j = 0;
unsigned char x, y;
if (y1 % 8 == 0)
y = y1 / 8;
else
y = y1 / 8 + 1;
for (y = y0; y < y1; y++)
{
OLED_Set_Pos(x0, y);
for (x = x0; x < x1; x++)
{
OLED_WR_Byte(BMP[j++], OLED_DATA);
}
}
}
// OLED的显存
// 存放格式如下.
//[0]0 1 2 3 ... 127
//[1]0 1 2 3 ... 127
//[2]0 1 2 3 ... 127
//[3]0 1 2 3 ... 127
//[4]0 1 2 3 ... 127
//[5]0 1 2 3 ... 127
//[6]0 1 2 3 ... 127
//[7]0 1 2 3 ... 127
// (128x64显存,8页)
uint8_t OLED_GRAM[128][8];
/**
* @brief 刷新显存到OLED物理屏幕
* @details 将GRAM数组内容通过I2C写入OLED的GDDRAM
*/
void OLED_Refresh_Gram(void)
{
uint8_t i, n;
for (i = 0; i < 4; i++)
{ // 仅刷新前4页(原为8)
OLED_WR_Byte(0xb0 + i, OLED_CMD);
OLED_WR_Byte(0x00, OLED_CMD);
OLED_WR_Byte(0x10, OLED_CMD);
for (n = 0; n < 128; n++)
OLED_WR_Byte(OLED_GRAM[n][i], OLED_DATA);
}
}
/**
* @brief 初始化SSD1306控制器
* @details 配置显示参数、硬件选项,执行上电序列
*/
void OLED_Init(void)
{
OLED_WR_Byte(0xAE,OLED_CMD);//关闭显示屏
OLED_WR_Byte(0x40,OLED_CMD);//设置起始行地址
OLED_WR_Byte(0xB0,OLED_CMD);//设置页面起始地址为页面寻址模式,0-7
OLED_WR_Byte(0xC8,OLED_CMD);//上下反置关(行重映射),C8,从COM[N-1]扫描到COM0;C0,设置 从COM0扫描到COM[N-1],N为复用率
OLED_WR_Byte(0x81,OLED_CMD);// 设置对比度
OLED_WR_Byte(0xff,OLED_CMD);// 选择0xff对比度,选择范围0x00-0xff
OLED_WR_Byte(0xa1,OLED_CMD);// 左右反置关(段重映射),A0H 设置GDDRAM的COL0映射到驱动器输出SEG0,A1H 设置COL127映射到SEG0
OLED_WR_Byte(0xa6,OLED_CMD);// 正常显示(1亮0灭)
OLED_WR_Byte(0xa8,OLED_CMD);// 设置多路传输比率,显示行数
OLED_WR_Byte(0x1f,OLED_CMD);// MUX=31 (显示31行)
OLED_WR_Byte(0xd3,OLED_CMD);// 设置垂直显示偏移(向上)
OLED_WR_Byte(0x00,OLED_CMD);// 偏移0行
OLED_WR_Byte(0xd5,OLED_CMD);// 设置DCLK分频和OSC频率
OLED_WR_Byte(0xf0,OLED_CMD);// 频率最高
OLED_WR_Byte(0xd9,OLED_CMD);// 设置预充电的持续时间
OLED_WR_Byte(0x22,OLED_CMD);
OLED_WR_Byte(0xda,OLED_CMD);// 设置COM引脚配置
// 128*32
OLED_WR_Byte(0x02,OLED_CMD);// 序列COM配置,禁用左右反置
// 128*64
// OLED_WR_Byte(0x12, OLED_CMD); // 交替COM,左右不反置
OLED_WR_Byte(0xdb,OLED_CMD);//调整Vcomh调节器的输出
OLED_WR_Byte(0x49,OLED_CMD);
OLED_WR_Byte(0x8d,OLED_CMD);// 启用电荷泵
OLED_WR_Byte(0x14,OLED_CMD);// 启用电荷泵
OLED_WR_Byte(0xaf,OLED_CMD);// 开OLED显示
OLED_Clear();
}
/**
* @brief 显示单个ASCII字符
* @param x 列坐标(0-127)
* @param y 页号(0-3)
* @param chr 要显示的字符
* @param Char_Size 字体大小:8或16
* @note 8像素字体使用6x8点阵,16像素使用8x16点阵
*/
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size)
{
unsigned char c = 0, i = 0;
c = chr - ' '; // 得到偏移后的值
if (x > Max_Column - 1)
{
x = 0;
// 原代码:y += 2(适用于8页,改为y += 1适应4页)
y = y + 1; // 每页高度为8像素,32行共4页
}
if (Char_Size == 16)
{
// 16像素字体占2页(原为两行,需确保不超过4页)
OLED_Set_Pos(x, y);
for (i = 0; i < 8; i++)
OLED_WR_Byte(F8X16[c * 16 + i], OLED_DATA);
OLED_Set_Pos(x, y + 1);
for (i = 0; i < 8; i++)
OLED_WR_Byte(F8X16[c * 16 + i + 8], OLED_DATA);
}
else if (Char_Size == 8)
{
OLED_Set_Pos(x, y);
for (i = 0; i < 6; i++)
OLED_WR_Byte(F6x8[c][i], OLED_DATA);
}
}
/**
* @brief 显示无符号整数
* @param x,y 起始坐标
* @param num 要显示的数字(0~4294967295)
* @param len 显示位数(自动截断高位)
* @param size2 字体大小(需为8或16)
*/
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size2) // OLED_ShowNum(103,6,t,3,16);//显示ASCII字符的码值
{
uint8_t t, temp;
uint8_t enshow = 0;
for (t = 0; t < len; t++)
{
temp = (num / oled_pow(10, len - t - 1)) % 10;
if (enshow == 0 && t < (len - 1))
{
if (temp == 0)
{
OLED_ShowChar(x + (size2 / 2) * t, y, ' ', size2);
continue;
}
else
enshow = 1;
}
OLED_ShowChar(x + (size2 / 2) * t, y, temp + '0', size2);
}
}
/**
* @brief 计算m的n次方
* @param m 底数
* @param n 指数
* @return m^n的值
*/
uint32_t oled_pow(uint8_t m, uint8_t n)
{
uint32_t result = 1;
while (n--)
result *= m;
return result;
}
/**
* @brief 显示字符串
* @param x,y 起始坐标
* @param chr 字符串数组指针
* @param Char_Size 字体大小(8或16)
* @note 字符串以'\0'结尾,自动计算长度
*/
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t chr[], uint8_t Char_Size)
{
unsigned char j = 0;
while (chr[j] != '\0')
{
OLED_ShowChar(x, y, chr[j], Char_Size);
x += 8;
if (x > Max_Column - 8)
{
x = 0;
y += 2;
}
j++;
}
}
/**
* @brief 显示汉字
* @param x,y 起始坐标
* @param no 汉字索引(0~7)
* @note 汉字数据存储在ZH数组中,索引范围为0~7
*/
void OLED_ShowCHinese(uint8_t x, uint8_t y, uint8_t no)
{
uint8_t t, adder = 0;
OLED_Set_Pos(x, y);
for (t = 0; t < 16; t++)
{
OLED_WR_Byte(ZH[2 * no][t], OLED_DATA);
adder += 1;
}
OLED_Set_Pos(x, y + 1);
for (t = 0; t < 16; t++)
{
OLED_WR_Byte(ZH[2 * no + 1][t], OLED_DATA);
adder += 1;
}
}
/**
* @brief 设置OLED显示位置
* @param x 列坐标(0~127)
* @param y 页号(0~3)
* @note 页号与屏幕行的对应关系:每页8行,128x32屏共4页
*/
void OLED_Set_Pos(unsigned char x, unsigned char y)
{
OLED_WR_Byte(0xb0 + y, OLED_CMD);
OLED_WR_Byte(((x & 0xf0) >> 4) | 0x10, OLED_CMD);
OLED_WR_Byte((x & 0x0f), OLED_CMD);
}
// 打开OLED显示
void OLED_Display_On(void)
{
OLED_WR_Byte(0X8D, OLED_CMD); // SET DCDC命令
OLED_WR_Byte(0X14, OLED_CMD); // DCDC ON
OLED_WR_Byte(0XAF, OLED_CMD); // DISPLAY ON
}
// 关闭OLED显示
void OLED_Display_Off(void)
{
OLED_WR_Byte(0X8D, OLED_CMD); // SET DCDC命令
OLED_WR_Byte(0X10, OLED_CMD); // DCDC OFF
OLED_WR_Byte(0XAE, OLED_CMD); // DISPLAY OFF
}
/**
* @brief 清空OLED显示
* @note 将所有像素设置为0(黑色)
*/
void OLED_Clear(void)
{
uint8_t i, n;
for (i = 0; i < 8; i++)
{
OLED_WR_Byte(0xb0 + i, OLED_CMD); // 设置页地址(0~7)
OLED_WR_Byte(0x00, OLED_CMD); // 设置显示位置—列低地址
OLED_WR_Byte(0x10, OLED_CMD); // 设置显示位置—列高地址
for (n = 0; n < 128; n++)
OLED_WR_Byte(0, OLED_DATA);
} // 更新显示
}
/**
* @brief 打开OLED显示
* @note 将所有像素设置为1(白色)
*/
void OLED_On(void)
{
uint8_t i, n;
for (i = 0; i < 8; i++)
{
OLED_WR_Byte(0xb0 + i, OLED_CMD); // 设置页地址(0~7)
OLED_WR_Byte(0x00, OLED_CMD); // 设置显示位置—列低地址
OLED_WR_Byte(0x10, OLED_CMD); // 设置显示位置—列高地址
for (n = 0; n < 128; n++)
OLED_WR_Byte(1, OLED_DATA);
} // 更新显示
}
/**
* @brief 填充OLED显示
* @param fill_Data 填充数据(0x00或0xFF)
* @note 0x00填充黑色,0xFF填充白色
*/
void fill_picture(unsigned char fill_Data)
{
unsigned char m, n;
for (m = 0; m < 8; m++)
{
OLED_WR_Byte(0xb0 + m, 0); // page0-page1
OLED_WR_Byte(0x00, 0); // low column start address
OLED_WR_Byte(0x10, 0); // high column start address
for (n = 0; n < 128; n++)
{
OLED_WR_Byte(fill_Data, 1);
}
}
}
/**
* @brief 写入数据或命令到OLED
* @param dat 要写入的数据
* @param cmd 0表示命令,1表示数据
* @note 通过I2C将数据发送到OLED控制器
*/
void OLED_WR_Byte(uint8_t dat, uint8_t cmd)
{
static uint8_t cmd_data[2];
if (cmd == OLED_CMD)
{
cmd_data[0] = 0x00;
}
else
{
cmd_data[0] = 0x40;
}
cmd_data[1] = dat;
HAL_I2C_Master_Transmit(&hi2c1, 0X78, cmd_data, 2, 10);
}
/**
* @brief 写入I2C命令或数据
* @param I2C_Command 要写入的命令或数据
* @note 通过I2C将数据发送到OLED控制器
*/
void Write_IIC_Command(unsigned char I2C_Command) // 写命令
{
uint8_t *pData;
pData = &I2C_Command;
HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT, pData, 1, 100);
}
/**
* @brief 写入I2C数据
* @param IIC_Data 要写入的数据
* @note 通过I2C将数据发送到OLED控制器
*/
void Write_IIC_Data(unsigned char IIC_Data) // 写数据
{
uint8_t *pData;
pData = &IIC_Data;
HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT, pData, 1, 100);
}
2)oled.h
#ifndef __OLED_H
#define __OLED_H
// #include "sys.h"
#include "main.h"
// OLED模式设置
// 0: 4线串行模式 (模块的BS1,BS2均接GND)
#define OLED_MODE 0
#define X_WIDTH 128
#define Y_WIDTH 32
#define Max_Column 128 // 列
#define Max_Row 32 // 行
#define SIZE 8
#define XLevelL 0x00
#define XLevelH 0x10
#define Brightness 0xFF
#define OLED_CMD 0 // 写命令
#define OLED_DATA 1 // 写数据
void Write_IIC_Data(unsigned char IIC_Data);
void Write_IIC_Command(unsigned char I2C_Command);
void OLED_WR_Byte(uint8_t dat, uint8_t cmd);
void fill_picture(unsigned char fill_Data);
void OLED_On(void);
void OLED_Clear(void);
void OLED_Display_Off(void);
void OLED_Display_On(void);
void OLED_Set_Pos(unsigned char x, unsigned char y);
void OLED_ShowCHinese(uint8_t x, uint8_t y, uint8_t no);
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t chr[], uint8_t Char_Size); // OLED_ShowString(0,0,a,sizeof(a));
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size2); // OLED_ShowNum(103,6,t,3,16);//显示ASCII字符的码值
uint32_t oled_pow(uint8_t m, uint8_t n);
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size);
void OLED_Init(void);
void OLED_Refresh_Gram(void);
void OLED_DrawBMP(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char BMP[]);
/*
x x x x x x x x x x x x x x x x ==16个字符列 y=0行
x x x x x x x x x x x x x x x x ==16个字符列 y=1行
x x x x x x x x x x x x x x x x ==16个字符列 y=2行
x x x x x x x x x x x x x x x x ==16个字符列 y=3行
x x x x x x x x x x x x x x x x ==16个字符列 y=4行
x x x x x x x x x x x x x x x x ==16个字符列 y=5行
x x x x x x x x x x x x x x x x ==16个字符列 y=6行
x x x x x x x x x x x x x x x x ==16个字符列 y=7行
*/
#endif
3) oledfont.h
#ifndef __OLEDFONT_H
#define __OLEDFONT_H
//常用ASCII表
//偏移量32
//ASCII字符集: !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
//PC2LCD2002取模方式设置:阴码+逐列式+顺向+C51格式
//总共:3个字符集(12*12、16*16和24*24),用户可以自行新增其他分辨率的字符集。
//每个字符所占用的字节数为:(size/8+((size%8)?1:0))*(size/2),其中size:是字库生成时的点阵大小(12/16/24...)
//12*12 ASCII字符集点阵
const unsigned char F6x8[][6] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,// sp
0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,// !
0x00, 0x00, 0x07, 0x00, 0x07, 0x00,// "
0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14,// #
0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12,// $
0x00, 0x62, 0x64, 0x08, 0x13, 0x23,// %
0x00, 0x36, 0x49, 0x55, 0x22, 0x50,// &
0x00, 0x00, 0x05, 0x03, 0x00, 0x00,// '
0x00, 0x00, 0x1c, 0x22, 0x41, 0x00,// (
0x00, 0x00, 0x41, 0x22, 0x1c, 0x00,// )
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14,// *
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08,// +
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00,// ,
0x00, 0x08, 0x08, 0x08, 0x08, 0x08,// -
0x00, 0x00, 0x60, 0x60, 0x00, 0x00,// .
0x00, 0x20, 0x10, 0x08, 0x04, 0x02,// /
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E,// 0
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00,// 1
0x00, 0x42, 0x61, 0x51, 0x49, 0x46,// 2
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31,// 3
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10,// 4
0x00, 0x27, 0x45, 0x45, 0x45, 0x39,// 5
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30,// 6
0x00, 0x01, 0x71, 0x09, 0x05, 0x03,// 7
0x00, 0x36, 0x49, 0x49, 0x49, 0x36,// 8
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E,// 9
0x00, 0x00, 0x36, 0x36, 0x00, 0x00,// :
0x00, 0x00, 0x56, 0x36, 0x00, 0x00,// ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00,// <
0x00, 0x14, 0x14, 0x14, 0x14, 0x14,// =
0x00, 0x00, 0x41, 0x22, 0x14, 0x08,// >
0x00, 0x02, 0x01, 0x51, 0x09, 0x06,// ?
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E,// @
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C,// A
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36,// B
0x00, 0x3E, 0x41, 0x41, 0x41, 0x22,// C
0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C,// D
0x00, 0x7F, 0x49, 0x49, 0x49, 0x41,// E
0x00, 0x7F, 0x09, 0x09, 0x09, 0x01,// F
0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A,// G
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F,// H
0x00, 0x00, 0x41, 0x7F, 0x41, 0x00,// I
0x00, 0x20, 0x40, 0x41, 0x3F, 0x01,// J
0x00, 0x7F, 0x08, 0x14, 0x22, 0x41,// K
0x00, 0x7F, 0x40, 0x40, 0x40, 0x40,// L
0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F,// M
0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F,// N
0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E,// O
0x00, 0x7F, 0x09, 0x09, 0x09, 0x06,// P
0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E,// Q
0x00, 0x7F, 0x09, 0x19, 0x29, 0x46,// R
0x00, 0x46, 0x49, 0x49, 0x49, 0x31,// S
0x00, 0x01, 0x01, 0x7F, 0x01, 0x01,// T
0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F,// U
0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F,// V
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F,// W
0x00, 0x63, 0x14, 0x08, 0x14, 0x63,// X
0x00, 0x07, 0x08, 0x70, 0x08, 0x07,// Y
0x00, 0x61, 0x51, 0x49, 0x45, 0x43,// Z
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00,// [
0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55,// 55
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00,// ]
0x00, 0x04, 0x02, 0x01, 0x02, 0x04,// ^
0x00, 0x40, 0x40, 0x40, 0x40, 0x40,// _
0x00, 0x00, 0x01, 0x02, 0x04, 0x00,// '
0x00, 0x20, 0x54, 0x54, 0x54, 0x78,// a
0x00, 0x7F, 0x48, 0x44, 0x44, 0x38,// b
0x00, 0x38, 0x44, 0x44, 0x44, 0x20,// c
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F,// d
0x00, 0x38, 0x54, 0x54, 0x54, 0x18,// e
0x00, 0x08, 0x7E, 0x09, 0x01, 0x02,// f
0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C,// g
0x00, 0x7F, 0x08, 0x04, 0x04, 0x78,// h
0x00, 0x00, 0x44, 0x7D, 0x40, 0x00,// i
0x00, 0x40, 0x80, 0x84, 0x7D, 0x00,// j
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00,// k
0x00, 0x00, 0x41, 0x7F, 0x40, 0x00,// l
0x00, 0x7C, 0x04, 0x18, 0x04, 0x78,// m
0x00, 0x7C, 0x08, 0x04, 0x04, 0x78,// n
0x00, 0x38, 0x44, 0x44, 0x44, 0x38,// o
0x00, 0xFC, 0x24, 0x24, 0x24, 0x18,// p
0x00, 0x18, 0x24, 0x24, 0x18, 0xFC,// q
0x00, 0x7C, 0x08, 0x04, 0x04, 0x08,// r
0x00, 0x48, 0x54, 0x54, 0x54, 0x20,// s
0x00, 0x04, 0x3F, 0x44, 0x40, 0x20,// t
0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C,// u
0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C,// v
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C,// w
0x00, 0x44, 0x28, 0x10, 0x28, 0x44,// x
0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C,// y
0x00, 0x44, 0x64, 0x54, 0x4C, 0x44,// z
0x14, 0x14, 0x14, 0x14, 0x14, 0x14,// horiz lines
};
/****************************************8*16的点阵************************************/
const unsigned char F8X16[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};
char ZH[][32]={
{0x40,0x44,0x54,0x65,0xC6,0x64,0x54,0x44,0x00,0xFC,0x44,0x44,0xC4,0x42,0x40,0x00},
{0x20,0x12,0x4A,0x82,0x7F,0x02,0x0A,0x92,0x60,0x1F,0x00,0x00,0xFF,0x00,0x00,0x00},/*"新",0*/
{0x00,0x20,0x18,0xC7,0x44,0x44,0x44,0x44,0xFC,0x44,0x44,0x44,0x44,0x04,0x00,0x00},
{0x04,0x04,0x04,0x07,0x04,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0x04,0x04,0x00},/*"年",1*/
{0x00,0xE0,0x00,0xFF,0x10,0x20,0x08,0x08,0x08,0xFF,0x08,0x08,0xF8,0x00,0x00,0x00},
{0x01,0x00,0x00,0xFF,0x00,0x81,0x41,0x31,0x0D,0x03,0x0D,0x31,0x41,0x81,0x81,0x00},/*"快",2*/
{0x00,0x00,0xE0,0x9C,0x84,0x84,0x84,0xF4,0x82,0x82,0x83,0x82,0x80,0x80,0x00,0x00},
{0x00,0x20,0x10,0x08,0x06,0x40,0x80,0x7F,0x00,0x00,0x02,0x04,0x08,0x30,0x00,0x00},/*"乐",3*/
{0x40,0x30,0x11,0x96,0x90,0x90,0x91,0x96,0x90,0x90,0x98,0x14,0x13,0x50,0x30,0x00},
{0x04,0x04,0x04,0x04,0x04,0x44,0x84,0x7E,0x06,0x05,0x04,0x04,0x04,0x04,0x04,0x00},/*"学",4*/
{0x80,0x80,0x80,0x80,0xFF,0x80,0x80,0xA0,0x90,0x88,0x84,0x82,0x80,0x80,0x80,0x00},
{0x00,0x00,0x00,0x00,0xFF,0x40,0x21,0x12,0x04,0x08,0x10,0x20,0x20,0x40,0x40,0x00},/*"长",5*/
{0x20,0x24,0x24,0x24,0xFE,0x23,0x22,0x20,0x20,0xFF,0x20,0x22,0x2C,0xA0,0x20,0x00},
{0x00,0x08,0x48,0x84,0x7F,0x02,0x41,0x40,0x20,0x13,0x0C,0x14,0x22,0x41,0xF8,0x00},/*"我",6*/
{0x10,0x0C,0x04,0x24,0x24,0x24,0x25,0x26,0x24,0x24,0x24,0x24,0x04,0x14,0x0C,0x00},
{0x00,0x81,0x81,0x41,0x31,0x0F,0x01,0x01,0x01,0x7F,0x81,0x81,0x81,0xF1,0x00,0x00},/*"完",7*/
{0x00,0x00,0xF8,0x88,0x88,0x88,0x88,0x08,0x08,0xFF,0x08,0x09,0x0A,0xC8,0x08,0x00},
{0x80,0x60,0x1F,0x00,0x10,0x20,0x1F,0x80,0x40,0x21,0x16,0x18,0x26,0x41,0xF8,0x00},/*"成",8*/
{0x00,0xFC,0x04,0xFC,0x00,0x10,0x10,0xFF,0x90,0xC8,0x09,0x0E,0x08,0xE8,0x08,0x00},
{0x00,0x0F,0x04,0x0F,0x00,0x44,0x82,0x7F,0x00,0x40,0x4F,0x60,0x5C,0x43,0x40,0x00},/*"啦",9*/
{0x10,0x88,0xC4,0x33,0x00,0x20,0x10,0x28,0x24,0xE3,0x24,0x28,0x10,0x20,0x20,0x00},
{0x01,0x00,0xFF,0x00,0x20,0x11,0x0D,0x41,0x81,0x7F,0x01,0x05,0x09,0x31,0x00,0x00},/*"徐",10*/
/* (16 X 16 , 宋体 )*/
{0x00,0xFE,0x22,0xFE,0x00,0xFE,0x22,0xFE,0x00,0xFC,0x16,0x25,0x84,0xFC,0x00,0x00},
{0x60,0x1F,0x22,0xBF,0x40,0x3F,0x82,0xFF,0x00,0x13,0x12,0x12,0x52,0x82,0x7E,0x00},/*"鹏",11*/
/* (16 X 16 , 宋体 )*/
{0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0xFE,0x40,0xA0,0x10,0x08,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0C,0x10,0x21,0x42,0xF0,0x00},/*"飞",12*/
/* (16 X 16 , 宋体 )*/
//每个字必须带大括号否则显示效果不好
};
#endif
(注:需根据具体硬件调整I2C引脚和屏幕参数)
一、硬件连接
- OLED屏幕:SSD1306控制器,支持I2C通信。
- STM32引脚配置:
- SCL:I2C时钟线(如PB6)
- SDA:I2C数据线(如PB7)
- I2C地址:0x78(若屏幕带RESET引脚,需额外配置)
二、代码结构
1. 核心文件说明
- oled.c:驱动层实现,包含初始化、显存管理、字符显示等功能。
- oled.h:定义宏、函数原型及屏幕参数。
- oledfont.h:存储ASCII和汉字点阵数据(6x8、8x16字体)。
2. 关键函数解析
- OLED_Init():初始化SSD1306控制器,配置显示参数。
void OLED_Init(void) {
OLED_WR_Byte(0xAE, OLED_CMD); // 关闭显示
OLED_WR_Byte(0xD5, OLED_CMD); // 设置时钟分频
OLED_WR_Byte(0xA8, OLED_CMD); // 设置复用率
// ... 其他配置命令
OLED_Clear(); // 清屏
}
- OLED_Refresh_Gram():将显存数据刷新到物理屏幕,通过I2C逐页写入。
- OLED_ShowChar():显示单个字符,支持8/16像素字体,自动换行。
三、关键实现细节
1. 显存管理
- 显存数组:OLED_GRAM[128][8],每页8行,共4页(128x32)或8页(128x64)。
- 刷新逻辑:仅刷新有效页,减少I2C传输量。
void OLED_Refresh_Gram(void) {
for (uint8_t i = 0; i < 4; i++) { // 仅刷新前4页
OLED_Set_Pos(0, i);
HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT, OLED_GRAM[i], 128, 100);
}
}
2. 字体显示优化
- ASCII字符:使用F6x8和F8X16点阵数据,通过偏移量快速定位。
- 汉字显示:预存储常用汉字点阵(如“新年快乐”),通过索引调用。
void OLED_ShowCHinese(uint8_t x, uint8_t y, uint8_t no) {
OLED_Set_Pos(x, y);
for (uint8_t t = 0; t < 16; t++)
OLED_WR_Byte(ZH[2*no][t], OLED_DATA); // 写入上半部分
OLED_Set_Pos(x, y+1);
for (uint8_t t = 0; t < 16; t++)
OLED_WR_Byte(ZH[2*no+1][t], OLED_DATA); // 写入下半部分
}
四、注意事项(重点!)
头文件包含问题
- main.c中禁止包含oledfont.h,否则报错:工程\工程名.axf: Error: L6200E: Symbol F6x8 multiply defined (by gpio.o and main.o).等。
- 正确做法:仅在oled.c中包含oledfont.h,其他文件通过extern引用。
屏幕参数调整
- 修改初始化参数(oled.c第106-110行),否则字符高度异常。
// 128x32屏配置
OLED_WR_Byte(0xDA, OLED_CMD);
OLED_WR_Byte(0x02, OLED_CMD); // COM引脚配置
// 128x64屏需改为:OLED_WR_Byte(0x12, OLED_CMD);
I2C地址与速率
- 确认OLED的I2C地址(通常为0x78或0x7A)。
- 调整I2C时钟频率(STM32默认100kHz,SSD1306支持400kHz)。
- extern I2C_HandleTypeDef hi2c1; ///< I2C外设句柄,根据实际情况改
五、使用示例
显示字符串和数字
OLED_ShowString(0, 0, "Hello World!", 16); // 16像素字体
OLED_ShowNum(0, 2, 2023, 4, 16); // 显示数字2023
显示自定义位图
const uint8_t BMP[] = {0xFF, 0x81, 0xBD, ...}; // 位图数据
OLED_DrawBMP(0, 0, 128, 4, BMP); // 全屏显示位图
六、常见问题
- 屏幕不显示:检查I2C地址、引脚配置及初始化序列。
- 字符错位:确认OLED_Set_Pos()的页号与显存对应关系。
- 刷新闪烁:提高刷新频率(建议200Hz以上),或使用双缓冲机制。
感谢婷婷后援团的小徐同学❤❤❤