STM32 HAL库驱动0.96寸OLED屏幕

发布于:2025-08-14 ⋅ 阅读:(18) ⋅ 点赞:(0)

STM32 HAL库驱动0.96寸OLED屏幕

项目概述

本项目使用STM32 HAL库为0.96寸OLED屏幕编写驱动程序。OLED屏幕通过I2C接口与STM32单片机通信,实现文本、数字和图形的显示功能。

项目仓库地址:STM32_Sensor_Drives

硬件连接

在这里插入图片描述

OLED屏幕通过I2C接口与STM32连接:

  • SCL连接到PB8
  • SDA连接到PB9

关键代码

1. I2C初始化

void MX_I2C1_Init(void)
{
    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 100000;
    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();
    }
}

2. I2C引脚配置

void HAL_I2C_MspInit(I2C_HandleTypeDef *i2cHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if (i2cHandle->Instance == I2C1)
    {
        __HAL_RCC_GPIOB_CLK_ENABLE();
        /**I2C1 GPIO Configuration
        PB8     ------> I2C1_SCL
        PB9     ------> I2C1_SDA
        */
        GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        __HAL_AFIO_REMAP_I2C1_ENABLE();

        /* I2C1 clock enable */
        __HAL_RCC_I2C1_CLK_ENABLE();
    }
}

3. OLED基本通信函数

// 向OLED发送命令
void Write_IIC_Command(uint8_t cmd)
{
    HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT, &cmd, 1, 100);
}

// 向OLED发送数据
void Write_IIC_Data(uint8_t data)
{
    HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT, &data, 1, 100);
}

4. OLED显示控制函数

// 设置显示坐标
void OLED_Set_Pos(unsigned char x, unsigned char y)
{
    Write_IIC_Command(0xb0 + y);
    Write_IIC_Command(((x & 0xf0) >> 4) | 0x10);
    Write_IIC_Command((x & 0x0f));
}

// 开启OLED显示
void OLED_Display_On(void)
{
    Write_IIC_Command(0X8D); // SET DCDC命令
    Write_IIC_Command(0X14); // DCDC ON
    Write_IIC_Command(0XAF); // DISPLAY ON
}

// 关闭OLED显示
void OLED_Display_Off(void)
{
    Write_IIC_Command(0X8D); // SET DCDC命令
    Write_IIC_Command(0X10); // DCDC OFF
    Write_IIC_Command(0XAE); // DISPLAY OFF
}

// 清屏函数
void OLED_Clear(void)
{
    uint8_t i, n;
    for (i = 0; i < 8; i++)
    {
        Write_IIC_Command(0xb0 + i); // 设置页地址(0~7)
        Write_IIC_Command(0x00);     // 设置显示位置—列低地址
        Write_IIC_Command(0x10);     // 设置显示位置—列高地址
        for (n = 0; n < 128; n++)
            Write_IIC_Data(0);
    }
}

// 全屏点亮
void OLED_On(void)
{
    uint8_t i, n;
    for (i = 0; i < 8; i++)
    {
        Write_IIC_Command(0xb0 + i); // 设置页地址(0~7)
        Write_IIC_Command(0x00);     // 设置显示位置—列低地址
        Write_IIC_Command(0x10);     // 设置显示位置—列高地址
        for (n = 0; n < 128; n++)
            Write_IIC_Data(1);
    }
}

5. 字符显示函数

// 在指定位置显示一个字符
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 = y + 2;
    }
    if (Char_Size == 16)
    {
        OLED_Set_Pos(x, y);
        for (i = 0; i < 8; i++)
            Write_IIC_Data(F8X16[c * 16 + i]);
        OLED_Set_Pos(x, y + 1);
        for (i = 0; i < 8; i++)
            Write_IIC_Data(F8X16[c * 16 + i + 8]);
    }
    else
    {
        OLED_Set_Pos(x, y);
        for (i = 0; i < 6; i++)
            Write_IIC_Data(F6x8[c][i]);
    }
}

// 显示字符串
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;
        j++;
    }
}

// 显示数字
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size2)
{
    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);
    }
}

