十天学会嵌入式技术之51单片机—day-9

第 19 章 OLED 模块-I2C 协议

19.1 OLED 模块概述

19.1.1 OLED 简介

OLED(Organic Light-Emitting Diode,有机发光二极管)显示屏由许多微小的发光二

极管构成,每个发光二极管就对应着屏幕上的一个像素,通过控制二极管的亮灭就能在屏

幕上显示图像或文字。

按照驱动方式划分,OLED 显示屏分可分为两类,分别是 PMOLED(Passive Matrix,

被动矩阵)和 AMOLED(Active Matrix,主动矩阵)。

PMOLED 的驱动方式和前文的 LED 点阵类似,每次只能点亮一行或者一列,需要快

速的逐行或者逐列扫描来显示内容。

AMOLED 屏幕上的每个像素点都有一个单独的控制电路,可以独立进行控制。

本课程使用的是一块 PMOLED(Passive Matrix,被动矩阵)屏,其分辨率为 128x64。

19.1.2 驱动芯片

市面上的多数 OLED 显示屏都会带有驱动芯片,驱动芯片的核心作用是控制每个像素

点的亮灭以显示图像或文字,此外它还会提供数据接口(例如 I2C),用于接收屏幕上要显

示的数据。驱动芯片的存在使得我们可以通过简单的接口控制 OLED 显示屏,大大简化了

开发和控制流程。

本课程所使用的这块 OLED 屏的驱动芯片为 SSD1315,由于我们需要通过它来控制

OLED 显示的内容,所以需要重点学习它的用法。

19.1.2.1 基本工作原理
19.1.2.2 IIC 接口

虽然 SSD1315 的 MCU Interface 支持多种通信协议,但我们所选用的 OLED 显示模块

只暴露出了 IIC 接口。

由于 OLED 显示屏的作用是显示数据,它对于 MCU 来讲更多的是一个输出设备,因

此我们只需关注如何向 SSD1315 写入数据即可。下面是写数据的时序图:

19.1.2.3 GDDRAM

GDDRAM 的作用是存储显示数据,其容量是 128×64 bit,每个 bit 对应着屏幕上的一

个像素,该 bit 的值就能决定该像素的亮灭。

(1)内存组织结构

(2)内存寻址

在了解了内存组织结构之后,我们还需掌握内存的寻址方式,这样才能在我们指定的

位置写入指定的内容。

向 GDDRAM 写入数据时是以 byte 为单位的,按照上述的内存组织结构, 定位一个

byte,至少需要明确两点,分别是第几页(Page Address,页地址)和第几列(ColumnAddress,列地址)。因此 GDDRAM 内部设有两个指针, Page Address Pointer 和 ColumnAddress Pointer,分别指向当前要写入的页和列。为方便连续写入多个字节,每当成功写

入一个字节后,Page Address Pointer 或者 Column Address Pointer 会自动递增,指向下一

个要写入的位置。

根据指针递增逻辑的不同,GDFRAM 提供了三种不同的寻址方式,分别是页寻址,水

平寻址和垂直寻址,具体使用哪种模式,可以通过向 SSD1315 发送控制命令进行选择,具

体命令如下

下面逐一介绍三种寻址方式的工作原理。

(1)页寻址

这种寻址方式下,用户需要先向 SSD1315 发送控制命令设置页地址(例如 Page1)和

列地址(例如 COL3),此时 Page Address Pointer 和 Column Address Pointer 就会指向对

应的位置。之后便可开始连续发送数据,每成功写入一个字节,Column Address Pointer

都会自动+1,而 Page Address Pointer 始终不变,如果写到当前页末尾,Column Address

Pointer 会回到当前页的第 1 列。

设置页地址的命令如下

设置列地址的命令如下。

(2)水平寻址

这种寻址方式下,用户需要先向 SSD1315 发送控制命令,设置一个写入区域,具体来

讲就是分别指定页的起始地址和结束地址(例如 Page1~Page5)以及列的起始地址和结束

地址(例如 COL2~COL125)。此时 Page Address Pointer 和 Column Address Pointer 会指

向该区域的左上角。之后便可开始连续发送数据,每成功写入一个字节,Column Address

