STM32硬件I2C驱动OLED屏幕
这个实现包含完整的OLED驱动库,支持初始化、清屏、像素绘制和字符串显示功能。使用STM32硬件I2C接口与SSD1306 OLED通信,包含必要的初始化配置和底层驱动函数。
在STM32中使用硬件I2C驱动OLED屏幕,通常涉及以下几个关键步骤:
一、硬件连接
首先,需要将STM32的I2C接口连接到OLED显示屏的SDA和SCL引脚。具体的引脚连接取决于你所使用的STM32型号和OLED模块。一般来说,STM32的I2C接口引脚可以配置为复用功能,用于I2C通信。
二、初始化I2C接口
在STM32的固件中,需要正确配置I2C接口的相关参数,如时钟速率、地址模式等。这通常包括:
- 启用I2C外设时钟:通过配置RCC(时钟控制寄存器)来启用I2C外设的时钟。
- 配置GPIO引脚:将用于I2C通信的GPIO引脚配置为复用功能,并设置为开漏输出模式(因为I2C总线需要线与功能)。
- 初始化I2C外设:设置I2C的通信速率、地址模式等参数。STM32的I2C外设支持标准模式(100Kbit/s)、快速模式(400Kbit/s)和高速模式(3.4Mbit/s)。
三、初始化OLED屏幕
OLED屏幕通常使用SSD1306等驱动芯片,这些芯片支持I2C接口。初始化OLED屏幕包括发送一系列的控制指令到OLED驱动IC,以配置显示屏的显示参数。这些指令通常包括:
- 关闭显示屏:在初始化过程中,可能需要先关闭显示屏,以避免在配置过程中显示不必要的内容。
- 设置对比度:调整显示屏的对比度以适应不同的环境光线条件。
- 设置显示方向:根据应用需求设置显示屏的显示方向(如正常显示、左右反置、上下反置等)。
- 启用电荷泵:SSD1306等驱动芯片通常内置电荷泵,用于提供显示屏所需的高压。在初始化过程中需要启用电荷泵。
四、编写显示函数
在初始化OLED屏幕后,需要编写显示函数来实现字符、图像等内容的显示。这通常包括:
- 定义字符和图像的显示区域:根据应用需求定义字符和图像的显示位置和大小。
- 发送显示数据:将字符或图像的数据通过I2C接口发送到OLED驱动IC中。
- 刷新显示屏:在发送完显示数据后,需要刷新显示屏以更新显示内容。
五、优化显示效果
为了获得更好的显示效果,可以对显示过程进行优化。例如:
- 调整对比度:根据实际应用场景调整显示屏的对比度。
- 减少闪烁:通过调整显示缓冲区的使用来减少显示闪烁。
- 实现自定义字形:根据应用需求实现自定义的字形以适应显示内容的需求。
六、测试与调试
在完成以上步骤后,需要通过STM32开发板进行实际测试,并通过调试器检查I2C总线上的通信内容,确保数据正确发送和接收。在测试过程中,可以观察显示屏的显示效果,并根据需要进行调整和优化。
OLED屏幕基础介绍
OLED(Organic Light Emitting Diode)即有机发光二极管,是一种基于有机半导体材料的显示技术。与传统的LCD(液晶显示器)相比,OLED屏幕具有自发光、高对比度、广视角、快速响应和轻薄可弯曲等显著优势。
OLED屏幕的工作原理
OLED屏幕由多层有机材料组成,当电流通过时,这些有机材料会发光。每个像素点都可以独立控制其开关状态,从而实现高对比度和纯黑色显示(关闭的像素点不发光)。
OLED屏幕的主要特点
- 自发光:无需背光灯,每个像素点独立发光。
- 高对比度:能够显示纯黑色,对比度极高。
- 广视角:视角可达170度以上,侧视画面不失真。
- 快速响应:响应时间极短,适合显示动态画面。
- 轻薄可弯曲:可制成柔性屏,应用于可穿戴设备和曲面显示。
OLED屏幕的驱动方式
OLED屏幕通常通过I2C或SPI接口与微控制器(如STM32)连接。以下是使用STM32硬件I2C驱动OLED屏幕的要点:
1. 硬件连接
- I2C接口:连接STM32的I2C引脚(如SCL和SDA)到OLED屏幕的对应引脚。
- 电源和地:确保OLED屏幕的电源(VCC)和地(GND)正确连接。
2. I2C初始化
- 配置I2C外设:设置I2C的时钟速率、地址模式等参数。
- 启用I2C外设时钟:通过RCC配置启用I2C外设的时钟。
- 配置GPIO引脚:将用于I2C通信的GPIO引脚配置为复用功能,并设置为开漏输出模式。
3. OLED屏幕初始化
- 发送初始化指令:通过I2C接口发送一系列控制指令到OLED驱动IC,以配置显示屏的显示参数。
- 设置对比度:调整显示屏的对比度以适应不同的环境光线条件。
- 设置显示方向:根据应用需求设置显示屏的显示方向。
4. 显示函数编写
- 定义显示区域:根据应用需求定义字符和图像的显示位置和大小。
- 发送显示数据:将字符或图像的数据通过I2C接口发送到OLED驱动IC中。
- 刷新显示屏:在发送完显示数据后,刷新显示屏以更新显示内容。
ssd1306.h
#ifndef __SSD1306_H
#define __SSD1306_H
#include "stm32f1xx_hal.h"
#define SSD1306_I2C_ADDR 0x78
#define SSD1306_WIDTH 128
#define SSD1306_HEIGHT 64
void SSD1306_Init(void);
void SSD1306_Clear(void);
void SSD1306_Update(void);
void SSD1306_DrawPixel(uint8_t x, uint8_t y, uint8_t color);
void SSD1306_WriteString(uint8_t x, uint8_t y, char* str, uint8_t size);
#endif

