一、sonata的SDK提供了i2c的硬件抽象层

void OLED_send_cmd(uint8_t oled_cmd)
{

	uint8_t tmp_buf[2]; 
	
	tmp_buf[0] = 0x00;
	tmp_buf[1] = oled_cmd;
	

	sonata_i2c_master_write_data(I2C_TEST, I2C_OLED_SLAVE_ADDR, tmp_buf, 2);
}

 SSD1315 的从地址规则

    • 地址结构
      SSD1315 的从地址由固定前缀011110 + SA0位 + R/W#位组成,其中:

      • SA0由硬件引脚D/C#决定:
        • D/C#接地(SA0=0) → 从地址为0111100(十六进制0x70);
        • D/C#接VDD(SA0=1) → 从地址为0111101(十六进制0x71)。
      • R/W#=0为写操作,R/W#=1为读操作。

   二、OLED页面初始化

PAGE 是按垂直方向(行)顺序排列的

void Page_set(uint8_t page)//page首地址
{
	OLED_send_cmd(0xb0+page);
}

void Column_set(uint8_t column)//
{
	OLED_send_cmd(0x10|(column>>4));    //设置列地址高位
	OLED_send_cmd(0x00|(column&0x0f));  //设置列地址低位		
}

这两个函数用于设置 SSD1315 的 RAM 访问指针起始地址,具体分析如下:

1. Page_set 函数:设置页面起始地址

  • 代码逻辑OLED_send_cmd(0xb0 + page) 中,0xb0 对应命令 Set Page Start Address for Page Addressing Mode(页寻址模式下的页面起始地址设置),page 取值范围为 0~7,对应 PAGE0~PAGE7(十六进制为 0xb0~0xb7)。
  • 文档依据:根据文档段落 ,页寻址模式下需通过 B0h~B7h 命令设置页面起始地址,与该函数功能完全一致。

2. Column_set 函数:设置列起始地址

  • 代码逻辑
    • 高位设置:0x10 | (column >> 4),其中 column >> 4 提取列地址的高 4 位(范围 0~15,对应十六进制 0x0~0xf),与 0x10 按位或后得到 0x10~0x1f,对应命令 Set Higher Column Start Address(列地址高半字节,10h~17h)。
    • 低位设置:0x00 | (column & 0x0f),提取列地址的低 4 位(范围 0~15),对应命令 Set Lower Column Start Address(列地址低半字节,00h~0fh)。
  • 文档依据:根据文档段落 ,页寻址模式下需通过 00h~0fh(低位)和 10h~17h(高位)组合设置列起始地址,该函数通过两次命令调用实现了这一功能。

根据以下的datasheet所实现

3.理解OLED的按位或
 

void Column_set(uint8_t column)//
{
	OLED_send_cmd(0x10|(column>>4));    //设置列地址高位
	OLED_send_cmd(0x00|(column&0x0f));  //设置列地址低位		
}

SSD1315 等 OLED 控制器采用分高低位传输 7 位地址的设计,主要是为了兼容历史协议和硬件接口限制。这种设计通过两次 8 位传输(高 4 位 + 低 3 位)组合成完整的 7 位地址,而非直接使用一个字节。以下从技术原理、设计逻辑和图示说明三个方面展开分析:

技术原理:地址传输的底层逻辑
  1. 7 位地址的实际需求
    SSD1315 的 GDDRAM(图形显示数据 RAM)包含 128 列,因此列地址需要 7 位(0-127)14。例如,列地址0x7F(127)对应第 128 列。

  2. 命令总线的 8 位限制
    控制器的命令总线为 8 位,但地址只需 7 位。若直接用一个字节传输,剩余 1 位可能被闲置或用于其他控制信号(如命令 / 数据标识)。然而,这种设计会导致协议不兼容早期设备,因此采用分两次传输的方案。

  3. 两次传输的组合方式

    • 第一次传输高 4 位:通过命令0x10~0x17设置列地址的高 4 位(D7-D4)。例如,0x13表示高 4 位为0011(十进制 3)。
    • 第二次传输低 3 位:通过命令0x00~0x07设置列地址的低 3 位(D7-D5)。例如,0x05表示低 3 位为101(十进制 5)。
    • 组合结果:高 4 位0011(3)和低 3 位101(5)组合成完整的 7 位地址0011101(十进制 29)613。