Pointer 会自动+1,当到达目标区域的右侧边界时,Page Address Pointer 便会自动+1。当写

到目标区域的右下角时,两个指针会再次回到左上角。如下图所示。

设置页地址范围的命令如下。

设置列地址范围的命令如下。

(3)垂直寻址

这种寻址方式下,用户需要先向 SSD1315 发送控制命令,设置一个写入区域,具体来

讲就是分别指定页的起始地址和结束地址(例如 Page1~Page5)以及列的起始地址和结束

地址(例如 COL2~COL125)。此时 Page Address Pointer 和 Column Address Pointer 会指

向该区域的左上角。之后便可开始连续发送数据,每成功写入一个字节,Page Address

Pointer 会自动+1,当到达目标区域的底部边界时,Column Address Pointer 便会自动+1。当

写到目标区域的右下角时,两个指针会再次回到左上角。如下图所示。

3)内存 bit 与屏幕像素映射关系

GDDRAM 中的每个 bit 都对应着屏幕上的一个像素,但具体哪个 bit 对应着哪个像素,

目前仍是不明确的,最理想的方式当然是每个 bit 和每个像素的位置完全对应,但默认情况

下并非如此。

bit 和像素之间的对应关系受两个环节的影响,第一个环节是 GDDRAM 和 SSD1315 输

出引脚(64 个 COM 和 128 个 SEG)的对应关系,第二个环节是 SSD1315 的输出引脚和

OLED 屏幕的连线方式。下面逐一分析。

(1)GDDRAM 和 SSD1315 输出引脚对应关系

(2)SSD1315 输出引脚和 OLED 屏幕对应关系

根据前文的描述,若要保证 GDDRAM 中的 bit 与 OLED 屏幕中的像素位置完全对应,

那么 GDDRAM 和 SSD1315 输出引脚的对应关系,需要进行重映射。

设置 Segment 重映射的命令如下。

设置 Common 重映射的命令如下。

19.1.3 相关资料

(1)实物图

19.2 需求描述

在 OLED 屏指定位置显示 ASCII 表中的指定字符.

19.3 硬件设计

19.4 软件设计

19.4.1 需求分析

想要在指定位置显示 ASCII 表中的指定字符,首先需要为每个字符制作字模。至于显

示位置的控制,只需通过命令指定自模数据写入 GDDRAM 的位置即可实现。

19.4.2 字模制作

19.4.3 显示位置

19.4.4 完整代码

(1)Int_Oled.h

cs 复制代码
#ifndef __INT_OLED_H__
#define __INT_OLED_H__
#include "Util.h"
/**
* @brief Oled 初始化
*
*/
void Int_Oled_Init();
/**
* @brief 在指定位置(x,y)显示字符串
*
* @param x 横坐标
* @param y 纵坐标
* @param str 待展示字符串
*/
void Int_Oled_ShowStr(u8 x, u8 y, u8 *str);
/**
* @brief 在指定位置(x,y)显示数字
*
* @param x 横坐标
* @param y 纵坐标
* @param num 待展示数字
*/
void Int_Oled_ShowNum(u8 x, u8 y, long int num);
/**
* @brief 清屏
*
*/
void Int_Oled_Clear();
#endif /* __INT_OLED_H__ */

(2)Int_Oled.c