ssd1306.c
#include "ssd1306.h"
#include "fonts.h"
extern I2C_HandleTypeDef hi2c1;
static uint8_t buffer[SSD1306_WIDTH * SSD1306_HEIGHT / 8];
static void SSD1306_WriteCommand(uint8_t cmd) {
uint8_t data[2] = {0x00, cmd};
HAL_I2C_Master_Transmit(&hi2c1, SSD1306_I2C_ADDR, data, 2, 100);
}
static void SSD1306_WriteData(uint8_t* data, uint16_t size) {
uint8_t d[size+1];
d[0] = 0x40;
memcpy(&d[1], data, size);
HAL_I2C_Master_Transmit(&hi2c1, SSD1306_I2C_ADDR, d, size+1, 100);
}
void SSD1306_Init(void) {
HAL_Delay(100);
SSD1306_WriteCommand(0xAE); // Display off
SSD1306_WriteCommand(0x20); // Set Memory Addressing Mode
SSD1306_WriteCommand(0x10); // Page Addressing Mode
SSD1306_WriteCommand(0xB0); // Set Page Start Address
SSD1306_WriteCommand(0xC8); // Set COM Output Scan Direction
SSD1306_WriteCommand(0x00); // Set low column address
SSD1306_WriteCommand(0x10); // Set high column address
SSD1306_WriteCommand(0x40); // Set start line address
SSD1306_WriteCommand(0x81); // Set contrast control
SSD1306_WriteCommand(0xFF); // Contrast value
SSD1306_WriteCommand(0xA1); // Set segment re-map
SSD1306_WriteCommand(0xA6); // Set normal display
SSD1306_WriteCommand(0xA8); // Set multiplex ratio
SSD1306_WriteCommand(0x3F); // 1/64 duty
SSD1306_WriteCommand(0xD3); // Set display offset
SSD1306_WriteCommand(0x00); // No offset
SSD1306_WriteCommand(0xD5); // Set display clock divide ratio
SSD1306_WriteCommand(0xF0); // Set divide ratio
SSD1306_WriteCommand(0xD9); // Set pre-charge period
SSD1306_WriteCommand(0x22); // Pre-charge period
SSD1306_WriteCommand(0xDA); // Set COM pins hardware configuration
SSD1306_WriteCommand(0x12); // Alternative COM pin config
SSD1306_WriteCommand(0xDB); // Set VCOMH
SSD1306_WriteCommand(0x20); // VCOM deselect level
SSD1306_WriteCommand(0x8D); // Set DC-DC enable
SSD1306_WriteCommand(0x14); // DC-DC enabled
SSD1306_WriteCommand(0xAF); // Display on
SSD1306_Clear();
SSD1306_Update();
}
void SSD1306_Clear(void) {
memset(buffer, 0, sizeof(buffer));
}
void SSD1306_Update(void) {
for(uint8_t i=0; i<8; i++) {
SSD1306_WriteCommand(0xB0 + i);
SSD1306_WriteCommand(0x00);
SSD1306_WriteCommand(0x10);
SSD1306_WriteData(&buffer[SSD1306_WIDTH*i], SSD1306_WIDTH);
}
}
void SSD1306_DrawPixel(uint8_t x, uint8_t y, uint8_t color) {
if(x >= SSD1306_WIDTH || y >= SSD1306_HEIGHT) return;
if(color) buffer[x + (y/8)*SSD1306_WIDTH] |= (1 << (y%8));
else buffer[x + (y/8)*SSD1306_WIDTH] &= ~(1 << (y%8));
}
void SSD1306_WriteString(uint8_t x, uint8_t y, char* str, uint8_t size) {
while(*str) {
if(x + 6 >= SSD1306_WIDTH) { x = 0; y++; }
if(y >= (SSD1306_HEIGHT/8)) return;
for(uint8_t i=0; i<5; i++) {
uint8_t c = Font5x7[*str - 32][i];
for(uint8_t j=0; j<8; j++, c>>=1) {
if(c & 1) SSD1306_DrawPixel(x+i, y*8+j, 1);
}
}
x += 6;
str++;
}
}

