RA4M2开发IOT(8)----IIC驱动OLED

发布于:2025-06-24 ⋅ 阅读:(13) ⋅ 点赞:(0)

概述

本章旨在通过 I²C 接口驱动 OLED 显示屏(常见型号如 SSD1306),实现图形和文本的显示功能。OLED 屏幕具有低功耗、自发光、对比度高等优点,适用于嵌入式人机界面显示。

最近在瑞萨RA的课程,需要样片的可以加qun申请:925643491。

在这里插入图片描述

视频教学

https://www.bilibili.com/video/BV15EMbzGEy7

RA4M2开发IOT(8)----IIC驱动OLED

样品申请

https://www.wjx.top/vm/rCrkUrz.aspx

硬件准备

首先需要准备一个开发板,这里我准备的是自己绘制的开发板,需要的可以进行申请。
主控为R7FA4M2AD3CFL#AA0

在这里插入图片描述
同时添加RA4M2_IOT扩展版。

在这里插入图片描述

参考程序

https://github.com/CoreMaker-lab/RA4M2_IOT

https://gitee.com/CoreMaker/RA4M2_IOT

修改IIC驱动

若同一个 I²C 总线上挂载多个不同地址的设备,只需在每次通信前调用 R_SCI_I2C_SlaveAddressSet() 设置目标设备地址,即可灵活访问多个设备,无需初始化多个 I²C 控制器实例。
由于LSM6DSV16X的地址是0x6B,所以在读写上添加如下函数。

    R_SCI_I2C_SlaveAddressSet(&g_i2c2_ctrl, 0x6B, I2C_MASTER_ADDR_MODE_7BIT);
    assert(FSP_SUCCESS == err);

在这里插入图片描述

OLED属性配置

查看手册,可以得知OLED的IIC地址为“b0111100” or “b0111101”,即0x3c或者0x3d。

在这里插入图片描述

在OLED的模块中,丝印上面写的地址是0x78(b0111 1000)或者0x7a(b0111 1010),是因为加了一位RW位,因为一般只要发送数据让屏幕进行显示。

在这里插入图片描述
这里接入的IIC和LSM6DSV16X是一个总线。

在这里插入图片描述

移植SSD1306

将用于驱动 OLED 显示屏的相关文件(oled.c, oled.h, oledfont.h, bmp.h)拷贝到当前 e2studio 项目 的 src 目录中。

在这里插入图片描述

OLED 驱动代码目前使用的是 基于 GPIO 模拟 I²C(Bit-Banging)方式 驱动 OLED。查看 oled.h 具体表现如下 。

在这里插入图片描述

删除 GPIO 宏定义与模拟 I²C 函数 。

在这里插入图片描述
通过 typedef 为无符号整型类型定义了简写别名,其中 u8 表示 8 位无符号整型(等同于 uint8_t),u32 表示 32 位无符号整型(等同于 uint32_t)。

typedef __uint8_t u8 ;
typedef __uint16_t u16 ;
typedef __uint32_t u32 ;

在这里插入图片描述
删除sys.h引用。
在这里插入图片描述

在 oled.c中删除模拟IIC的函数。

在这里插入图片描述

删除后如下所示。

在这里插入图片描述

在 oled.c最下面关闭IIC初始化。

在这里插入图片描述

删除delay.h引用。

在这里插入图片描述

添加E2STUDIO的部分头文件和定义。

#include "hal_data.h"
extern fsp_err_t err;
extern int  timeout_ms;
extern  i2c_master_event_t i2c_event ;

在这里插入图片描述

在 oled.c 中新增适用于 RA 平台的 I²C 写入函数, Send_Byte函数修改后如下所示。

//写入一个字节
void Send_Byte(u8 dat)
{
//    u8 i;
//    for(i=0;i<8;i++)
//    {
//        if(dat&0x80)//将dat的8位从最高位依次写入
//        {
//            OLED_SDA_Set();
//    }
//        else
//        {
//            OLED_SDA_Clr();
//    }
//        IIC_delay();
//        OLED_SCL_Set();
//        IIC_delay();
//        OLED_SCL_Clr();//将时钟信号设置为低电平
//        dat<<=1;
//  }
    R_SCI_I2C_SlaveAddressSet(&g_i2c2_ctrl, 0x3C, I2C_MASTER_ADDR_MODE_7BIT);
    assert(FSP_SUCCESS == err);

    err = R_SCI_I2C_Write(&g_i2c2_ctrl, &dat, 1, true);
     assert(FSP_SUCCESS == err);
    /* Since there is nothing else to do, block until Callback triggers*/
    //while ((I2C_MASTER_EVENT_TX_COMPLETE != i2c_event) && timeout_ms)
    while ((I2C_MASTER_EVENT_TX_COMPLETE != i2c_event) && timeout_ms>0)
    {
        R_BSP_SoftwareDelay(100U, BSP_DELAY_UNITS_MICROSECONDS);
        timeout_ms--;
    }
    if (I2C_MASTER_EVENT_ABORTED == i2c_event)
    {
        __BKPT(0);
    }
    /* Read data back from the I2C slave */
    i2c_event = I2C_MASTER_EVENT_ABORTED;
    timeout_ms           = 100000;

}