cs 复制代码
#include "Int_Oled.h"
#include "Dri_IIC.h"
#define OLED_ADDR 0x78
#define DATA_MODE 0x40
#define CMD_MODE 0x00
code const u8 Int_Oled_Font[][16] =
{
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0
    0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x33, 0x30, 0x00, 0x00, 0x00, //! 1
    0x00, 0x10, 0x0C, 0x06, 0x10, 0x0C, 0x06, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //" 2
    0x40, 0xC0, 0x78, 0x40, 0xC0, 0x78, 0x40, 0x00,
    0x04, 0x3F, 0x04, 0x04, 0x3F, 0x04, 0x04, 0x00, // # 3
    0x00, 0x70, 0x88, 0xFC, 0x08, 0x30, 0x00, 0x00,
    0x00, 0x18, 0x20, 0xFF, 0x21, 0x1E, 0x00, 0x00, //$ 4
    0xF0, 0x08, 0xF0, 0x00, 0xE0, 0x18, 0x00, 0x00,
    0x00, 0x21, 0x1C, 0x03, 0x1E, 0x21, 0x1E, 0x00, //% 5
    0x00, 0xF0, 0x08, 0x88, 0x70, 0x00, 0x00, 0x00,
    0x1E, 0x21, 0x23, 0x24, 0x19, 0x27, 0x21, 0x10, //& 6
    0x10, 0x16, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //' 7
    0x00, 0x00, 0x00, 0xE0, 0x18, 0x04, 0x02, 0x00,
    0x00, 0x00, 0x00, 0x07, 0x18, 0x20, 0x40, 0x00, //( 8
    0x00, 0x02, 0x04, 0x18, 0xE0, 0x00, 0x00, 0x00,
    0x00, 0x40, 0x20, 0x18, 0x07, 0x00, 0x00, 0x00, //) 9
    0x40, 0x40, 0x80, 0xF0, 0x80, 0x40, 0x40, 0x00,
    0x02, 0x02, 0x01, 0x0F, 0x01, 0x02, 0x02, 0x00, //* 10
    0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00,
    0x01, 0x01, 0x01, 0x1F, 0x01, 0x01, 0x01, 0x00, //+ 11
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x80, 0xB0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, //, 12
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//- 13
    0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, //- 13
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, //. 14
    0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x18, 0x04,
    0x00, 0x60, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, /// 15
    0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00,
    0x00, 0x0F, 0x10, 0x20, 0x20, 0x10, 0x0F, 0x00, // 0 16
    0x00, 0x10, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // 1 17
    0x00, 0x70, 0x08, 0x08, 0x08, 0x88, 0x70, 0x00,
    0x00, 0x30, 0x28, 0x24, 0x22, 0x21, 0x30, 0x00, // 2 18
    0x00, 0x30, 0x08, 0x88, 0x88, 0x48, 0x30, 0x00,
    0x00, 0x18, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // 3 19
    0x00, 0x00, 0xC0, 0x20, 0x10, 0xF8, 0x00, 0x00,
    0x00, 0x07, 0x04, 0x24, 0x24, 0x3F, 0x24, 0x00, // 4 20
    0x00, 0xF8, 0x08, 0x88, 0x88, 0x08, 0x08, 0x00,
    0x00, 0x19, 0x21, 0x20, 0x20, 0x11, 0x0E, 0x00, // 5 21
    0x00, 0xE0, 0x10, 0x88, 0x88, 0x18, 0x00, 0x00,
    0x00, 0x0F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // 6 22
    0x00, 0x38, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00,
    0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, // 7 23
    0x00, 0x70, 0x88, 0x08, 0x08, 0x88, 0x70, 0x00,
    0x00, 0x1C, 0x22, 0x21, 0x21, 0x22, 0x1C, 0x00, // 8 24
    0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00,
    0x00, 0x00, 0x31, 0x22, 0x22, 0x11, 0x0F, 0x00, // 9 25
    0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, //: 26
    0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, //; 27
    0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00,
    0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, //< 28
    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00,
    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, //= 29
    0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00,
    0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, //> 30
    0x00, 0x70, 0x48, 0x08, 0x08, 0x08, 0xF0, 0x00,
    0x00, 0x00, 0x00, 0x30, 0x36, 0x01, 0x00, 0x00, //? 31
    0xC0, 0x30, 0xC8, 0x28, 0xE8, 0x10, 0xE0, 0x00,
    0x07, 0x18, 0x27, 0x24, 0x23, 0x14, 0x0B, 0x00, //@ 32
    0x00, 0x00, 0xC0, 0x38, 0xE0, 0x00, 0x00, 0x00,
    0x20, 0x3C, 0x23, 0x02, 0x02, 0x27, 0x38, 0x20, // A 33
    0x08, 0xF8, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00,
    0x20, 0x3F, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // B 34
    0xC0, 0x30, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00,
    0x07, 0x18, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, // C 35
    0x08, 0xF8, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
    0x20, 0x3F, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // D 36
    0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00,
    0x20, 0x3F, 0x20, 0x20, 0x23, 0x20, 0x18, 0x00, // E 37
    0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00,
    0x20, 0x3F, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, // F 38
    0xC0, 0x30, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00,
    0x07, 0x18, 0x20, 0x20, 0x22, 0x1E, 0x02, 0x00, // G 39
    0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08,
    0x20, 0x3F, 0x21, 0x01, 0x01, 0x21, 0x3F, 0x20, // H 40
    0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0x00,
    0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // I 41
    0x00, 0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00,
    0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, 0x00, // J 42
    0x08, 0xF8, 0x88, 0xC0, 0x28, 0x18, 0x08, 0x00,
    0x20, 0x3F, 0x20, 0x01, 0x26, 0x38, 0x20, 0x00, // K 43
    0x08, 0xF8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x20, 0x3F, 0x20, 0x20, 0x20, 0x20, 0x30, 0x00, // L 44
    0x08, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x08, 0x00,
    0x20, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x20, 0x00, // M 45
    0x08, 0xF8, 0x30, 0xC0, 0x00, 0x08, 0xF8, 0x08,
    0x20, 0x3F, 0x20, 0x00, 0x07, 0x18, 0x3F, 0x00, // N 46
    0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
    0x0F, 0x10, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // O 47
    0x08, 0xF8, 0x08, 0x08, 0x08, 0x08, 0xF0, 0x00,
    0x20, 0x3F, 0x21, 0x01, 0x01, 0x01, 0x00, 0x00, // P 48
    0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00,
    0x0F, 0x18, 0x24, 0x24, 0x38, 0x50, 0x4F, 0x00, // Q 49
    0x08, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00,
    0x20, 0x3F, 0x20, 0x00, 0x03, 0x0C, 0x30, 0x20, // R 50
    0x00, 0x70, 0x88, 0x08, 0x08, 0x08, 0x38, 0x00,
    0x00, 0x38, 0x20, 0x21, 0x21, 0x22, 0x1C, 0x00, // S 51
    0x18, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x18, 0x00,
    0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // T 52
    0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08,
    0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // U 53
    0x08, 0x78, 0x88, 0x00, 0x00, 0xC8, 0x38, 0x08,
    0x00, 0x00, 0x07, 0x38, 0x0E, 0x01, 0x00, 0x00, // V 54
    0xF8, 0x08, 0x00, 0xF8, 0x00, 0x08, 0xF8, 0x00,
    0x03, 0x3C, 0x07, 0x00, 0x07, 0x3C, 0x03, 0x00, // W 55
    0x08, 0x18, 0x68, 0x80, 0x80, 0x68, 0x18, 0x08,
    0x20, 0x30, 0x2C, 0x03, 0x03, 0x2C, 0x30, 0x20, // X 56
    0x08, 0x38, 0xC8, 0x00, 0xC8, 0x38, 0x08, 0x00,
    0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // Y 57
    0x10, 0x08, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00,
    0x20, 0x38, 0x26, 0x21, 0x20, 0x20, 0x18, 0x00, // Z 58
    0x00, 0x00, 0x00, 0xFE, 0x02, 0x02, 0x02, 0x00,
    0x00, 0x00, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x00, //[ 59
    0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x06, 0x38, 0xC0, 0x00, //\ 60
    0x00, 0x02, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00,
    0x00, 0x40, 0x40, 0x40, 0x7F, 0x00, 0x00, 0x00, //] 61
    0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x04, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //^ 62
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, //_ 63
    0x00, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //` 64
    0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
    0x00, 0x19, 0x24, 0x22, 0x22, 0x22, 0x3F, 0x20, // a 65
    0x08, 0xF8, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00,
    0x00, 0x3F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // b 66
    0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
    0x00, 0x0E, 0x11, 0x20, 0x20, 0x20, 0x11, 0x00, // c 67
    0x00, 0x00, 0x00, 0x80, 0x80, 0x88, 0xF8, 0x00,
    0x00, 0x0E, 0x11, 0x20, 0x20, 0x10, 0x3F, 0x20, // d 68
    0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
    0x00, 0x1F, 0x22, 0x22, 0x22, 0x22, 0x13, 0x00, // e 69
    0x00, 0x80, 0x80, 0xF0, 0x88, 0x88, 0x88, 0x18,
    0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // f 70
    0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
    0x00, 0x6B, 0x94, 0x94, 0x94, 0x93, 0x60, 0x00, // g 71
    0x08, 0xF8, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,   
    0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // h 72
    0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // i 73
    0x00, 0x00, 0x00, 0x80, 0x98, 0x98, 0x00, 0x00,
    0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, // j 74
    0x08, 0xF8, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00,
    0x20, 0x3F, 0x24, 0x02, 0x2D, 0x30, 0x20, 0x00, // k 75
    0x00, 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // l 76
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
    0x20, 0x3F, 0x20, 0x00, 0x3F, 0x20, 0x00, 0x3F, // m 77
    0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
    0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // n 78
    0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
    0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // o 79
    0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00,
    0x80, 0xFF, 0xA1, 0x20, 0x20, 0x11, 0x0E, 0x00, // p 80
    0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00,
    0x00, 0x0E, 0x11, 0x20, 0x20, 0xA0, 0xFF, 0x80, // q 81
    0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00,
    0x20, 0x20, 0x3F, 0x21, 0x20, 0x00, 0x01, 0x00, // r 82
    0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
    0x00, 0x33, 0x24, 0x24, 0x24, 0x24, 0x19, 0x00, // s 83
    0x00, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x00, 0x00, // t 84
    0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00,
    0x00, 0x1F, 0x20, 0x20, 0x20, 0x10, 0x3F, 0x20, // u 85
    0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80,
    0x00, 0x01, 0x0E, 0x30, 0x08, 0x06, 0x01, 0x00, // v 86
    0x80, 0x80, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80,
    0x0F, 0x30, 0x0C, 0x03, 0x0C, 0x30, 0x0F, 0x00, // w 87
    0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00,
    0x00, 0x20, 0x31, 0x2E, 0x0E, 0x31, 0x20, 0x00, // x 88
    0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80,
    0x80, 0x81, 0x8E, 0x70, 0x18, 0x06, 0x01, 0x00, // y 89
    0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
    0x00, 0x21, 0x30, 0x2C, 0x22, 0x21, 0x30, 0x00, // z 90
    0x00, 0x00, 0x00, 0x00, 0x80, 0x7C, 0x02, 0x02,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x40, //{ 91
    0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, //| 92
    0x00, 0x02, 0x02, 0x7C, 0x80, 0x00, 0x00, 0x00,
    0x00, 0x40, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, //} 93
    0x00, 0x06, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //~ 94
};
/**
* @brief 写显示数据
*
* @param bytes 字节数组
* @param length 数组长度
*/
void Int_Oled_WriteData(u8 bytes[], u8 length)
{
    u8 i;
    // 发送起始信号
    Dri_IIC_Start();

    // 发送设备地址
    Dri_IIC_SendByte(OLED_ADDR);
    Dri_IIC_ReceiveAck();

    // 发送控制字节
    Dri_IIC_SendByte(DATA_MODE);
    Dri_IIC_ReceiveAck();

    // 发送数据
    for (i = 0; i < length; i++) {
        Dri_IIC_SendByte(bytes[i]);
        Dri_IIC_ReceiveAck();
    }
    Dri_IIC_Stop();
}
/**
* @brief 写控制命令
*
* @param bytes 字节数组
* @param length 数组长度
*/
void Int_Oled_WriteCmd(u8 bytes[], u8 length)
{
    u8 i;
    // 发送起始信号
    Dri_IIC_Start();
    // 发送设备地址
    Dri_IIC_SendByte(OLED_ADDR);
    Dri_IIC_ReceiveAck();
    // 发送控制字节
    Dri_IIC_SendByte(CMD_MODE);
    Dri_IIC_ReceiveAck();
    // 发送数据
    for (i = 0; i < length; i++) {
        Dri_IIC_SendByte(bytes[i]);
        Dri_IIC_ReceiveAck();
    }
    Dri_IIC_Stop();
}
void Int_Oled_Init()
{
    u8 bytes[6];
    // 关闭屏幕
    bytes[0] = 0xAE;
    // Segment 重映射
    bytes[1] = 0xA1;
    // Common 重映射
    bytes[2] = 0xC8;
    // 启动内置电荷泵(用于升压)
    bytes[3] = 0x8D;
    bytes[4] = 0x14;
    // 开启屏幕
    bytes[5] = 0xAF;
    Int_Oled_WriteCmd(bytes, 6);
}

