IIC协议
一、IIC协议
1.1 IIC协议概述
IIC全称Inter-Integrated Circuit (集成电路总线)
是由PHILIPS(飞利浦)公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备。IIC属于半双工同步通信方式
特点
由于接口直接在组件之上,因此IIC总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件
- 一根线(SDA),同一时间只能发送或者是接收。、
- 蓝牙串口是两个线
- IIC有两条总线,一条双向的串行数据线SDA,一条串行时钟线SCL。
- SDA(Serial data):串行数据线,用来传送数据;
- SCL(Serial clock line):时钟线,用来控制数据发送的时序。
其中任何能够进行发送和接收的设备都可以成为主总线。一个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主控。
构成
IIC串行总线一般有两根信号线,
其时钟信号是由主控器件产生。所有接到IIC总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。对于并联在一条总线上的每个IC都有唯一的地址。
1.2 IIC协议
IIC总线在传输数据的过程中一共有三种类型信号,分别为:开始信号、结束信号和应答信号。
//起始位,停止位,数据位,速度
1. 起终信号
这些信号中,起始信号是必需的,结束信号和应答信号
- SCL =1
- SDA = 1;
- 延时
- while(!sda)
- 延时
2. 应答信号
发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。
应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节; 应答信号为高电平时,规定为非应答(ACK),一般表示接收器接收该字节没有成功。
sda(应答信号)为高电平,延迟5微妙,(时钟线)SCL为高电平。延迟5微妙之后,去读sda(应答信号),为高\低电平,高电平(非应答)\低电平(应答),延迟5微妙,(时钟线)SCL为低电平,延迟5微妙
char IIC_ACK() // 应答
{
char flag;
sda = 1;//就在时钟脉冲9期间释放数据线
_nop_();
scl = 1;
_nop_();
flag = sda;
_nop_();
scl = 0;
_nop_();
return flag;
}
3. 数据发送的字节
注意当scl属于高电平期间,就是在传输数据,SDA不能出现数据翻转,防止系统误以为是起终止信号,当SCL属于低电平期间时,数据可以进行翻转
void IIC_Send_Byte(char dataSend)
{
int i;
for(i = 0;i<8;i++){
scl = 0;//scl拉低,让sda做好数据准备
sda = dataSend & 0x80;//1000 0000获得dataSend的最高位,给sda
_nop_();//发送数据建立时间
scl = 1;//scl拉高开始发送
_nop_();//数据发送时间
scl = 0;//发送完毕拉低
_nop_();//
dataSend = dataSend << 1;
}
}
void Oled_Write_Cmd(char dataCmd)
{
// 1. start()
IIC_Start();
//
// 2. 写入从机地址 b0111 1000 0x78
IIC_Send_Byte(0x78);
// 3. ACK
IIC_ACK();
// 4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
IIC_Send_Byte(0x00);
// 5. ACK
IIC_ACK();
//6. 写入指令/数据
IIC_Send_Byte(dataCmd);
//7. ACK
IIC_ACK();
//8. STOP
IIC_Stop();
}
void Oled_Write_Data(char dataData)
{
// 1. start()
IIC_Start();
//
// 2. 写入从机地址 b0111 1000 0x78
IIC_Send_Byte(0x78);
// 3. ACK
IIC_ACK();
// 4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
IIC_Send_Byte(0x40);
// 5. ACK
IIC_ACK();
///6. 写入指令/数据
IIC_Send_Byte(dataData);
//7. ACK
IIC_ACK();
//8. STOP
IIC_Stop();
}
4. OLED的寻址模式
有三种,分别位页地址模式,水平地址模式和垂直地址模式,可以通过一下表格进行配置
内存管理
如果写入0x08(b00001000)会显示什么呢
一个字节负责一个Page的一列显示
#include "reg52.h"
#include "intrins.h"
sbit scl = P2^5;
sbit sda = P2^6;
void IIC_Start()
{
sda = 1;
scl = 1;
_nop_();
sda = 0;
_nop_();
}
void IIC_Stop()
{
sda = 0;
scl = 1;
_nop_();
sda = 1;
_nop_();
}
char IIC_ACK()
{
char flag;
sda = 1;//就在时钟脉冲9期间释放数据线
_nop_();
scl = 1;
_nop_();
flag = sda;
_nop_();
scl = 0;
_nop_();
return flag;
}
void IIC_Send_Byte(char dataSend)
{
int i;
for(i = 0;i<8;i++){
scl = 0;//scl拉低,让sda做好数据准备
sda = dataSend & 0x80;//1000 0000获得dataSend的最高位,给sda
_nop_();//发送数据建立时间
scl = 1;//scl拉高开始发送
_nop_();//数据发送时间
scl = 0;//发送完毕拉低
_nop_();//
dataSend = dataSend << 1;
}
}
void Oled_Write_Cmd(char dataCmd)
{
// 1. start()
IIC_Start();
//
// 2. 写入从机地址 b0111 1000 0x78
IIC_Send_Byte(0x78);
// 3. ACK
IIC_ACK();
// 4. cotrol byte: (0)(0)000000 写入命令
IIC_Send_Byte(0x00);
// 5. ACK
IIC_ACK();
//6. 写入指令/数据
IIC_Send_Byte(dataCmd);
//7. ACK
IIC_ACK();
//8. STOP
IIC_Stop();
}
void Oled_Write_Data(char dataData)
{
// 1. start()
IIC_Start();
//
// 2. 写入从机地址 b0111 1000 0x78
IIC_Send_Byte(0x78);
// 3. ACK
IIC_ACK();
// 4. cotrol byte: (0)(1)000000写入数据
IIC_Send_Byte(0x40);
// 5. ACK
IIC_ACK();
///6. 写入指令/数据
IIC_Send_Byte(dataData);
//7. ACK
IIC_ACK();
//8. STOP
IIC_Stop();
}
void Oled_Init(void){ // 初始化
Oled_Write_Cmd(0xAE);//--display off
Oled_Write_Cmd(0x00);//---set low column address
Oled_Write_Cmd(0x10);//---set high column address
Oled_Write_Cmd(0x40);//--set start line address
Oled_Write_Cmd(0xB0);//--set page address
Oled_Write_Cmd(0x81); // contract control
Oled_Write_Cmd(0xFF);//--128
Oled_Write_Cmd(0xA1);//set segment remap
Oled_Write_Cmd(0xA6);//--normal / reverse
Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
Oled_Write_Cmd(0x3F);//--1/32 duty
Oled_Write_Cmd(0xC8);//Com scan direction
Oled_Write_Cmd(0xD3);//-set display offset
Oled_Write_Cmd(0x00);//
Oled_Write_Cmd(0xD5);//set osc division
Oled_Write_Cmd(0x80);//
Oled_Write_Cmd(0xD8);//set area color mode off
Oled_Write_Cmd(0x05);//
Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
Oled_Write_Cmd(0xF1);//
Oled_Write_Cmd(0xDA);//set com pin configuartion
Oled_Write_Cmd(0x12);//
Oled_Write_Cmd(0xDB);//set Vcomh
Oled_Write_Cmd(0x30);//
Oled_Write_Cmd(0x8D);//set charge pump enable
Oled_Write_Cmd(0x14);//
Oled_Write_Cmd(0xAF);//--turn on oled panel
}
void main()
{
int a = 10;
int i;
//1. OLED初始化
Oled_Init();
//2. 选择一个位置
//2.1 确认页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
//2.2 选择PAGE 0 1011 0000
// 0xB0(8421法)
Oled_Write_Cmd(0xB0);
// 发送指令0xB0,
// 这个指令选择第0页(PAGE 0)。
// OLED的页地址从0xB0到0xB7,每一个指令分别对应一个页。
//3. 显示一个行 列地址会自动向后偏移
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
Oled_Write_Data(0x08);
while(1);
}
为127列 +0列,是最后一行
Oled_Write_Cmd(0x0f);
Oled_Write_Cmd(0x17);
Oled_Write_Data(0x08);
void Oled_Clear()
{
unsigned char i,j; // 定义两个无符号字符变量 i 和 j,用于循环控制
for(i=0;i<8;i++){ // 外层循环,循环8次,分别清除8页(每页8行,总共64行)
Oled_Write_Cmd(0xB0 + i);// 设置当前页地址,从 page0 到 page7
// 每个 page 从第 0 列开始
Oled_Write_Cmd(0x00); // 设置列地址的低四位为 0
Oled_Write_Cmd(0x10); // 设置列地址的高四位为 1,结合低四位,列地址为 0
// 从第 0 列到第 127 列,依次写入 0,每写入一个数据,列地址会自动增加
for(j = 0;j<128;j++){ // 内层循环,循环128次,清除当前页的所有列(每页128列)
Oled_Write_Data(0); // 向当前列写入数据 0,即清除该列
}
}
}
-
- 变量声明
unsigned char i,j;
i
和 j
,用于循环控制。-
- 外层循环
for(i=0;i<8;i++){
-
- 设置当前页地址
Oled_Write_Cmd(0xB0 + i);
0xB0
到 0xB7
分别对应 page0
到 page7
。-
- 设置列地址
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
0x00
设置低四位为 0,然后发送 0x10
设置高四位为 0,这样列地址被设置为 0x00
。-
- 内层循环
for(j = 0;j<128;j++){
-
- 清除当前列
Oled_Write_Data(0);
0
,即清除该列。写入数据后,列地址会自动增加,直到当前页的所有列都被清除。void Oled_Screen_Clear(void){
char i,n;
Oled_Write_Cmd (0x20); // 设置内存寻址模式
Oled_Write_Cmd (0x02); // 选择页寻址模式
for(i=0;i<8;i++){
Oled_Write_Cmd(0xb0+i); // 设置页地址(0~7)
Oled_Write_Cmd(0x00); // 设置显示位置列低地址
Oled_Write_Cmd(0x10); // 设置显示位置列高地址
for(n=0;n<128;n++) // 循环128次,对应每页的128列
Oled_Write_Data(0x00); // 写入数据0,清除该列
}
}
/*-- 文字: A --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
char A1[8] = {0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00};
char A2[8] = {0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20};
void main()
{
int i;
//1. OLED初始化
Oled_Init();
//2. 选择一个位置
//2.1 确认页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
Oled_Clear();
//2.2 选择PAGE0 1011 0000
// 0xB0
// 打印字符‘A’
Oled_Write_Cmd(0xB0); // 打印上半身
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i=0;i<8;i++){
Oled_Write_Data(A1[i]);
}
Oled_Write_Cmd(0xB1);// 打印下半身
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i=0;i<8;i++){
Oled_Write_Data(A2[i]);
}
while(1);
}
5. OLED 显示字符 'A' 的实现
先使用点阵液晶取模软件生成字符
-
- 初始化 OLED
Oled_Init();
-
- 选择页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
-
- 清屏
Oled_Clear();
-
- 显示字符 'A'
Oled_Write_Cmd(0xB0); // 设置页地址为 PAGE0
Oled_Write_Cmd(0x00); // 设置列地址低位
Oled_Write_Cmd(0x10); // 设置列地址高位
for (i = 0; i < 8; i++) {
Oled_Write_Data(A1[i]);
}
Oled_Write_Cmd(0xB1); // 设置页地址为 PAGE1
Oled_Write_Cmd(0x00); // 设置列地址低位
Oled_Write_Cmd(0x10); // 设置列地址高位
for (i = 0; i < 8; i++) {
Oled_Write_Data(A2[i]);
}
6. 显示一个字符串“LXL”
/*-- 文字: L --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
code char L1[8] = {0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00}; // "L" 字符的上半部分点阵数据
code char L2[8] = {0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00}; // "L" 字符的下半部分点阵数据
/*-- 文字: X --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
code char L3[8] = {0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08}; // "X" 字符的上半部分点阵数据
code char L4[8] = {0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20}; // "X" 字符的下半部分点阵数据
void main()
{
int i,j; // 定义循环变量 i 和 j
// 1. OLED初始化
Oled_Init(); // 调用 OLED 初始化函数
// 2. 选择一个位置
// 2.1 确认页寻址模式
Oled_Write_Cmd(0x20); // 设置内存寻址模式
Oled_Write_Cmd(0x02); // 设置为页寻址模式
Oled_Clear(); // 清屏
// 2.2 选择PAGE0 (1011 0000)
// 设置起始位置为第0页 (Page 0)
Oled_Write_Cmd(0xB0); // 设置页地址为 Page 0
Oled_Write_Cmd(0x00); // 设置列地址低4位为 0x00
Oled_Write_Cmd(0x10); // 设置列地址高4位为 0x10,即列地址为 0x00
// 显示第一个字符 "L" 的上半部分
for(i=0;i<8;i++){
Oled_Write_Data(L1[i]); // 依次写入 "L" 字符上半部分的点阵数据
}
// 显示字符 "X" 的上半部分
for(i=0;i<8;i++){
Oled_Write_Data(L3[i]); // 依次写入 "X" 字符上半部分的点阵数据
}
// 再次显示字符 "L" 的上半部分
for(i=0;i<8;i++){
Oled_Write_Data(L1[i]); // 依次写入 "L" 字符上半部分的点阵数据
}
// 选择PAGE1 (1011 0001)
// 设置起始位置为第1页 (Page 1)
Oled_Write_Cmd(0xB1); // 设置页地址为 Page 1
Oled_Write_Cmd(0x00); // 设置列地址低4位为 0x00
Oled_Write_Cmd(0x10); // 设置列地址高4位为 0x10,即列地址为 0x00
// 显示字符 "L" 的下半部分
for(j=0;j<8;j++){
Oled_Write_Data(L2[j]); // 依次写入 "L" 字符下半部分的点阵数据
}
// 显示字符 "X" 的下半部分
for(j=0;j<8;j++){
Oled_Write_Data(L4[j]); // 依次写入 "X" 字符下半部分的点阵数据
}
// 再次显示字符 "L" 的下半部分
for(j=0;j<8;j++){
Oled_Write_Data(L2[j]); // 依次写入 "L" 字符下半部分的点阵数据
}
while(1); // 无限循环,保持显示
}
Oled_Write_Cmd
函数: 用于发送命令到 OLED,比如设置页面地址、列地址等。Oled_Write_Data
函数: 用于发送数据到 OLED,比如每个字符的点阵数据。Oled_Init
函数: 初始化 OLED 显示屏,使其进入可操作状态。Oled_Clear
函数: 清空 OLED 显示屏的内容。for
循环: 第一个 for 循环显示字符的上半部分(Page 0),第二个 for 循环显示字符的下半部分(Page 1)。这样分开写入可以确保字符显示正确。
- 字符点阵的排列方式:在原始方法中,每个字符的数据分别通过单独的
for
循环写入 OLED。这意味着第一个字符的所有点阵数据(上半部分)会首先写入,然后是第二个字符的所有点阵数据,依次类推。这样可以确保每个字符的数据连续写入 OLED 显示屏的相应列,不会混淆。 - 显示顺序:每个
for
循环对应一个字符的数据块,这样可以保持字符在 OLED 显示屏上的正确显示顺序。例如,第一个字符“上”的上半部分数据在s1
数组中,依次写入 OLED 显示屏的第一页;第二个字符“官”的上半部分数据在g1
数组中,依次写入同一页面的后续列。
- 数据混淆:如果你使用修改后的方法,将所有字符的数据在一个
for
循环中交替写入,字符的点阵数据会交错。例如,第一个字符“上”的第一列数据(s1[0])写入后,接着是第二个字符“官”的第一列数据(g1[0]),然后是第三个字符的数据(k1[0]),依次类推。这会导致字符的显示数据混在一起,无法正确显示。 - 位置不对:OLED 显示屏的列地址会在写入数据后自动递增,因此在单个
for
循环中交替写入不同字符的数据会导致它们无法正确排列在显示屏上。每个字符的数据会被打乱,显示效果会非常混乱。
原始方法通过多个 for
循环确保每个字符的数据独立、连续地写入 OLED 显示屏,保持字符的正确显示顺序和位置。修改后的方法则会导致字符数据交错,显示效果混乱。因此,必须保持原始方法的写法,以确保 OLED 显示屏上字符的正确显示。
为了更好地理解这一点,可以试想一个示例:
假设有两个字符“A”和“B”,它们的点阵数据如下:
{A1[0], A1[1], A1[2], ..., A1[7]}
{B1[0], B1[1], B1[2], ..., B1[7]}
如果使用原始方法:
如果使用修改后的方法:
因此,保持原始方法的 for
循环写法是正确的,确保字符正确显示。
7. ode 关键字
code 指定字符存储位置,以防存储空间过大
在 C51 单片机编程中,可以使用 code
关键字来将常量数据存储在代码存储区(Flash)中,而不是在数据存储区(RAM)中。这对于存储大量的字符点阵数据非常有用,因为 RAM 的空间通常非常有限,而 Flash 的空间相对较大。
8. 显示文字”越加越强“
/*-- 文字: 越 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char y1[16] = {0x40,0x48,0x48,0xFF,0x48,0x48,0x00,0xF8,0x08,0x08,0xFF,0x08,0x89,0x6A,0x00,0x00};
code char y2[16] = {0x80,0x7E,0x10,0x3F,0x44,0x44,0x40,0x4F,0x44,0x50,0x49,0x46,0x49,0x5C,0x40,0x00};
/*-- 文字: 加 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char j1[16] = {0x10,0x10,0x10,0xFF,0x10,0x10,0xF0,0x00,0x00,0xF8,0x08,0x08,0x08,0xF8,0x00,0x00};
code char j2[16] = {0x80,0x40,0x30,0x0F,0x40,0x80,0x7F,0x00,0x00,0x7F,0x20,0x20,0x20,0x7F,0x00,0x00};
/*-- 文字: 越 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char y3[16] = {0x40,0x48,0x48,0xFF,0x48,0x48,0x00,0xF8,0x08,0x08,0xFF,0x08,0x89,0x6A,0x00,0x00};
code char y4[16] = {0x80,0x7E,0x10,0x3F,0x44,0x44,0x40,0x4F,0x44,0x50,0x49,0x46,0x49,0x5C,0x40,0x00};
/*-- 文字: 强 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char q1[16] = {0x02,0xE2,0x22,0x22,0x3E,0x00,0x80,0x9E,0x92,0x92,0xF2,0x92,0x92,0x9E,0x80,0x00};
code char q2[16] = {0x00,0x43,0x82,0x42,0x3E,0x40,0x47,0x44,0x44,0x44,0x7F,0x44,0x44,0x54,0xE7,0x00};
void main()
{
int i;
//1. OLED初始化
Oled_Init();
//2. 选择一个位置
//2.1 确认页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
Oled_Clear(); // 清屏
//2.2 选择PAGE0 1011 0000
// 0xB0
// 从第一行第0列开始打印上半部分
Oled_Write_Cmd(0xB0);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i=0;i<16;i++){
Oled_Write_Data(y1[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(j1[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(y3[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(q1[i]);
}
// 从第二行第0列开始打印下半部分
Oled_Write_Cmd(0xB1);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i=0;i<16;i++){
Oled_Write_Data(y2[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(j2[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(y4[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(q2[i]);
}
while(1);
}
9. 显示一张图片和一段字符串”lxl“
code unsigned char bmpImager[] = {
/*-- 调入了一幅图像:C:\Users\86199\Pictures\无标题.bmp --*/
/*-- 宽度x高度=128x64 --128X8X8*/
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,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,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,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,
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,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0xF0,0xD0,0xD6,0xD6,0xDE,0xDE,0xDE,0xDE,0x5E,0x5E,0x56,0x56,0x50,0x50,0x50,0x50,
0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0xD8,0x88,0x88,0x88,
0xF8,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,0x1F,0x10,0x1F,0x08,0x08,0x08,0x0E,0x1A,0x1A,0x1A,
0x0E,0x02,0x02,0x02,0x0E,0x0A,0x0A,0x0F,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,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,
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,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,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,
};
void Oled_Show_Image(unsigned char *image)
{
unsigned char i;
unsigned int j;
for(i=0;i<8;i++){
Oled_Write_Cmd(0xB0 + i);//page0--page7
//每个page从0列
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
//0到127列,依次写入0,每写入数据,列地址自动偏移
for(j = 128 * i; j<(128 * (i+1));j++){
Oled_Write_Data(image[j]);
}
}
}
/*-- 文字: L --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
code char L1[8] = {0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00}; // "L" 字符的上半部分点阵数据
code char L2[8] = {0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00}; // "L" 字符的下半部分点阵数据
/*-- 文字: X --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
code char L3[8] = {0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08}; // "X" 字符的上半部分点阵数据
code char L4[8] = {0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20}; // "X" 字符的下半部分点阵数据
void main()
{
int i,j;
//1. OLED初始化
Oled_Init();
//2. 选择一个位置
//2.1 确认页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
Oled_Clear();
Oled_Show_Image(bmpImager);
Oled_Write_Cmd(0xB0); // 设置页地址为 Page 0
Oled_Write_Cmd(0x00); // 设置列地址低4位为 0x00
Oled_Write_Cmd(0x10); // 设置列地址高4位为 0x10,即列地址为 0x00
// 显示第一个字符 "L" 的上半部分
for(i=0;i<8;i++){
Oled_Write_Data(L1[i]); // 依次写入 "L" 字符上半部分的点阵数据
}
// 显示字符 "X" 的上半部分
for(i=0;i<8;i++){
Oled_Write_Data(L3[i]); // 依次写入 "X" 字符上半部分的点阵数据
}
// 再次显示字符 "L" 的上半部分
for(i=0;i<8;i++){
Oled_Write_Data(L1[i]); // 依次写入 "L" 字符上半部分的点阵数据
}
// 选择PAGE1 (1011 0001)
// 设置起始位置为第1页 (Page 1)
Oled_Write_Cmd(0xB1); // 设置页地址为 Page 1
Oled_Write_Cmd(0x00); // 设置列地址低4位为 0x00
Oled_Write_Cmd(0x10); // 设置列地址高4位为 0x10,即列地址为 0x00
// 显示字符 "L" 的下半部分
for(j=0;j<8;j++){
Oled_Write_Data(L2[j]); // 依次写入 "L" 字符下半部分的点阵数据
}
// 显示字符 "X" 的下半部分
for(j=0;j<8;j++){
Oled_Write_Data(L4[j]); // 依次写入 "X" 字符下半部分的点阵数据
}
// 再次显示字符 "L" 的下半部分
for(j=0;j<8;j++){
Oled_Write_Data(L2[j]); // 依次写入 "L" 字符下半部分的点阵数据
}
while(1); // 无限循环,保持显示
}
先将照片设置成128×64像素,并且将照片保存为BMP类型的格式,然后使用字模识别软件,打开该图片。生成c51格式代码,封装成函数调用即可
void Oled_Show_Image(unsigned char *image)
{
unsigned char i;
unsigned int j;
for(i=0;i<8;i++){
Oled_Write_Cmd(0xB0 + i);//page0--page7
//每个page从0列
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
//0到127列,依次写入0,每写入数据,列地址自动偏移
for(j = 128 * i; j<(128 * (i+1));j++){
Oled_Write_Data(image[j]);
}
}
}
c
复制代码
void Oled_Show_Image(unsigned char *image)
Oled_Show_Image
,它接受一个指向无符号字符数组(即图像数据)的指针 image
作为参数。c
复制代码
unsigned char i;
unsigned int j;
i
用于循环遍历OLED屏幕的页(共8页),j
用于遍历每一页中的像素数据。c
复制代码
for(i=0; i<8; i++) {
Oled_Write_Cmd(0xB0 + i); // 选择当前页(page0--page7)
for
循环遍历了OLED屏幕的8个页,每个页包含8行像素(总共64行)。Oled_Write_Cmd(0xB0 + i);
选择了当前操作的页,i
的范围是从0到7,对应页地址从0xB0到0xB7。c
复制代码
Oled_Write_Cmd(0x00); // 设置当前列的低位地址为0
Oled_Write_Cmd(0x10); // 设置当前列的高位地址为0
c
复制代码
for(j = 128 * i; j < (128 * (i + 1)); j++) {
Oled_Write_Data(image[j]); // 写入当前页的图像数据
}
}
for
循环从图像数据中取出对应当前页的128个字节(对应128列)的数据并写入OLED屏幕。j = 128 * i
计算当前页的起始位置,128 * (i + 1)
计算该页数据的结束位置。Oled_Write_Data(image[j]);
这一行将图像数组中的数据发送到OLED屏幕,显示在当前页的对应列上。Oled_Show_Image
函数的主要功能是将一幅128×64像素的图像(分8页,每页128列)显示到OLED屏幕上。每个页的数据依次写入OLED显示屏的对应位置。
作者:越加越强