0.96英寸OLED显示屏(I2C接口)

在当前的嵌入式市场上,有一种0.96英寸的OLED显示屏非常流行,这里就来讨论一下如何通过LPC824驱动它。目前该OLED屏流行两种接口,一种是SPI接口,另一种是I2C接口。这里仅讨论I2C接口的,其外形如下图所示。

3919b94e3a4340028e4cc86566ebb9bf

该屏为128X64的点阵屏,横向有128个像数点,纵向有64个像数点。目前市场上有白色、蓝色和黄蓝双色等显示颜色可选。

该OLED屏所使用的驱动芯片型号为SSD1306,其显示原理如下所示。

图片1

首先通过通信接口(比如I2C)接收来自单片机的一个字节数据, 然后通过判断数据的D/C#位来确定是命令还是数据。命令用于控制显示的地址等等,数据则存入GDDRAM中去屏幕上显示。显示屏上横向的X坐标是以像数作为单位的,从左到右分别是0~127。但纵向则不同,纵向的Y坐标是以页(Page)为单位的,从上到下分别是0~7。其中,每页用8位二进制数来表征该页中某一列上显示的像数,从下往上排列,即高位在下低位在上。值为1时点亮该像数,为0时熄灭。通常在显示ASCII码时,每个字符需要用6列8行来显示,即需要连续接收6字节显示数据才能显示一个ASCII码字符(如上图中的字符A,就使用了6个字节进行显示)。

下面来看I2C接口的通信时序,如下图所示。

无标题

需要注意的是,其I2C传输数据的格式有两种。一种是控制字节与数据字节交替传输,另一种是先发一个控制字节,后面跟着连续的数据字节。这两种模式的选择由控制字节中的Co位来确定,其值为1时表示交替传输,为0时表示连续传输。通常情况下会选择连续传输方式(即Co值为0)。同时,D/C#位紧跟在Co位后面发,值为0时表示后面收到的字节是控制命令,为1时是数据。命令字节只包含Co位和D/C#位,其余位全部为0(见上图中的Contol byte)。此外,该显示模块的器件地址为011110+SA0,其中的SA0为外部引脚,通过接高电平或地的方式进行选择(即在I2C总线上最多可挂两块屏)。其他的就跟传统I2C传输格式一样了。

接下来根据前面的要求封装出两个函数。一个是写命令函数,如下。

void oled_writeCmd(uint8_t cmd)
{    
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x0)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTDAT = 0x78;                  //要写入的器件地址(写方向)
    LPC_I2C0->MSTCTL = 1<<1;                  //启动传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x4)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTDAT = 0x00;                  //将要写入的是命令
    LPC_I2C0->MSTCTL = 1<<0;                  //启动重新传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x4)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTDAT = cmd;                   //要写入的命令(1字节)
    LPC_I2C0->MSTCTL = 1<<0;                  //启动重新传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x4)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTCTL = 1<<2;                  //停止传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x0)abort(); //若返回的状态不为空闲则终止
}

一个是写数据函数,如下。

void oled_writeData(uint8_t data)
{    
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x0)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTDAT = 0x78;                  //要写入的器件地址(写方向)
    LPC_I2C0->MSTCTL = 1<<1;                  //启动传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x4)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTDAT = 0x40;                  //将要写入的是数据
    LPC_I2C0->MSTCTL = 1<<0;                  //启动重新传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x4)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTDAT = data;                  //要写入的数据(1字节)
    LPC_I2C0->MSTCTL = 1<<0;                  //启动重新传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x4)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTCTL = 1<<2;                  //停止传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x0)abort(); //若返回的状态不为空闲则终止
}

下面是官方手册给出的显示屏初始化过程(内部自举方式),只需要按步骤进行相应的控制命令写入就可以了。

无标题1

结合上面的初始化过程,下面给出其对应的初始化函数。

