OLED简介
OLED(Organic Light-Emitting Diode,有机发光二极管)显示屏由许多微小的发光二极管构成,每个发光二极管就对应着屏幕上的一个像素,通过控制二极管的亮灭就能在屏幕上显示图像或文字。
按照驱动方式划分,OLED显示屏分可分为两类,分别是PMOLED(Passive Matrix,被动矩阵)和AMOLED(Active Matrix,主动矩阵)。
- PMOLED
PMOLED的驱动方式和前文的LED点阵类似,每次只能点亮一行或者一列,需要快速的逐行或者逐列扫描来显示内容。
- AMOLED
AMOLED屏幕上的每个像素点都有一个单独的控制电路,可以独立进行控制。
本次介绍的是一块PMOLED(Passive Matrix,被动矩阵)屏,其分辨率为128x64。
驱动芯片
市面上的多数OLED显示屏都会带有驱动芯片,驱动芯片的核心作用是控制每个像素点的亮灭以显示图像或文字,此外它还会提供数据接口(例如I2C),用于接收屏幕上要显示的数据。驱动芯片的存在使得我们可以通过简单的接口控制OLED显示屏,大大简化了开发和控制流程。
本次介绍的这块OLED屏的驱动芯片为SSD1315
基本工作原理
- MCU InterFace
通信接口,MCU通过该接口向SSD1315发送显示数据或者控制命令(控制屏幕显示效果,例如对比度、亮度等)。该接口支持多种通信协议,其中就包括IC。 - Command Decoder
命令解码器,负责解析和执行主机发送的控制命令 - Graphic Display Data RAM
图形显示数据RAM,用于存储显示数据,其容量为128x64(bit)。每个bit对应屏幕上的1个像素。 - Common/Segment Driver
用于产生实际驱动OLED显示屏的信号。其中Common Driver用于产生行扫描信号共有64个输出引脚。Segment Driver用于产生每行要显示的内容信号,共有128个输出引脚。
IIC接口、写时序
SSD1315的MCU Interface支持多种通信协议,这里OLED显示模块只暴露出了IIC接口
OLED显示屏的作用是显示数据,是一个输出设备,我们只需关注如何向SSD1315写入数据即可。下面是写数据的时序图
- SA0
SSD1315的地址,高6位是固定的011110,最后1位SA0可由用户自定义。参考0LED模块手册,可得最后1位的默认值为0 - R/W#
R/W#(读写标识)应为0,故地址+读写标识应为01111000(0x78) - Data byte
数据字节,其内容可能是Data(显示数据),也可能是Command(控制命令)。 - Control byte
控制字节,在Data byte之前发送,用于声明后续Data byte内容的类型和格式,该字节只有高2位有效,其余6位均为0 - D/C#(Data/Command)
用于声明后续的Data byte是Data还是Command,1表示Data,0表示Command。 - Co(Continuation Bit)
用于声明后续内容是否连续,0表示连续,此时后边可以连续发送多个Data bvte:1表示不连续,此时后边只能发送一个Data byte。需要注意的是,当Co设置0时,本次通信中后续所有的字节都会被视作Databyte
内存组织结构
内存寻址
定位一个byte,至少需要明确两点,分别是第几页(Page Address,页地址)和第几列(Column Address,列地址)。
GDDRAM内部设有两个指针
- Page Address Pointer,指向当前要写入的页
- Column Address Pointer,指向当前要写入的列
为方便连续写入多个字节,每当成功写入一个字节后,Page Address Pointer或者Column Address Pointer会自动递增,指向下一个要写入的位置。
设置寻址方式的命令
页寻址
这种寻址方式下,用户需要先向SSD1315发送控制命令设置页地址(例如Page1)和列地址(例如COL3),此时Page Address Pointer和Column Address Pointer就会指向对应的位置。之后便可开始连续发送数据,每成功写入一个字节,Column Address Pointer都会自动+1,而Page Address Pointer始终不变,如果写到当前页末尾,Column Address Pointer会回到当前页的第1列。
设置页地址的命令如下。
设置列地址的命令如下。
水平寻址
这种寻址方式下,用户需要先向SSD1315发送控制命令,设置一个写入区域,具体来讲就是分别指定页的起始地址和结束地址(例如Page1Page5)以及列的起始地址和结束地址(例如COL2COL125)。此时Page Address Pointer和Column Address Pointer会指向该区域的左上角。之后便可开始连续发送数据,每成功写入一个字节,Column Address Pointer会自动+1,当到达目标区域的右侧边界时,Page Address Pointer便会自动+1。当写到目标区域的右下角时,两个指针会再次回到左上角。
设置页地址范围的命令如下。
设置列地址范围的命令如下。
垂直寻址
这种寻址方式下,用户需要先向SSD1315发送控制命令,设置一个写入区域,具体来讲就是分别指定页的起始地址和结束地址(例如Page1Page5)以及列的起始地址和结束地址(例如COL2COL125)。此时Page Address Pointer和Column Address Pointer会指向该区域的左上角。之后便可开始连续发送数据,每成功写入一个字节,Page Address Pointer会自动+1,当到达目标区域的底部边界时,Column Address Pointer便会自动+1。当写到目标区域的右下角时,两个指针会再次回到左上角。
内存bit与屏幕像素映射关系
GDDRAM中的每个bit都对应着屏幕上的一个像素,但具体哪个bit对应着哪个像素,目前仍是不明确的,最理想的方式当然是每个bit和每个像素的位置完全对应,但默认情况下并非如此。
bit和像素之间的对应关系受两个环节的影响,第一个环节是GDDRAM和SSD1315输出引脚(64个COM和128个SEG)的对应关系,第二个环节是SSD1315的输出引脚和OLED屏幕的连线方式。下面逐一分析。
GDDRAM和SSD1315输出引脚对应关系
SSD1315输出引脚和OLED屏幕对应关系
根据前文的描述,若要保证GDDRAM中的bit与OLED屏幕中的像素位置完全对应,那么GDDRAM和SSD1315输出引脚的对应关系,需要进行重映射。
设置Segment重映射的命令如下。
设置Common重映射的命令如下。
代码实现
Int_Oled.h
#ifndef __INT_OLED_H__
#define __INT_OLED_H__
#include "Com_Util.h"
/**
* @brief Oled初始化
*
*/
void Int_Oled_Init();
void Int_Oled_WriteData(u8 bytes[], u8 length);
void Int_Oled_WriteCmd(u8 bytes[], u8 length);
/**
* @brief 清屏
*
*/
void Int_Oled_Clear();
/**
* @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);
#endif /* __INT_OLED_H__ */
Int_Oled.c
#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,
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);
}
void Int_Oled_Clear() {
u8 cmd_bytes[2]={0x20,0x00};
u8 data_bytes[8] = {0};
u8 i;
Int_Oled_WriteCmd(cmd_bytes, 2);
for ( i = 0; i < 128; i++)
{
Int_Oled_WriteData(data_bytes, 8);
}
}
/**
* @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_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);
}
mian.c
#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) {
}
}
补充
清屏优化
void Dri_IIC_SendByte(u8 byte)
{
u8 i;
for (i = 0; i < 8; i++) {
SDA = (byte & (0x80 >> i)) == 0 ? 0 : 1;
SCL = 1;
SCL = 0;
}
}
这是I2C中一段代码,现在对其进行优化
void Dri_IIC_SendByte(u8 byte)
{
u8 i;
for (i = 0; i < 8; i++) {
//SDA = (byte & (0x80 >> i)) == 0 ? 0 : 1;
if ((byte & 0x80) == 0x00) {
SDA = 0;
} else {
SDA = 1;
}
byte <<= 1;
SCL = 1;
SCL = 0;
}
}
void Int_Oled_Clear() {
u8 cmd_bytes[2]={0x20,0x00};
u8 data_bytes[8] = {0};
u8 i;
Int_Oled_WriteCmd(cmd_bytes, 2);
for ( i = 0; i < 128; i++)
{
Int_Oled_WriteData(data_bytes, 8);
}
}
优化清屏逻辑
原来的逻辑:通过128次循环,每次循环进行1次通信,1次通信写8个字节
现在的逻辑:只进行1次通信,循环写入128*8字节
void Int_Oled_Clear() {
u8 cmd_bytes[2]={0x20,0x00};
u8 data_bytes[8] = {0};
u16 i;
Int_Oled_WriteCmd(cmd_bytes, 2);
// for ( i = 0; i < 128; i++)
// {
// Int_Oled_WriteData(data_bytes, 8);
// }
// 发送起始信号
Dri_IIC_Start();
// 发送设备地址
Dri_IIC_SendByte(OLED_ADDR);
Dri_IIC_ReceiveAck();
// 发送控制字节
Dri_IIC_SendByte(DATA_MODE);
Dri_IIC_ReceiveAck();
// 发送数据
for (i = 0; i < 128 * 8; i++) {
Dri_IIC_SendByte(0x00);
Dri_IIC_ReceiveAck();
}
Dri_IIC_Stop();
}
数字展示
使用库函数,将数字转成字符串
#include <STDIO.H>
void Int_Oled_ShowNum(u8 x, u8 y, long int num)
{
char str[12];
sprintf(str, "%ld", num);
Int_Oled_ShowStr(x, y, str);
}
标签:0x08,u8,0x20,0x00,Oled,OLED,0x80,屏幕
From: https://blog.csdn.net/m0_58749949/article/details/144899440