在这里插入图片描述

OLED_WR_Byte函数写入了地址0x78,然后是0x40或者0x00的数据/命令标志,最后是dat数据。

在这里插入图片描述

//发送一个字节
//mode:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 mode)
{
//    I2C_Start();
//    Send_Byte(0x78);
//    I2C_WaitAck();
//    if(mode){Send_Byte(0x40);}
//  else{Send_Byte(0x00);}
//    I2C_WaitAck();
//    Send_Byte(dat);
//    I2C_WaitAck();
//    I2C_Stop();

    R_SCI_I2C_SlaveAddressSet(&g_i2c2_ctrl, 0x3C, I2C_MASTER_ADDR_MODE_7BIT);
    assert(FSP_SUCCESS == err);
    uint8_t ii[2]={0x00,0x00};
    if(mode)
        ii[0] = 0x40;
      else
        ii[0] = 0x00;
    ii[1] = dat;

    err = R_SCI_I2C_Write(&g_i2c2_ctrl, ii, 0x02, true);
    assert(FSP_SUCCESS == err);
    /* Since there is nothing else to do, block until Callback triggers*/
    //while ((I2C_MASTER_EVENT_TX_COMPLETE != i2c_event) && timeout_ms)
    while ((I2C_MASTER_EVENT_TX_COMPLETE != i2c_event) && timeout_ms>0)
    {
     R_BSP_SoftwareDelay(100U, BSP_DELAY_UNITS_MICROSECONDS);
     timeout_ms--;
    }
    if (I2C_MASTER_EVENT_ABORTED == i2c_event)
    {
        __BKPT(0);
    }
    /* Read data back from the I2C slave */
    i2c_event = I2C_MASTER_EVENT_ABORTED;
    timeout_ms           = 100000;
}

在这里插入图片描述

OLED_Refresh() 中的模拟 I²C 方式批量写入 OLED 显存内容。

在这里插入图片描述

修改如下。

//更新显存到OLED
void OLED_Refresh(void)
{
//    u8 i,n;
//    for(i=0;i<8;i++)
//    {
//        OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
//        OLED_WR_Byte(0x00,OLED_CMD);   //设置低列起始地址
//        OLED_WR_Byte(0x10,OLED_CMD);   //设置高列起始地址
//        I2C_Start();
//        Send_Byte(0x78);
//        I2C_WaitAck();
//        Send_Byte(0x40);
//        I2C_WaitAck();
//        for(n=0;n<128;n++)
//        {
//            Send_Byte(OLED_GRAM[n][i]);
//            I2C_WaitAck();
//        }
//        I2C_Stop();
//  }
    uint8_t i, n;
    fsp_err_t err;
    uint8_t buf[129]; // 控制字节 + 128 字节数据
    buf[0] = 0x40;     // 控制字节(0x40 表示后续为数据)
    for(i = 0; i < 8; i++)
    {
        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++)
        {
            buf[n + 1] = OLED_GRAM[n][i]; // 填充数据部分
        }

        // 设置 OLED I2C 地址(建议只设置一次,若已设置可略过)
        R_SCI_I2C_SlaveAddressSet(&g_i2c2_ctrl, 0x3C, I2C_MASTER_ADDR_MODE_7BIT);

        // 发送整帧显示数据(129字节)
        err = R_SCI_I2C_Write(&g_i2c2_ctrl, buf, sizeof(buf), true);
        assert(FSP_SUCCESS == err);

        // 等待写入完成
        while ((I2C_MASTER_EVENT_TX_COMPLETE != i2c_event) && timeout_ms > 0)
        {
            R_BSP_SoftwareDelay(100U, BSP_DELAY_UNITS_MICROSECONDS);
            timeout_ms--;
        }

        if (I2C_MASTER_EVENT_ABORTED == i2c_event)
        {
            __BKPT(); // 出错断点
        }

        i2c_event = I2C_MASTER_EVENT_ABORTED;
        timeout_ms = 100000;
    }   
}

在这里插入图片描述
在hal_entry.c中添加对应头文件。

#include "oled.h"
#include "bmp.h"