void oled_init(void)
{
    delay_ms(100);                  //Delay 100ms(Recommended)
    oled_writeCmd(0xAE);            //Set Display Off
    oled_writeCmd(0xD5);
    oled_writeCmd(0x80);            //Set Display Clock Divide Ratio/Oscillator Frequency
    oled_writeCmd(0xA8);
    oled_writeCmd(0x3F);            //Set Multiplex Ratio
    oled_writeCmd(0xD3);
    oled_writeCmd(0x00);            //Set Display Offset
    oled_writeCmd(0x40);            //Set Display Start Line                   
    oled_writeCmd(0xA1);            //Set Segment Re-Map
    oled_writeCmd(0xC8);            //Set COM Output Scan Direction
    oled_writeCmd(0xDA);
    oled_writeCmd(0x12);            //Set COM Pins Hardware Configuration
    oled_writeCmd(0x81);
    oled_writeCmd(0xCF);            //Set Contrast Control
    oled_writeCmd(0xD9);
    oled_writeCmd(0xF1);            //Set Pre-Charge Period
    oled_writeCmd(0xDB);
    oled_writeCmd(0x30);            //Set VCOMH Deselect Level
    oled_writeCmd(0xA4);            //Set Entire Display On/Off
    oled_writeCmd(0xA6);            //Set Normal/Inverse Display
    oled_writeCmd(0x8D);
    oled_writeCmd(0x14);            //Set Charge Pump
    oled_writeCmd(0xAF);            //Set Display On
    delay_ms(100);                  //Delay 100ms(Recommended)
}

完成初始化后,就可以对显示屏发送显示坐标和显示数据了。在设置显示位置时,需要分横坐标和页坐标来进行,其中横坐标需要分高低四位进行两次写入。下表是官方手册中给出的显示坐标设置要求。

4

结合上述要求,下面给出一个设置显示位置的函数。

void oled_setLocation(uint8_t x, uint8_t page)
{
    oled_writeCmd(0x00 | (x & 0x0F));               //写入x坐标的低四位值
    oled_writeCmd(0x10 | ((x & 0xF0) >> 4));        //写入x坐标的高四位值
    oled_writeCmd(0xB0 | page);                     //写入页坐标的值
}

下面来看一个实际的例子,通过LPC824驱动OLED模拟显示一个手机屏幕,其中有图像、数字、英文字符和中文字符。完整代码如下。

