在STM32中使用硬件I2C驱动OLED屏幕,通常涉及以下几个关键步骤:

一、硬件连接

首先,需要将STM32的I2C接口连接到OLED显示屏的SDA和SCL引脚。具体的引脚连接取决于你所使用的STM32型号和OLED模块。一般来说,STM32的I2C接口引脚可以配置为复用功能,用于I2C通信。

二、初始化I2C接口

在STM32的固件中,需要正确配置I2C接口的相关参数,如时钟速率、地址模式等。这通常包括:

  1. 启用I2C外设时钟‌:通过配置RCC(时钟控制寄存器)来启用I2C外设的时钟。
  2. 配置GPIO引脚‌:将用于I2C通信的GPIO引脚配置为复用功能,并设置为开漏输出模式(因为I2C总线需要线与功能)。
  3. 初始化I2C外设‌:设置I2C的通信速率、地址模式等参数。STM32的I2C外设支持标准模式(100Kbit/s)、快速模式(400Kbit/s)和高速模式(3.4Mbit/s)。

三、初始化OLED屏幕

OLED屏幕通常使用SSD1306等驱动芯片,这些芯片支持I2C接口。初始化OLED屏幕包括发送一系列的控制指令到OLED驱动IC,以配置显示屏的显示参数。这些指令通常包括:

  1. 关闭显示屏‌:在初始化过程中,可能需要先关闭显示屏,以避免在配置过程中显示不必要的内容。
  2. 设置对比度‌:调整显示屏的对比度以适应不同的环境光线条件。
  3. 设置显示方向‌:根据应用需求设置显示屏的显示方向(如正常显示、左右反置、上下反置等)。
  4. 启用电荷泵‌:SSD1306等驱动芯片通常内置电荷泵,用于提供显示屏所需的高压。在初始化过程中需要启用电荷泵。

四、编写显示函数

在初始化OLED屏幕后,需要编写显示函数来实现字符、图像等内容的显示。这通常包括:

  1. 定义字符和图像的显示区域‌:根据应用需求定义字符和图像的显示位置和大小。
  2. 发送显示数据‌:将字符或图像的数据通过I2C接口发送到OLED驱动IC中。
  3. 刷新显示屏‌:在发送完显示数据后,需要刷新显示屏以更新显示内容。

五、优化显示效果

为了获得更好的显示效果,可以对显示过程进行优化。例如:

  1. 调整对比度‌:根据实际应用场景调整显示屏的对比度。
  2. 减少闪烁‌:通过调整显示缓冲区的使用来减少显示闪烁。
  3. 实现自定义字形‌:根据应用需求实现自定义的字形以适应显示内容的需求。

六、测试与调试

在完成以上步骤后,需要通过STM32开发板进行实际测试,并通过调试器检查I2C总线上的通信内容,确保数据正确发送和接收。在测试过程中,可以观察显示屏的显示效果,并根据需要进行调整和优化。

OLED屏幕基础介绍

OLED(Organic Light Emitting Diode)‌即有机发光二极管,是一种基于有机半导体材料的显示技术。与传统的LCD(液晶显示器)相比,OLED屏幕具有自发光、高对比度、广视角、快速响应和轻薄可弯曲等显著优势。


OLED屏幕的工作原理

OLED屏幕由多层有机材料组成,当电流通过时,这些有机材料会发光。每个像素点都可以独立控制其开关状态,从而实现高对比度和纯黑色显示(关闭的像素点不发光)。


OLED屏幕的主要特点

  1. 自发光‌:无需背光灯,每个像素点独立发光。
  2. 高对比度‌:能够显示纯黑色,对比度极高。
  3. 广视角‌:视角可达170度以上,侧视画面不失真。
  4. 快速响应‌:响应时间极短,适合显示动态画面。
  5. 轻薄可弯曲‌:可制成柔性屏,应用于可穿戴设备和曲面显示。

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通信,包含必要的初始化配置和底层驱动函数。

一、代码架构

  1. 头文件定义(ssd1306.h)

  • 定义了OLED的基本参数(地址0x78,分辨率128x64)
  • 声明了核心功能函数:初始化、清屏、刷新显示、画点、写字符串
  1. 驱动实现(ssd1306.c)
  • 包含两个关键底层函数:
    • SSD1306_WriteCommand():发送控制命令(0x00前缀)
    • SSD1306_WriteData():发送显示数据(0x40前缀)
  • 显示缓冲区buffer[]:存储128x64/8=1024字节的显存数据
  1. 字库文件(fonts.h)
  • 提供5x7点阵ASCII字库
  • 每个字符用5字节表示,每字节对应一列像素

二、核心函数解析

  1. 初始化流程(SSD1306_Init())

  • 发送27条配置指令(包含显示模式、扫描方向、对比度等)
  • 关键配置:
    • 0xAE/0xAF:显示开关
    • 0x20/0x10:页寻址模式
    • 0xC8:反向COM扫描
    • 0xA1:段重映射
    • 0xD5/0xF0:时钟分频
  1. 显示更新机制(SSD1306_Update())

  • 分8页(每页8行)更新显存
  • 每页发送:页地址(0xB0~0xB7) + 列起始地址(0x00,0x10)
  • 通过I2C批量传输128字节页数据
  1. 绘图原理(SSD1306_DrawPixel())

  • 计算像素位置:x + (y/8)*128
  • 位操作:1<<(y%8)定位具体bit
  • 支持两种颜色:置位(1)或清零(0)

三、硬件接口配置

  1. I2C配置(MX_I2C1_Init())

  • 400kHz速率(标准模式)
  • 7位地址模式
  • 无拉伸模式
  1. 通信协议特点

  • 控制字节:0x00(命令)/0x40(数据)
  • 每次传输添加前缀字节
  • 使用HAL_I2C_Master_Transmit()发送

四、使用示例

  1. 主程序流程

  • 初始化HAL库和硬件外设
  • OLED初始化后显示"Hello World!"
  • 通过SSD1306_Update()刷新显示
  1. 扩展功能

  • 可修改Font5x7数组添加自定义字库
  • 通过组合DrawPixel()实现图形绘制
  • 支持多国语言需扩展字库

五、注意事项

  1. 硬件连接

  • SCL:PB6(I2C1)
  • SDA:PB7(I2C1)
  • 需接上拉电阻(通常4.7kΩ)
  1. 性能优化

  • 可改用DMA传输提升刷新率
  • 局部刷新替代全屏刷新
  • 使用硬件加速的位操作
  1. 常见问题

  • 地址冲突时调整0x78/0x7A
  • 初始化失败检查复位时序
  • 显示异常验证电压电平

该实现完整展示了嵌入式图形显示的典型开发流程,涉及硬件接口、显示协议、字库处理等关键技术点。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