fonts.h
__FONTS_H
#define __FONTS_H
static const unsigned char Font5x7[][5] = {
{0x00,0x00,0x00,0x00,0x00}, //
{0x00,0x00,0x5F,0x00,0x00}, // !
{0x00,0x07,0x00,0x07,0x00}, // "
// 其他ASCII字符...
{0x7C,0x12,0x11,0x12,0x7C}, // A
{0x7F,0x49,0x49,0x49,0x36}, // B
// 更多字符...
};
#endif
main.c
"stm32f1xx_hal.h"
#include "ssd1306.h"
I2C_HandleTypeDef hi2c1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
SSD1306_Init();
SSD1306_WriteString(0, 0, "Hello World!", 1);
SSD1306_Update();
while(1) {
HAL_Delay(1000);
}
}
void SystemClock_Config(void) {
// 系统时钟配置代码...
}
static void MX_I2C1_Init(void) {
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000;
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;
if(HAL_I2C_Init(&hi2c1) != HAL_OK) {
Error_Handler();
}
}
static void MX_GPIO_Init(void) {
// GPIO初始化代码...
}
代码说明:这个实现包含完整的OLED驱动库,支持初始化、清屏、像素绘制和字符串显示功能。使用STM32硬件I2C接口与SSD1306 OLED通信,包含必要的初始化配置和底层驱动函数。

一、代码架构
-
头文件定义(ssd1306.h)
- 定义了OLED的基本参数(地址0x78,分辨率128x64)
- 声明了核心功能函数:初始化、清屏、刷新显示、画点、写字符串
-
驱动实现(ssd1306.c)
- 包含两个关键底层函数:
- SSD1306_WriteCommand():发送控制命令(0x00前缀)
- SSD1306_WriteData():发送显示数据(0x40前缀)
- 显示缓冲区buffer[]:存储128x64/8=1024字节的显存数据
-
字库文件(fonts.h)
- 提供5x7点阵ASCII字库
- 每个字符用5字节表示,每字节对应一列像素
二、核心函数解析
-
初始化流程(SSD1306_Init())
- 发送27条配置指令(包含显示模式、扫描方向、对比度等)
- 关键配置:
- 0xAE/0xAF:显示开关
- 0x20/0x10:页寻址模式
- 0xC8:反向COM扫描
- 0xA1:段重映射
- 0xD5/0xF0:时钟分频
-
显示更新机制(SSD1306_Update())
- 分8页(每页8行)更新显存
- 每页发送:页地址(0xB0~0xB7) + 列起始地址(0x00,0x10)
- 通过I2C批量传输128字节页数据
-
绘图原理(SSD1306_DrawPixel())
- 计算像素位置:x + (y/8)*128
- 位操作:1<<(y%8)定位具体bit
- 支持两种颜色:置位(1)或清零(0)
三、硬件接口配置
-
I2C配置(MX_I2C1_Init())
- 400kHz速率(标准模式)
- 7位地址模式
- 无拉伸模式
-
通信协议特点
- 控制字节:0x00(命令)/0x40(数据)
- 每次传输添加前缀字节
- 使用HAL_I2C_Master_Transmit()发送
四、使用示例
-
主程序流程
- 初始化HAL库和硬件外设
- OLED初始化后显示"Hello World!"
- 通过SSD1306_Update()刷新显示
-
扩展功能
- 可修改Font5x7数组添加自定义字库
- 通过组合DrawPixel()实现图形绘制
- 支持多国语言需扩展字库
五、注意事项
-
硬件连接
- SCL:PB6(I2C1)
- SDA:PB7(I2C1)
- 需接上拉电阻(通常4.7kΩ)
-
性能优化
- 可改用DMA传输提升刷新率
- 局部刷新替代全屏刷新
- 使用硬件加速的位操作
-
常见问题
- 地址冲突时调整0x78/0x7A
- 初始化失败检查复位时序
- 显示异常验证电压电平
该实现完整展示了嵌入式图形显示的典型开发流程,涉及硬件接口、显示协议、字库处理等关键技术点。

更多推荐




所有评论(0)