添加OLED_Start() 函数 ,初始化OLED。

// OLED 屏幕启动函数:完成初始化、清屏、颜色/方向配置
static void OLED_Start(void)
{
    OLED_Init();              // 初始化 OLED 屏幕(发送初始化命令序列,设置工作模式)
    OLED_Clear();             // 清空显存(OLED_GRAM),并刷新,使屏幕全黑
    OLED_ColorTurn(0);        // 设置显示颜色模式:0 为正常显示,1 为反色显示(黑白反转)
    OLED_DisplayTurn(0);      // 设置显示方向:0 为正常方向,1 为上下翻转显示
}

在这里插入图片描述
在主程序中添加。

    // 初始化 OLED,保证屏幕点亮且处于默认显示状态
    OLED_Start();

在这里插入图片描述

字符取模

由于单片机的flash比较吃紧,所以要显示汉字需要先进行取模。首先需要设置为字符模式。

在这里插入图片描述

取模软件设置。

在这里插入图片描述

设置完之后就可以取自己想要汉字的编码,输入完毕点击生成字模即可。

在这里插入图片描述

在oledfont.h中放入字库。

const unsigned char Hzk1[][32]={
{0x84,0x84,0xFC,0x84,0x84,0x40,0x5E,0x50,0x50,0x50,0xDF,0x50,0x50,0x50,0x5E,0x00,0x10,0x30,0x1F,0x08,0x08,0x00,0xFE,0x02,0x02,0x7F,0x02,0x7E,0x02,0x82,0xFE,0x00},/*"瑞",0*/
{0x04,0xE4,0x24,0x24,0xA4,0x6F,0x04,0x24,0x64,0xAF,0x34,0xA4,0x64,0x24,0x04,0x00,0x00,0xFF,0x00,0x11,0x22,0x9C,0x40,0x3F,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00},/*"萨",1*/
{0x00,0x00,0xF8,0x49,0x4A,0x4C,0x48,0xF8,0x48,0x4C,0x4A,0x49,0xF8,0x00,0x00,0x00,0x10,0x10,0x13,0x12,0x12,0x12,0x12,0xFF,0x12,0x12,0x12,0x12,0x13,0x10,0x10,0x00},/*"单",2*/
{0x00,0x00,0x00,0xFE,0x20,0x20,0x20,0x20,0x20,0x3F,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x80,0x60,0x1F,0x02,0x02,0x02,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x00},/*"片",3*/
{0x10,0x10,0xD0,0xFF,0x90,0x10,0x00,0xFE,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x04,0x03,0x00,0xFF,0x00,0x83,0x60,0x1F,0x00,0x00,0x00,0x3F,0x40,0x40,0x78,0x00},/*"机",4*/


};

在这里插入图片描述
OLED_ShowChinese() 函数,用于在 OLED 上显示汉字。代码逻辑已经实现了对不同大小字模的选择,主要依赖 Hzk1[]、Hzk2[]、Hzk3[]、Hzk4[] 这几个数组来获取字模数据。

在这里插入图片描述

在OLED_Start添加汉字显示驱动。

// OLED 屏幕启动函数:完成初始化、清屏、颜色/方向配置
static void OLED_Start(void)
{
    OLED_Init();              // 初始化 OLED 屏幕(发送初始化命令序列,设置工作模式)
    OLED_Clear();             // 清空显存(OLED_GRAM),并刷新,使屏幕全黑
    OLED_ColorTurn(0);        // 设置显示颜色模式:0 为正常显示,1 为反色显示(黑白反转)
    OLED_DisplayTurn(0);      // 设置显示方向:0 为正常方向,1 为上下翻转显示
    OLED_Clear();//清空 OLED 显存
    OLED_ShowChinese(0,0,0,16,1);//在坐标 (0,0) 显示 Hzk1[0],即汉字“瑞”,正显
    OLED_ShowChinese(16,0,1,16,1);//在坐标 (16,0) 显示 Hzk1[1],即汉字“萨”,正显
    OLED_ShowChinese(32,0,2,16,0);//在坐标 (32,0) 显示 Hzk1[2],即汉字“单”,反色
    OLED_ShowChinese(48,0,3,16,0);//在坐标 (48,0) 显示 Hzk1[3],即汉字“片”,反色
    OLED_ShowChinese(64,0,4,16,0);//在坐标 (64,0) 显示 Hzk1[4],即汉字“机”,反色
    OLED_Refresh();//将上述通过 OLED_ShowChinese() 写入 OLED_GRAM[][] 的内容,批量发送到 OLED 屏幕显示。如果没有调用这个函数,屏幕上不会出现任何内容(即写入显存但未更新)。
}