设计逻辑:兼容性与协议演进
  1. 历史协议的延续
    早期 OLED 控制器(如 SSD1306)采用类似设计,地址分两次传输以兼容并行接口的时序要求。SSD1315 为保持软件和硬件的兼容性,延续了这一方案1217。

  2. 命令格式的灵活性
    每次传输的 8 位中,除地址位外,还可包含其他控制信息。例如:

    • 高 4 位命令字节(如0x10)可能同时携带操作码(如设置列地址)和地址的高位。
    • 低 3 位命令字节(如0x05)可能包含地址的低位和保留位(如未来扩展用)613。
  3. 硬件接口的适配性
    在并行接口(如 8080/6800 协议)中,数据总线为 8 位,分两次传输地址可简化硬件设计,避免额外的锁存器或移位寄存器1017。

图示说明:两次传输的具体实现

以下为列地址0x1D(十进制 29)的传输示例:

步骤 1:传输高 4 位(0x10 + 高 4 位)
  • 二进制地址0001 1101(十进制 29)
  • 高 4 位0001(十进制 1)
  • 命令字节0x10 + 1 = 0x11(二进制0001 0001
  • 实际传输:通过 I2C 或 SPI 发送0x11,其中高 4 位0001为地址高位,低 4 位0001为保留位。
步骤 2:传输低 3 位(0x00 + 低 3 位)
  • 低 3 位101(十进制 5)
  • 命令字节0x00 + 5 = 0x05(二进制0000 0101
  • 实际传输:发送0x05,其中高 3 位010为地址低位,低 5 位00001为保留位。
组合结果
  • 高 4 位0001和低 3 位101组合为0001 101(十进制 29),即完整的 7 位地址。

4. OLED 显示屏的控制函数,用于实现图像显示、反色显示、全屏点亮和清屏功能

1. Picture_display 函数
void Picture_display(const uint8_t *picture_ptr)
{
    for(uint8_t page=0; page<OLED_PAGE_SIZE; page++)        //page loop
    {
        Page_set(page);
        Column_set(0);

        for(uint8_t column=0;column<128;column++)	//column loop
        {
            OLED_send_data(picture_ptr++, 1);
        }
    }
}
  • 功能:在 OLED 屏幕上显示一幅完整的图像。
  • 工作流程
    • 按页(Page)循环操作,SSD1315 这类 OLED 通常有 8 个 Page,每个 Page 控制 8 行像素。
    • 针对每个 Page,先设置页地址(Page_set),再将列地址重置为 0(Column_set(0))。
    • 逐列传输图像数据,每个字节对应 8 个垂直像素(即同一列的 8 行像素)。
2. Picture_ReverseDisplay 函数
void Picture_ReverseDisplay(const uint8_t *ptr_pic)
{
    for(uint8_t page=0; page<OLED_PAGE_SIZE; page++)        //page loop
    {
        Page_set(page);
        Column_set(0);

        uint8_t data;
        for(uint8_t column=0; column<128; column++)	//column loop
        {
            data=*ptr_pic++;
            data=~data;
            OLED_send_data(&data, 1);
        }
    }
}
  • 功能:以反色方式显示图像(即原本的亮像素变为暗像素,暗像素变为亮像素)。
  • 工作流程
    • Picture_display类似,但在发送数据前会对每个字节进行按位取反操作(data=~data)。
    • 这对于需要突出显示或创建特殊效果的场景非常有用。
3. OLED_full 函数
void OLED_full(void)
{
    for(uint8_t page=0; page<OLED_PAGE_SIZE; page++)             //page loop
    {
        Page_set(page);
        Column_set(0);

        for(uint8_t column=0;column<128;column++)	//column loop
        {
            uint8_t tmp = 0xff;
            OLED_send_data(&tmp, 1);
        }
    }
}
  • 功能:将整个 OLED 屏幕点亮(所有像素显示为亮状态)。
  • 工作流程
    • 遍历所有 Page 和列,向每个位置发送0xff(二进制1111 1111)。
    • 每个1代表对应像素点亮,因此整个屏幕会被完全点亮。
4. OLED_clear 函数
void OLED_clear(void)
{
    for(uint8_t page=0; page<OLED_PAGE_SIZE; page++)             //page loop
    {
        Page_set(page);
        Column_set(0);

        for(uint8_t column=0;column<128;column++)	//column loop
        {
            uint8_t tmp = 0x00;
            OLED_send_data(&tmp, 1);
        }
    }
}
  • 功能:清空 OLED 屏幕(所有像素显示为暗状态)。
  • 工作流程
    • 遍历所有 Page 和列,向每个位置发送0x00(二进制0000 0000)。
    • 每个0代表对应像素熄灭,因此整个屏幕会被清空。
Logo

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

更多推荐