STM32 基于HAL库的硬件I2C驱动SSD1306

本文详细介绍了SSD1306 OLED驱动的I2C通信流程,包括地址设置、有效信息构成、寻址模式(页寻址、水平/垂直寻址)、初始化步骤和驱动实现。通过硬件I2C,掌握如何调整对比度、设置显示状态和优化通信效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


SSD1306 介绍

SSD1306 是一款 OLED 驱动芯片,可以驱动 64*128px 的OLED屏幕。允许主机使用 I2C、6800、8080、4线SPI、3线SPI 方式进行通信,为 BS[2:0] 设置不同的电平以实现通信方式的选择,本文介绍的是采用硬件 I2C 的通信方式,。


I2C 通信流程

I2C通信流程

上图所示为 I2C 通信,将连续的 Control byteData byte 称为一组有效信息,可以看到,发出地址字节后,主机必须发送至少1次的有效信息。

I2C 通信地址

SSD1306 的 I2C 地址中 [1:7] 位为 0111100 或 0111101,第1位代表进行读或写操作,由于 OLED 为一输出设备,故第1位应固定为0,所以SSD1306的两种 I2C 地址位 0x780x7A

有效信息

一个 Control byte 与一个 Data byte 构成一组有效信息,其中 Control byte 为:

76543210
CoD/C#000000
  • Co位被设置为逻辑“0”,表示其后会传输一位 Data byte

  • D/C位决定将后一位 Data byte 解释为命令或数据。如果D/C位是“0”,则将 Data byte 定义为命令。若为“1”,则将 Data byte 定义为数据。

使用硬件 I2C 通信

SSD1306 的一次有效通信中应至少包含一组有效信息,故可简化为,每次与 SSD1306 通信均只发送一组有效信息。则这次通信中共发送三个字节,分别是 地址Control byteData byte。故可以使用 HAL 库中提供的 HAL_I2C_Mem_Write 方法,将 Control byte 作为寄存器地址发送,并再发送一字节的数据。其中地址固定为 0x78Control byte0x400x00


SSD1306 结构

SSD1306 将 OLED 屏幕划分成了 8 页,每页中右 8 行、128列,如下图所示:

屏幕分区

寻址模式 (内容更新模式)

由于一次有效通信只能写入一字节的数据,只允许更新某一页中某一列共8位的显示内容。倘若在每次更新前指定更新位置,则存在一定的浪费,SSD1306 提供了三种寻址模式,可以连续更新显示内容。

页寻址

页寻址是默认的寻址模式,它具有以下特性:

  1. 列地址指针每次自动加1,如果列地址指针到达最后一个地址,将会自动复位到开始的地址;
  2. 页地址不会自动增加,必须手动设置新的页地址;

页寻址

在这个模式下,设置页地址需要通过以下一个字节实现

76543210作用
10110X2X1X0设置页地址

发送以上字节,则页地址被设置为 X[2:0],

在这个模式下,设置列地址需要通过以下两个字节实现

76543210作用
0000X3X2X1X0设置列地址低四位
0000X7X6X5X4设置列地址高四位

连续发送以上两个字节,则列地址被设置为 X[7:0]

水平寻址模式

在水平寻址模式下,列地址指针自动加1,如果列地址指针到达最后一个地址,将会自动复位到开始的地址,同时页地址指针也自动加1。

水平寻址模式

垂直寻址模式

在垂直寻址模式下,页地址指针自动加1,如果页地址指针到达最后一个地址,将会自动复位到开始的地址,同时列地址指针也自动加1。

垂直寻址模式

在水平和垂直寻址模式下,需要设置页的起始和结束位置、列的起始和结束位置,需发送以下字节:

76543210作用
00100001开始设置列地址
*A6A5A4A3A2A1A0设置起始列地址为 A[6:0],默认为0
*B6B5B4B3B2B1B0设置结束列地址为 B[6:0],默认为127
00100010开始设置页地址
*****A2A1A0设置起始页地址为 A[2:0],默认为0
*****B2B1B0设置结束页地址为 B[2:0],默认为7

* 表示此位置对结果不产生影响

设置寻址模式

设置寻址模式需要发送以下字节:

76543210作用
00100000开始设置寻址模式
******A1A000b 水平寻址模式;01b 垂直寻址模式;10b 页寻址模式

SSD1306 初始化