在这里插入图片描述
在这里插入图片描述

ASCII显示

OLED_ShowNum 和 OLED_ShowString 的主要作用就是 在 OLED 上显示 ASCII 字符组成的数字或字符串,使用的是内置的 ASCII 字体库(如 oledfont.h 中定义的 6×8 或 8×16 等点阵字体)。它们都调用了 OLED_ShowChar 这个底层函数来逐个字符地显示。

在OLED_Start添加显示ASCII。

    OLED_ShowNum(0, 16, 20250615, 8, 16, 1);//在坐标 (0,16) 显示20250615,长度8,字体16,正显
    OLED_ShowString(84, 16, "RA4M2", 16, 1);//在坐标 (84,16) 显示RA4M2,字体16,正显
    OLED_Refresh();// 将 OLED_GRAM 显存内容刷新到 OLED 屏幕上,显示数字和字符串

在这里插入图片描述

在这里插入图片描述

图片取模

设置为图形模式。

在这里插入图片描述

格式设置。

在这里插入图片描述

选择需要打开的文件。

在这里插入图片描述

打开的文件必须为bmp文件。

在这里插入图片描述

选择生成字模。

在这里插入图片描述

图片数据放在bmp.h中。

unsigned char BMP3[] =
{

 0x1E,0x0E,0x07,0x07,0x07,0x07,0x03,0x03,0x83,0x83,0xC7,0xC7,0xFF,0xFF,0xFF,0xFF,
 0xFF,0x7E,0x3C,0xE0,0xF0,0xF8,0xF8,0xF8,0xF8,0xBC,0xBC,0xBC,0xBC,0xBC,0xBC,0xBC,
 0xBC,0xBC,0x1C,0xFC,0xFC,0xFC,0xFC,0xF8,0xF8,0xF8,0xF8,0xE0,0xC0,0x80,0x00,0x00,
 0xFC,0xFC,0xFC,0xFC,0x00,0xE0,0xF0,0xF8,0xF8,0xF8,0xF8,0xBC,0xBC,0xBC,0xBC,0xBC,
 0xBC,0xBC,0xBC,0x9C,0xE0,0xF0,0xF8,0xF8,0xF8,0xF8,0xFC,0xFC,0xFC,0xBC,0xBC,0xBC,
 0x3C,0x3C,0x3C,0x3C,0x1C,0x00,0x00,0x80,0xC0,0xF0,0xF0,0xF8,0xF8,0xFC,0xFC,0xFC,
 0xF8,0xF8,0xC0,0x80,0x00,0xF0,0xF0,0xF8,0xF8,0xF8,0xF8,0xFC,0xFC,0xBC,0xBC,0xBC,
 0xBC,0x3C,0x3C,0x3C,0x1C,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x03,0x07,0x0F,
 0x1F,0x3F,0x7F,0xFF,0xFD,0xF8,0xF0,0xE0,0xFF,0xBF,0x7F,0xFF,0xFF,0xFF,0xF7,0xE7,
 0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE3,0xE0,0xFF,0xFF,0xFF,0xFF,0xFF,0x03,0x07,0x0F,
 0x3F,0x3F,0x7F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0x00,0x3F,0x7F,0xFF,0xFF,0xFF,0xFF,
 0xF7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE3,0xE3,0xE0,0xE0,0xE1,0xE3,0xE3,0xE7,0xE7,
 0xEF,0xEF,0xEF,0xFF,0xFF,0xFF,0xFF,0xFE,0x7E,0xFC,0xFC,0xFE,0xFF,0xFF,0x7F,0x1F,
 0xEF,0xE1,0xE1,0xE3,0xEF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFD,0xF1,0xE3,0xE3,0xE7,0xE7,
 0xE7,0xEF,0xEF,0xEF,0xFF,0xFF,0xFF,0xFF,0xFE,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x03,0x03,0x07,0x07,
 0x07,0x06,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"RA4M2_IOT\OLED\renesas-logo.bmp",0*/
 
};

在这里插入图片描述

显示图片

查看属性可以知道分别率为19*117。

在这里插入图片描述

在 OLED 屏幕下半部分显示一张 117×19 的图片,并刷新屏幕显示。

    OLED_ShowPicture(0, 32, 117, 19, BMP3, 1);                // 在 OLED 屏幕的 (x=0, y=32) 位置显示一张宽 117、高 19 像素的图片 BMP3,正常模式显示
    OLED_Refresh();                                           // 将图片内容从缓冲区刷新到 OLED 屏幕上,真正显示出来
    R_BSP_SoftwareDelay(200, BSP_DELAY_UNITS_MILLISECONDS);  // 延时 200 毫秒

在这里插入图片描述
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到