#include <LPC82x.h>
#include <stdlib.h>
#define nor        6
#define lar        8
//****************ASCII码(宽6像素,高8像素)*************************
const uint8_t oled_6x8[][6] =
{
    0x00,0x00,0x00,0x00,0x00,0x00,//   0
    0x00,0x00,0x00,0x2F,0x00,0x00,// ! 1
    0x00,0x00,0x07,0x00,0x07,0x00,// " 2
    0x00,0x14,0x7F,0x14,0x7F,0x14,// # 3
    0x00,0x24,0x2A,0x7F,0x2A,0x12,// $ 4
    0x00,0x23,0x13,0x08,0x64,0x62,// % 5
    0x00,0x36,0x49,0x55,0x22,0x50,// & 6
    0x00,0x00,0x00,0x07,0x00,0x00,// ' 7
    0x00,0x00,0x1C,0x22,0x41,0x00,// ( 8
    0x00,0x00,0x41,0x22,0x1C,0x00,// ) 9
    0x00,0x14,0x08,0x3E,0x08,0x14,// * 10
    0x00,0x08,0x08,0x3E,0x08,0x08,// + 11
    0x00,0x00,0x00,0xA0,0x60,0x00,// , 12
    0x00,0x08,0x08,0x08,0x08,0x08,// - 13
    0x00,0x00,0x60,0x60,0x00,0x00,// . 14
    0x00,0x20,0x10,0x08,0x04,0x02,// / 15
    0x00,0x3E,0x51,0x49,0x45,0x3E,// 0 16
    0x00,0x00,0x42,0x7F,0x40,0x00,// 1 17
    0x00,0x42,0x61,0x51,0x49,0x46,// 2 18
    0x00,0x21,0x41,0x45,0x4B,0x31,// 3 19
    0x00,0x18,0x14,0x12,0x7F,0x10,// 4 20
    0x00,0x27,0x45,0x45,0x45,0x39,// 5 21
    0x00,0x3C,0x4A,0x49,0x49,0x30,// 6 22
    0x00,0x01,0x71,0x09,0x05,0x03,// 7 23
    0x00,0x36,0x49,0x49,0x49,0x36,// 8 24
    0x00,0x06,0x49,0x49,0x29,0x1E,// 9 25
    0x00,0x00,0x36,0x36,0x00,0x00,// : 26
    0x00,0x00,0x56,0x36,0x00,0x00,// ; 27
    0x00,0x08,0x14,0x22,0x41,0x00,// < 28
    0x00,0x14,0x14,0x14,0x14,0x14,// = 29
    0x00,0x00,0x41,0x22,0x14,0x08,// > 30
    0x00,0x02,0x01,0x51,0x09,0x06,// ? 31
    0x00,0x3E,0x49,0x55,0x59,0x2E,// @ 32
    0x00,0x7C,0x12,0x11,0x12,0x7C,// A 33
    0x00,0x7F,0x49,0x49,0x49,0x36,// B 34
    0x00,0x3E,0x41,0x41,0x41,0x22,// C 35
    0x00,0x7F,0x41,0x41,0x22,0x1C,// D 36
    0x00,0x7F,0x49,0x49,0x49,0x41,// E 37
    0x00,0x7F,0x09,0x09,0x09,0x01,// F 38
    0x00,0x3E,0x41,0x49,0x49,0x7A,// G 39
    0x00,0x7F,0x08,0x08,0x08,0x7F,// H 40
    0x00,0x00,0x41,0x7F,0x41,0x00,// I 41
    0x00,0x20,0x40,0x41,0x3F,0x01,// J 42
    0x00,0x7F,0x08,0x14,0x22,0x41,// K 43
    0x00,0x7F,0x40,0x40,0x40,0x40,// L 44
    0x00,0x7F,0x02,0x0C,0x02,0x7F,// M 45
    0x00,0x7F,0x04,0x08,0x10,0x7F,// N 46
    0x00,0x3E,0x41,0x41,0x41,0x3E,// O 47
    0x00,0x7F,0x09,0x09,0x09,0x06,// P 48
    0x00,0x3E,0x41,0x51,0x21,0x5E,// Q 49
    0x00,0x7F,0x09,0x19,0x29,0x46,// R 50
    0x00,0x46,0x49,0x49,0x49,0x31,// S 51
    0x00,0x01,0x01,0x7F,0x01,0x01,// T 52
    0x00,0x3F,0x40,0x40,0x40,0x3F,// U 53
    0x00,0x1F,0x20,0x40,0x20,0x1F,// V 54
    0x00,0x3F,0x40,0x38,0x40,0x3F,// W 55
    0x00,0x63,0x14,0x08,0x14,0x63,// X 56
    0x00,0x07,0x08,0x70,0x08,0x07,// Y 57
    0x00,0x61,0x51,0x49,0x45,0x43,// Z 58
    0x00,0x00,0x7F,0x41,0x41,0x00,// [ 59
    0x00,0x02,0x04,0x08,0x10,0x20,// \ 60
    0x00,0x00,0x41,0x41,0x7F,0x00,// ] 61
    0x00,0x04,0x02,0x01,0x02,0x04,// ^ 62
    0x00,0x40,0x40,0x40,0x40,0x40,// _ 63
    0x00,0x00,0x01,0x02,0x04,0x00,// ` 64
    0x00,0x20,0x54,0x54,0x54,0x78,// a 65
    0x00,0x7F,0x48,0x44,0x44,0x38,// b 66
    0x00,0x38,0x44,0x44,0x44,0x20,// c 67
    0x00,0x38,0x44,0x44,0x48,0x7F,// d 68
    0x00,0x38,0x54,0x54,0x54,0x18,// e 69
    0x00,0x08,0x7E,0x09,0x01,0x02,// f 70
    0x00,0x18,0xA4,0xA4,0xA4,0x7C,// g 71
    0x00,0x7F,0x08,0x04,0x04,0x78,// h 72
    0x00,0x00,0x44,0x7D,0x40,0x00,// i 73
    0x00,0x40,0x80,0x84,0x7D,0x00,// j 74
    0x00,0x7F,0x10,0x28,0x44,0x00,// k 75
    0x00,0x00,0x41,0x7F,0x40,0x00,// l 76
    0x00,0x7C,0x04,0x18,0x04,0x78,// m 77
    0x00,0x7C,0x08,0x04,0x04,0x78,// n 78
    0x00,0x38,0x44,0x44,0x44,0x38,// o 79
    0x00,0xFC,0x24,0x24,0x24,0x18,// p 80
    0x00,0x18,0x24,0x24,0x18,0xFC,// q 81
    0x00,0x7C,0x08,0x04,0x04,0x08,// r 82
    0x00,0x48,0x54,0x54,0x54,0x20,// s 83
    0x00,0x04,0x3F,0x44,0x40,0x20,// t 84
    0x00,0x3C,0x40,0x40,0x20,0x7C,// u 85
    0x00,0x1C,0x20,0x40,0x20,0x1C,// v 86
    0x00,0x3C,0x40,0x30,0x40,0x3C,// w 87
    0x00,0x44,0x28,0x10,0x28,0x44,// x 88
    0x00,0x1C,0xA0,0xA0,0xA0,0x7C,// y 89
    0x00,0x44,0x64,0x54,0x4C,0x44,// z 90
    0x00,0x00,0x08,0x7F,0x41,0x00,// { 91
    0x00,0x00,0x00,0x7F,0x00,0x00,// | 92
    0x00,0x00,0x41,0x7F,0x08,0x00,// } 93
    0x00,0x08,0x04,0x08,0x10,0x08,// ~ 94
};
//****************ASCII码(宽8像素,高16像素)*************************
const uint8_t oled_8x16[][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,0x16,0x0E,0x00,0x16,0x0E,0x00,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
    0x00,0x00,0x00,0x16,0x0E,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,
    0x00,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,0xC0,0xC0,0x00,0x00,0x00,
    0x00,0x00,0x80,0xB0,0x70,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,0x20,0x10,0x08,0x04,0x08,0x10,0x20,
    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,0x04,0x08,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
    0x00,0x80,0x80,0x00,0x80,0x80,0x00,0x00,
    0x00,0x20,0x3F,0x21,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,0x80,0x40,0x40,0x80,0x00,0x00,0x80,
    0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,// ~ 94
};
//****************天线信号(宽6像素,高8像素)*************************
const uint8_t ANT_6x8[] =
{
    0x00,0xC0,0xE0,0x00,0xE0,0xF0,0x00,0xF0,0xF8,0x00,0xF8,0xFC,0x00,0xFC,0xFE,0x00,0xFF,0xFF,
};
//****************电池图标(宽6像素,高8像素)*************************
const uint8_t BAT_6x8[] =
{
    0x00,0x00,0x3C,0x3C,0xFF,0x81,0x81,0xBD,0xBD,0xBD,0x81,0xBD, \
    0xBD,0xBD,0x81,0xBD,0xBD,0xBD,0x81,0xBD,0xBD,0xBD,0x81,0xFF,
};
//****************四个汉字(宽16像素,高16像素)*************************
const uint8_t chr[][32] =
{
    0x00,0x00,0xF0,0x10,0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x10,0xF0,0x00,0x00,0x00,
    0x00,0x00,0x0F,0x04,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0x0F,0x00,0x00,0x00,/*"中",0*/
    0x00,0xFE,0x02,0x12,0x92,0x92,0x92,0xF2,0x92,0x92,0x92,0x12,0x02,0xFE,0x00,0x00,
    0x00,0xFF,0x40,0x48,0x48,0x48,0x48,0x4F,0x48,0x4A,0x4C,0x48,0x40,0xFF,0x00,0x00,/*"国",1*/    
    0x00,0x00,0xF8,0x88,0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x88,0xF8,0x00,0x00,0x00,
    0x00,0x00,0x1F,0x08,0x08,0x08,0x08,0x7F,0x88,0x88,0x88,0x88,0x9F,0x80,0xF0,0x00,/*"电",2*/
    0x00,0x80,0x60,0xF8,0x07,0x00,0x04,0x24,0x24,0x25,0x26,0x24,0x24,0x24,0x04,0x00,
    0x01,0x00,0x00,0xFF,0x00,0x00,0x00,0xF9,0x49,0x49,0x49,0x49,0x49,0xF9,0x00,0x00,/*"信",3*/
};
//*************************I2C初始化**********************************
void i2c_init()
{
    LPC_SYSCON->SYSAHBCLKCTRL |= 1<<7;        //开启SWM时钟
    LPC_SWM->PINENABLE0 &= ~(0x3<<11);        //使能I2C0引脚
    LPC_SYSCON->SYSAHBCLKCTRL &= ~(1<<7);     //关闭SWM时钟
    LPC_IOCON->PIO0_10 = 0x80;                //配置I2C0的SCL引脚为标准/快速模式(默认值 )
    LPC_IOCON->PIO0_11 = 0x80;                //配置I2C0的SDA引脚为标准/快速模式(默认值 )
    LPC_SYSCON->SYSAHBCLKCTRL |= 1<<5;        //开启I2C0时钟
    LPC_SYSCON->PRESETCTRL &= ~(1<<6);        //开启I2C0外设复位
    LPC_SYSCON->PRESETCTRL |= 1<<6;           //关闭I2C0外设复位        
    LPC_I2C0->CLKDIV = 0x09;                  //配置SCL时钟为系统时钟的10分频
    LPC_I2C0->MSTTIME = 0x00;                 //将每个SCL高位和低位时间都设为2个时钟周期(默认值 )
    LPC_I2C0->CFG |= 1<<0;                    //使能主机模式
}
//***************************写命令************************************
void oled_writeCmd(uint8_t cmd)
{    
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x0)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTDAT = 0x78;                  //要写入的器件地址(写方向)
    LPC_I2C0->MSTCTL = 1<<1;                  //启动传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x4)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTDAT = 0x00;                  //将要写入的是命令
    LPC_I2C0->MSTCTL = 1<<0;                  //启动重新传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x4)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTDAT = cmd;                   //要写入的命令(1字节)
    LPC_I2C0->MSTCTL = 1<<0;                  //启动重新传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x4)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTCTL = 1<<2;                  //停止传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x0)abort(); //若返回的状态不为空闲则终止
}
//***************************写数据************************************
void oled_writeData(uint8_t data)
{    
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x0)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTDAT = 0x78;                  //要写入的器件地址(写方向)
    LPC_I2C0->MSTCTL = 1<<1;                  //启动传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x4)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTDAT = 0x40;                  //将要写入的是数据
    LPC_I2C0->MSTCTL = 1<<0;                  //启动重新传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x4)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTDAT = data;                  //要写入的数据(1字节)
    LPC_I2C0->MSTCTL = 1<<0;                  //启动重新传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x4)abort(); //若返回的状态不为空闲则终止
    LPC_I2C0->MSTCTL = 1<<2;                  //停止传输
    while(!(LPC_I2C0->STAT & 0x01));          //等待I2C的状态就绪
    if((LPC_I2C0->STAT & 0xE) != 0x0)abort(); //若返回的状态不为空闲则终止
}
//***************************延时函数************************************
void delay_ms(uint32_t ms)
{
    SysTick->LOAD = (((12000)*ms)-1);         //载入初始值
    SysTick->VAL = 0;                         //写当前值寄存器使其清零
    SysTick->CTRL |= (1<<0);                  //启动定时器,选择半系统时钟
    while(!(SysTick->CTRL & 0x10000));        //循环查询,等待定时时间到
    SysTick->CTRL &= ~(1<<0);                 //关闭定时器
}
//************************oled初始化***********************************
void oled_init(void)
{
    delay_ms(100);                  //Delay 100ms(Recommended)
    oled_writeCmd(0xAE);            //Set Display Off
    oled_writeCmd(0xD5);
    oled_writeCmd(0x80);            //Set Display Clock Divide Ratio/Oscillator Frequency
    oled_writeCmd(0xA8);
    oled_writeCmd(0x3F);            //Set Multiplex Ratio
    oled_writeCmd(0xD3);
    oled_writeCmd(0x00);            //Set Display Offset
    oled_writeCmd(0x40);            //Set Display Start Line                   
    oled_writeCmd(0xA1);            //Set Segment Re-Map
    oled_writeCmd(0xC8);            //Set COM Output Scan Direction
    oled_writeCmd(0xDA);
    oled_writeCmd(0x12);            //Set COM Pins Hardware Configuration
    oled_writeCmd(0x81);
    oled_writeCmd(0xCF);            //Set Contrast Control
    oled_writeCmd(0xD9);
    oled_writeCmd(0xF1);            //Set Pre-Charge Period
    oled_writeCmd(0xDB);
    oled_writeCmd(0x30);            //Set VCOMH Deselect Level
    oled_writeCmd(0xA4);            //Set Entire Display On/Off
    oled_writeCmd(0xA6);            //Set Normal/Inverse Display
    oled_writeCmd(0x8D);
    oled_writeCmd(0x14);            //Set Charge Pump
    oled_writeCmd(0xAF);            //Set Display On
    delay_ms(100);                  //Delay 100ms(Recommended)
}
//*************************设置显示坐标********************************
void oled_setLocation(uint8_t x, uint8_t page)
{
    oled_writeCmd(0x00 | (x & 0x0F));               //写入x坐标的低四位值
    oled_writeCmd(0x10 | ((x & 0xF0) >> 4));        //写入x坐标的高四位值
    oled_writeCmd(0xB0 | page);                     //写入页坐标的值
}
//***************************清屏函数**********************************
void oled_clear(void)
{
    uint8_t i,j;
    for(j=0; j<8; j++)                              //循环写入一共8页
    {
        oled_setLocation(0, j);                     //写完一行页自动加1
        for(i=0; i<128; i++)
            oled_writeData(0x0);                    //循环写入每行128个数据0
    }
}
//*************************显示一个字符********************************
void oled_showChar(int8_t x, int8_t page, uint8_t chr, uint8_t size)
{
    uint8_t i;
    if (size == lar)                                  //大字体,一个字符占两页
    {
        oled_setLocation(x, page);                    //设置显示坐标位置
        for(i=0; i<8; i++)
        oled_writeData(oled_8x16[chr-0x20][i]);       //循环写入第一页显示数据
        oled_setLocation(x, page+1);                  //设置第二页显示
        for(i=0; i<8; i++)
            oled_writeData(oled_8x16[chr-0x20][i+8]);//循环写入第二页显示数据
    }
    else if(size == nor)                             //常规字体,一个字符占一页
    {
        oled_setLocation(x, page);                   //设置显示坐标位置
        for(i=0; i<6; i++)
            oled_writeData(oled_6x8[chr-0x20][i]);   //循环写入显示数据
    }
}
//**************************显示字符串*********************************
void oled_showString(uint8_t x, uint8_t page, char *str, uint8_t size)
{
    uint8_t i;
    for(i=0; str[i] != '\0'; i++)        //在未检测到字符串结尾时循环写入显示数据
        oled_showChar(x + i*size, page, str[i], size);
}
//***************************显示汉字**********************************
void oled_showChinese(uint8_t x, uint8_t page, const uint8_t *chr)
{
    uint8_t i,j;
    for(j=0; j<2; j++)                         //一个汉字字符占两页
    {
        oled_setLocation(x, page + j);         //设置显示坐标位置
        for(i=0; i<16; i++)
        oled_writeData(chr[16*j+i]);           //循环写入2X16个显示数据
    }
}
//*************************显示天线信号********************************
void oled_showANT(void)
{
    uint8_t i;
    oled_setLocation(0, 0);                   //设置显示坐标
    for(i=0; i<18; i++)
        oled_writeData(ANT_6x8[i]);           //写入显示天线信号数据
}
//*************************显示电池图标********************************
void oled_showBAT(void)
{
    uint8_t i;
    oled_setLocation(103, 0);                 //设置显示坐标
    for(i=0; i<24; i++)
    oled_writeData(BAT_6x8[i]);               //写入显示电池图标数据
}
//***************************主函数************************************
int main(void)
{
    i2c_init();                               //调用I2C初始化函数
    oled_init();                              //调用OLED初始化函数
    oled_clear();                             //调用清屏函数
    oled_showANT();                           //调用天线信号显示
    oled_showBAT();                           //调用电池图标显示
    oled_showChinese(25, 2, chr[0]);          //调用显示“中”
    oled_showChinese(45, 2, chr[1]);          //调用显示“国”
    oled_showChinese(65, 2, chr[2]);          //调用显示“电”
    oled_showChinese(85, 2, chr[3]);          //调用显示“信”
    oled_showString(33, 5, "2026-05-24", nor);//调用显示日期,常规大小
    oled_showString(0, 6, "MENU", lar);       //调用显示“MENU”,大字体
    oled_showString(103, 6, "MSN", lar);      //调用显示“MSN”,大字体
    while(1);                                 //无限循环
}

最终的显示效果如下图所示。 

DSC_1133 拷贝

上述代码中的所有字符数据,都是通过取模软件获取的。取模软件网上有很多,常见的有“字模提取”、“牧码字模”、“PCtoLCD2002”等。使用时需要注意设置成"列行模式"(即纵向取模),数据为“逆向方式”(即低位在上),并注意选择合适的分辨率。

posted @ 2026-05-24 14:12  fxzq  阅读(79)  评论(0)    收藏  举报