/**
* @brief 设置页地址和列地址
*
* @param page 页地址
* @param column 列地址
*/
void Int_Oled_SetPointer(u8 page, u8 column)
{
    u8 bytes[3];
    bytes[0] = 0xB0 | (page & 0x07);
    bytes[1] = 0x00 | (column & 0x0F);
    bytes[2] = 0x10 | ((column >> 4) & 0x07);
    Int_Oled_WriteCmd(bytes, 3);
}

void Int_Oled_Clear()
{
    u8 i;
    u8 j;
    for (i = 0; i < 8; i++) {
        Int_Oled_SetPointer(i, 0);
        for (j = 0; j < 8; j++) {
            Int_Oled_WriteData(Int_Oled_Font[0], 16);
        }
    }
}

void Int_Oled_ShowStr(u8 x, u8 y, u8 *str)
{
    u8 i;
    // 上半部分
    // 设置页地址和列地址
    Int_Oled_SetPointer(2 * y, 8 * x);
    // 发送数据
    for (i = 0; i < 16 - x && str[i]; i++) {
        Int_Oled_WriteData(Int_Oled_Font[str[i] - 32], 8);
    }
    // 下半部分
    // 设置页地址和列地址
    Int_Oled_SetPointer(2 * y + 1, 8 * x);
    // 发送数据
    for (i = 0; i < 16 - x && str[i]; i++) {
        Int_Oled_WriteData(Int_Oled_Font[str[i] - 32] + 8, 8);
    }
}