SSD1306 上电后应首先进行初始化,我将会选择初始化中几个重要步骤进行解释:

关闭显示器

上电第一步应关闭显示器,以避免初始化过程中屏幕上显示寄存器中存留的内容,需发送以下字节

76543210作用
1010111XX=0 显示关;X=1 显示开

设置对比度

使用以下字节设置对比度

76543210作用
10000001开始设置对比度
A7A6A5A4A3A2A1A0设置对比度为A[7:0],默认为0x7F

设置整体显示状态

使用以下字节设置显示状态

76543210作用
1010010XX=0 显示RAM中的内容;X=1 不显示RAM中的内容

其他命令需阅读datasheet
https://wenku.baidu.com/view/6d6497a53d1ec5da50e2524de518964bce84d233.html

详细流程

初始化包括很多环节的设置,由于不能确定 MCU 上电时 SSD1306 的状态,所以即使我们需要的状态时默认状态,还是建议重新进行设定。
详细代码如下,可以参照注释进行分析。

    OLED_Write_Byte(CmdReg, OLED_OFF);  //关闭显示器
    OLED_Write_Byte(CmdReg, 0x20);  //设置内存寻址模式Set Memory Addressing Mode
    // 00,水平寻址模式 01,垂直寻址模式 02,页面寻址模式(默认)
    OLED_Write_Byte(CmdReg, 0x01);
    OLED_Write_Byte(CmdReg, 0x81);  //设置对比度
    OLED_Write_Byte(CmdReg, 0xff);  //对比度,数值越大对比度越高
    OLED_Write_Byte(CmdReg, 0xc8);  //扫描方向 不上下翻转Com scan direction
    OLED_Write_Byte(CmdReg, 0xa1);  //设置段重新映射 不左右翻转set segment remap
    OLED_Write_Byte(CmdReg, 0xa8);  //设置多路复用比(1-64)
    OLED_Write_Byte(CmdReg, 0x3f);  //设定值1/32  1/32 duty
    OLED_Write_Byte(CmdReg, 0xd3);  //设置显示偏移 set display offset
    OLED_Write_Byte(CmdReg, 0x00);  //
    OLED_Write_Byte(CmdReg, 0xd5);  //设置osc分区 set osc division
    OLED_Write_Byte(CmdReg, 0x80);  //
    OLED_Write_Byte(CmdReg, 0xd8);  //关闭区域颜色模式 set area color mode off
    OLED_Write_Byte(CmdReg, 0x05);  //
    OLED_Write_Byte(CmdReg, 0xd9);  //设置预充电期 Set Pre-Charge Period
    OLED_Write_Byte(CmdReg, 0xf1);  //
    OLED_Write_Byte(CmdReg, 0xda);  //设置com引脚配置 set com pin configuartion
    OLED_Write_Byte(CmdReg, 0x12);  //
    OLED_Write_Byte(CmdReg, 0xdb);  //设置vcomh set Vcomh
    OLED_Write_Byte(CmdReg, 0x30);  //
    OLED_Write_Byte(CmdReg, 0x8d);  //设置电源泵启用 set charge pump enable
    OLED_Write_Byte(CmdReg, 0x14);  //
    OLED_Write_Byte(CmdReg, 0xa4);  //设置全局显示  bit0,1白,0黑
#ifdef OLED_INVERSE_COLOR
    OLED_Write_Byte(CmdReg, 0xa7);  //反相显示
#endif
#ifndef OLED_INVERSE_COLOR
    OLED_Write_Byte(CmdReg, 0xa6);  //正常显示
#endif
    OLED_Fill(0x00);                      //清屏
    OLED_Write_Byte(CmdReg, OLED_ON);  //打开oled面板 turn on oled panel

SSD1306 驱动

由于 SSD1306 在更新时会将同一页中本列的所有数据都进行更新,当需要显示的数据并没有占满整页的高度时,可能会擦除掉本页中其他行的图像。所以,建立一个缓冲区十分的有必要。

我编写了一个带有缓冲区的驱动,具有以下功能:

  • 绘制图象时不受 page 限制,可以于屏幕上的任何坐标绘制。
  • 图像布尔运算功能,实现图像的加减。
  • 数据暂存缓冲区,统一进行通信,实现局部刷新。
  • 计算通信较优方案,使得I2C通信次数较少。

https://gitee.com/snitro/stm32_hal_iic_ssd1306

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值