// m^n函数
uint32_t oled_pow(uint8_t m, uint8_t n)
{
    uint32_t result = 1;
    while (n--)
        result *= m;
    return result;
}

6. 中文显示和图片显示

// 显示中文
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++)
    {
        Write_IIC_Data(Hzk[no][t]);
        adder += 1;
    }
    OLED_Set_Pos(x, y + 1);
    for (t = 0; t < 16; t++)
    {
        Write_IIC_Data(Hzk[no][t + 16]);
        adder += 1;
    }
}

// 显示BMP图片
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++)
        {
            Write_IIC_Data(BMP[j++]);
        }
    }
}

7. OLED初始化函数

void OLED_start(void)
{
    Write_IIC_Command(0xAE); // 关闭显示
    Write_IIC_Command(0xD5); // 设置时钟分频因子,震荡频率
    Write_IIC_Command(0x80); // [3:0],分频因子;[7:4],震荡频率
    Write_IIC_Command(0xA8); // 设置驱动路数
    Write_IIC_Command(0x3F); // 默认0X3F(1/64)
    Write_IIC_Command(0xD3); // 设置显示偏移
    Write_IIC_Command(0x00); // 默认为0

    Write_IIC_Command(0x40); // 设置显示开始行 [5:0],行数.

    Write_IIC_Command(0x8D); // 电荷泵设置
    Write_IIC_Command(0x14); // bit2,开启/关闭
    Write_IIC_Command(0x20); // 设置内存地址模式
    Write_IIC_Command(0x02); // [1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
    Write_IIC_Command(0xA1); // 段重定义设置,bit0:0,0->0;1,0->127;
    Write_IIC_Command(0xC8); // 设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
    Write_IIC_Command(0xDA); // 设置COM硬件引脚配置
    Write_IIC_Command(0x12); // [5:4]配置

    Write_IIC_Command(0x81); // 对比度设置
    Write_IIC_Command(0xEF); // 1~255;默认0X7F (亮度设置,越大越亮)
    Write_IIC_Command(0xD9); // 设置预充电周期
    Write_IIC_Command(0xf1); // [3:0],PHASE 1;[7:4],PHASE 2;
    Write_IIC_Command(0xDB); // 设置VCOMH 电压倍率
    Write_IIC_Command(0x30); // [6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;

    Write_IIC_Command(0xA4); // 全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
    Write_IIC_Command(0xA6); // 设置显示方式;bit0:1,反相显示;0,正常显示
    Write_IIC_Command(0xAF); // 开启显示
    OLED_Clear();
}

8. 主函数中的使用示例

int main(void)
{
    /* 省略初始化代码 */
    
    /* 初始化外设 */
    MX_GPIO_Init();
    MX_USART2_UART_Init();
    MX_I2C1_Init();
    
    /* 初始化OLED */
    OLED_start();
    
    /* 无限循环 */
    printf("System will start while\n");
    OLED_Clear();
    OLED_ShowString(0, 0, (uint8_t*)"Init success", 16);
    OLED_ShowString(0, 2, (uint8_t*)"Init success", 12);
    while (1)
    {
        HAL_Delay(200);
    }
}

字体数据

项目中包含了两种字体数据:

  1. 6x8点阵字体(F6x8):适用于小字体显示
  2. 8x16点阵字体(F8X16):适用于大字体显示
  3. 中文字库(Hzk):用于显示中文字符

注意事项

  1. OLED的I2C地址为0x78(写操作)
  2. 显示区域为128x64像素
  3. 使用前需要先调用OLED_start()初始化OLED
  4. 清屏函数OLED_Clear()可以清除屏幕上的所有内容

常用函数总结

函数名 功能描述
OLED_start() 初始化OLED
OLED_Clear() 清屏
OLED_Display_On() 开启显示
OLED_Display_Off() 关闭显示
OLED_ShowChar() 显示单个字符
OLED_ShowString() 显示字符串
OLED_ShowNum() 显示数字
OLED_ShowCHinese() 显示中文
OLED_DrawBMP() 显示BMP图片

参考资料

  • STM32 HAL库文档
  • 0.96寸OLED屏幕数据手册
  • 项目仓库