void Int_Oled_ShowNum(u8 x, u8 y, long int num)
{
    u8 str[17];
    u8 i = 0;
    u8 j = 0;
    u8 tmp;
    if (num == 0) {
        str[0] = '0';
    } else {
        if (num < 0) {
            str[i++] = '-';
            num = -num;
            j = 1;
        }
        // 转换字符串
        while (num) {
            str[i++] = num % 10 + '0';
            num = num / 10;
        }
        // 字符串终止
        str[i] = 0;
        i--;
        // 反转整个数字
        while (i > j) {
            tmp = str[i];
            str[i] = str[j];
            str[j] = tmp;
            i--;
            j++;
        }
    }    
    Int_Oled_ShowStr(x, y, str);
}

(3)main.c

cs 复制代码
#include "Int_Oled.h"
void main()
{
    Int_Oled_Init();
    Int_Oled_Clear();
    Int_Oled_ShowStr(0, 0, "Hello world!");
    Int_Oled_ShowNum(0, 1, 123456);
    while (1) {
    }
}
相关推荐
O。o.尊都假都1 分钟前
socket套接字的超时控制
单片机·嵌入式硬件·网络协议
欢乐熊嵌入式编程1 小时前
智能手表项目的《项目背景与目标说明书》样本文档
嵌入式硬件·目标跟踪·规格说明书·智能手表
海尔辛2 小时前
学习黑客BitLocker与TPM详解
stm32·单片机·学习
上海合宙LuatOS3 小时前
全栈工程师实战手册:LuatOS日志系统开发指南!
java·开发语言·单片机·嵌入式硬件·物联网·php·硬件工程
公子无缘3 小时前
【嵌入式】记一次解决VScode+PlatformIO安装卡死的经历
vscode·stm32·单片机·mcu·platformio
欢乐熊嵌入式编程4 小时前
智能手表蓝牙 GATT 通讯协议文档
嵌入式硬件·目标跟踪·规格说明书·智能手表
whaosoft-1434 小时前
51c嵌入式~电路~合集27
嵌入式硬件
Camellia03115 小时前
嵌入式学习--江协51单片机day5
嵌入式硬件·学习·51单片机
7yewh5 小时前
FPGA前瞻篇-计数器设计与实现实例
arm开发·驱动开发·嵌入式硬件·fpga开发·硬件架构·硬件工程·精益工程