IIC协议

IIC协议概述

IIC全称Inter-Integrated Circuit (集成电路总线) 是由PHILIPS公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备。IIC属于半双 工同步通信方式

特点

  • 简单性和有效性。

由于接口直接在组件之上,因此IIC总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件

构成

IIC串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL,其时钟信号是由主控器件产生。所有接到IIC总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。对于并联在一条总线上的每个IC都有唯一的地址。

image-20220815150649916

IIC协议

IIC总线在传输数据的过程中一共有三种类型信号,分别为:开始信号、结束信号和应答信号。

//起始位,停止位,数据位,速度

这些信号中,起始信号是必需的,结束信号和应答信号

  • 起始信号

  • 终止信号

image-20220815150749694
  • 应答信号

发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节; 应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。

image-20220815150823317
  • 数据发送的时序
image-20220815150840172

OLED写命令

image-20220815155717480

写命令/数据的思路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*1. start() 
2. 写入 b0111 1000 0x78
3. ACK
4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
5. ACK
6. 写入指令/数据
7. ACK
8. STOP */


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();
}

具体的 每个参数的意义 看卖家给的文档

OLED 显示一个点

如何显示一个点?

有三种,分别位页地址模式,水平地址模式和垂直地址模式,可以通过一下表格进行配置

内存管理

image-20220815163312778

页寻址模式:

  1. 发送cmd:0x20
  2. 发送cmd: 0x02 ; 默认是页寻址模式

页地址模式

image-20220815163623674

水平地址模式

image-20220815163702760

垂直地址模式

image-20220815163717911
64 0列 1列 2列 3列 ··························· 124列 125列 126列 127列
Page0 bit0 0行
bit1 1行
bit2 2行
bit3 3行
bit4 4行
bit5 5行
bit6 6行
bit7 7行
Page1 8到15行
Page2 16到23行
Page3
Page4
Page5
Page6 56行到63行

显示一个点代码

这里我遇到的坑: 初始化会花屏 我在初始化完成后 加了一个清屏函数 就解决了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include<REG52.H>
#include<INTRINS.H>
sbit scl = P0^0;
sbit sda = P0^1;
void Oled_Clear();
void IIC_start()
{
scl = 0;
sda = 1;
scl = 1;
_nop_();
sda = 0;
_nop_();

}

void IIC_Stop()
{
scl = 0;
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最高位
_nop_(); // 发送数据建立时间
scl = 1 ; //scl 拉高开始发生
_nop_(); //数据发送时间
scl = 0 ; //发生完毕拉低
_nop_(); //数据发送时间
dataSend = dataSend << 1 ; //发送一次 移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();
}
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
Oled_Clear();
}

void Oled_Clear()
{
unsigned char i, j; //-128 --- 127
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 = 0; j < 128; j++)
{
Oled_Write_Data(0);
}
}
}
void main()
{
//oled 初始化
Oled_Init();
// 选择一个位置
// 选择页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
// 选择一个0 1011 0000 == 0xB0
Oled_Write_Cmd(0xB0);
Oled_Write_Data(0x08);
while(1);

}

显示一个字母A

通过取显示字母的 数组

image-20220815220605099

字模取出来是2*16的 需要拆解一下 因为OLED的一个page只能放8位

1
char A[2][8] ={{0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00},{0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20}} ;

我用的 是二维数组

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include<REG52.H>
#include<INTRINS.H>
sbit scl = P0^0;
sbit sda = P0^1;
void Oled_Clear();
void IIC_start()
{
scl = 0;
sda = 1;
scl = 1;
_nop_();
sda = 0;
_nop_();

}

void IIC_Stop()
{
scl = 0;
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最高位
_nop_(); // 发送数据建立时间
scl = 1 ; //scl 拉高开始发生
_nop_(); //数据发送时间
scl = 0 ; //发生完毕拉低
_nop_(); //数据发送时间
dataSend = dataSend << 1 ; //发送一次 移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();
}
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
Oled_Clear();
}

void Oled_Clear()
{
unsigned char i, j; //-128 --- 127
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 = 0; j < 128; j++)
{
Oled_Write_Data(0);
}
}
}
/*-- 文字: A --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
char A[2][8] ={{0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00},{0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20}} ;
void main()
{
int i,j;
//oled 初始化
Oled_Init();

// 选择一个位置
// 选择页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
// 选择一个page0 1011 0000 == 0xB0
for ( i =0;i<2;i++){
Oled_Write_Cmd(0xB0+i);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for (j = 0; j< 8; j++)
{
Oled_Write_Data(A[i][j]);
}
}
while(1);

}
c5258ae852af29ac815cec9acc2a3ff

显示中文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#include<REG52.H>
#include<INTRINS.H>
sbit scl = P0^0;
sbit sda = P0^1;
void Oled_Clear();
void IIC_start()
{
scl = 0;
sda = 1;
scl = 1;
_nop_();
sda = 0;
_nop_();

}

void IIC_Stop()
{
scl = 0;
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最高位
_nop_(); // 发送数据建立时间
scl = 1 ; //scl 拉高开始发生
_nop_(); //数据发送时间
scl = 0 ; //发生完毕拉低
_nop_(); //数据发送时间
dataSend = dataSend << 1 ; //发送一次 移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();
}
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
Oled_Clear();
}

void Oled_Clear()
{
unsigned char i, j; //-128 --- 127
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 = 0; j < 128; j++)
{
Oled_Write_Data(0);
}
}
}
/*-- 文字: 小 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char xiao[2][16]={{0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x20,0x40,0x80,0x00,0x00},
{0x08,0x04,0x03,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x01,0x0E,0x00}};

/*-- 文字: 刘 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char liu[2][16] ={{0x08,0x28,0x48,0x89,0x0E,0x88,0x78,0x08,0x08,0x00,0xF8,0x00,0x00,0xFF,0x00,0x00},
{0x40,0x20,0x10,0x09,0x06,0x19,0x60,0x00,0x00,0x00,0x0F,0x40,0x80,0x7F,0x00,0x00}};

/*-- 文字: 同 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char tong[2][16]= {{0x00,0x00,0xFE,0x02,0x12,0x92,0x92,0x92,0x92,0x92,0x92,0x12,0x02,0xFE,0x00,0x00},
{0x00,0x00,0xFF,0x00,0x00,0x1F,0x08,0x08,0x08,0x08,0x1F,0x40,0x80,0x7F,0x00,0x00}};

/*-- 文字: 学 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char xue[2][16]={{0x40,0x30,0x11,0x96,0x90,0x90,0x91,0x96,0x90,0x90,0x98,0x14,0x13,0x50,0x30,0x00},
{0x04,0x04,0x04,0x04,0x04,0x44,0x84,0x7E,0x06,0x05,0x04,0x04,0x04,0x04,0x04,0x00}};


void main()
{
int i,j;
//oled 初始化
Oled_Init();

// 选择一个位置
// 选择页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
// 选择一个page0 1011 0000 == 0xB0
for ( i =0;i<2;i++){
Oled_Write_Cmd(0xB0+i);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for (j = 0; j< 16; j++)
{
Oled_Write_Data(xiao[i][j]);
}
for (j = 0; j< 16; j++)
{
Oled_Write_Data(liu[i][j]);
}
for (j = 0; j< 16; j++)
{
Oled_Write_Data(tong[i][j]);
}
for (j = 0; j< 16; j++)
{
Oled_Write_Data(xue[i][j]);
}

}


while(1);

}
441c9b56fdfac5f5ef87d2cd68608ca

相机拍摄的 刷新率有问题 肉眼看到没有 横杠

显示 照片

需要先对图片进行处理 分辨率为128*64

输出方法类似清屏 只不过 清屏时候 写入的 数据是0 显示图片 换成对应的数组值

image-20220815231250630
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#include<REG52.H>
#include<INTRINS.H>
sbit scl = P0^0;
sbit sda = P0^1;
void Oled_Clear();
void IIC_start()
{
scl = 0;
sda = 1;
scl = 1;
_nop_();
sda = 0;
_nop_();

}

void IIC_Stop()
{
scl = 0;
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最高位
_nop_(); // 发送数据建立时间
scl = 1 ; //scl 拉高开始发生
_nop_(); //数据发送时间
scl = 0 ; //发生完毕拉低
_nop_(); //数据发送时间
dataSend = dataSend << 1 ; //发送一次 移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();
}
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
Oled_Clear();
}

void Oled_Clear()
{
unsigned char i, j; //-128 --- 127
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 = 0; j < 128; j++)
{
Oled_Write_Data(0);
}
}
}
void Oled_Show_Image(unsigned char* img)
{
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(img[j]);
}
}
}
unsigned char code BMP1[] =
{
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,0xC0,0xC0,0xE0,0xE0,0xE0,0xE0,0xF0,
0xF0,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0x70,0x70,0xE0,0xE0,0xFE,0xFE,0xFE,0xFE,0xBE,
0xBE,0x1E,0x1E,0x1F,0x1F,0x1F,0x1F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x03,
0x03,0x83,0x83,0x83,0x83,0x03,0x03,0x67,0x67,0x67,0x67,0x67,0x67,0x06,0x06,0x86,
0x86,0x8E,0x8E,0x8E,0x8E,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x38,0x38,0x78,0x78,0x70,
0x70,0xE0,0xE0,0xE0,0xE0,0xC0,0xC0,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xE0,0xE0,0xF8,0xF8,0xF8,
0xF8,0xF8,0xF8,0xF9,0xF9,0x73,0x73,0x2F,0x2F,0x0F,0x0F,0x0F,0x0F,0x07,0x07,0x03,
0x03,0x01,0x01,0x70,0x70,0x7E,0x7E,0x3F,0x3F,0x0F,0x0F,0x7F,0x7F,0xFF,0xFF,0xFF,
0xFF,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x04,0x04,0x05,0x05,0x05,0x05,0x07,0x07,0x16,0x16,0x1E,0x1E,0x3E,0x3E,0x3E,
0x3E,0x3F,0x3F,0x1F,0x1F,0x07,0x07,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x1F,0x1F,0x3F,
0x3F,0x3F,0x3F,0x7F,0x7F,0x77,0x77,0x7F,0x7F,0x3F,0x3F,0x3F,0x3F,0x7E,0x7E,0xFC,
0xFC,0xF8,0xF8,0xE0,0xE0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x18,0x18,0x3E,0x3E,0x7F,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,
0x1F,0x07,0x07,0x81,0x81,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x06,0x06,0x04,0x04,0x04,0x04,0x0C,0x0C,0x0C,
0x0C,0x0C,0x0C,0x3C,0x3C,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7E,0x7E,0xFE,0xFC,0xEC,
0xEC,0xF0,0xF0,0xFC,0xFC,0xFC,0xFC,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,
0x00,0x03,0x03,0x1F,0x1F,0xFF,0xFF,0xFF,0xFF,0xFE,0xFE,0xF8,0xF8,0xC0,0xC0,0x00,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFC,0xFC,0xFC,0xFC,0x18,0x18,0x7D,
0x7D,0xFD,0xFD,0xFF,0xFF,0xDF,0xDF,0x3F,0x3F,0x3B,0x3B,0x3B,0x3B,0x33,0x33,0x33,
0x33,0x23,0x23,0x03,0x03,0x01,0x01,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,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
0x03,0x07,0x07,0x0F,0x0F,0x0F,0x0F,0x9E,0x9E,0xFD,0xFD,0xF9,0xF9,0xFC,0xFC,0xFC,
0xFC,0x78,0x78,0xF8,0xF8,0xF9,0xF9,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,
0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x7F,0x78,0x78,0x00,
0x00,0x00,0x00,0x81,0x81,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
0x00,0xC0,0xC0,0xE0,0xE0,0xF0,0xF0,0x78,0x78,0xB8,0xB8,0xDC,0xDC,0xCE,0xCE,0xEE,
0xEE,0x77,0x77,0x77,0x77,0xB7,0xB7,0xBB,0xBB,0xBB,0xBB,0xDB,0xDB,0xDB,0xDB,0xDB,
0xDB,0xDB,0xDB,0xDB,0xDB,0xBB,0xBB,0xBB,0xBB,0xB7,0xB7,0x77,0x77,0x77,0x77,0xEE,
0xEE,0xDE,0xDE,0xDC,0xDC,0xB8,0xB8,0x78,0x78,0xF0,0xF0,0xE0,0xE0,0xC0,0xC0,0x00,
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x81,0x81,0x83,0x83,0x83,0x83,0x0F,0x0F,0x0F,
0x1F,0x1F,0x1F,0x1F,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,
0x00,0x01,0x01,0x19,0x19,0x5D,0x5D,0xDE,0xDE,0xEE,0xEE,0xF6,0xF6,0x77,0x77,0xB7,
0xB7,0xBB,0xBB,0xBB,0xBB,0xFB,0xFB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xBB,0xBB,0xBB,
0xBB,0xBB,0xBB,0xB7,0xB7,0x77,0x77,0xFF,0xFF,0xEF,0xEF,0xDF,0xDF,0xDD,0xDD,0xBE,
0xBE,0x7F,0x7F,0xF7,0xF7,0xFB,0xFB,0xFB,0xFB,0x1D,0x1D,0x1D,0x9D,0x8D,0x8D,0x8D,
0x8D,0x8D,0x8D,0x1D,0x1D,0x1D,0x1D,0xFB,0xFB,0xFB,0xFB,0xF7,0xF7,0x7F,0x7F,0xBE,
0xBE,0xDD,0xDD,0xDF,0xDF,0xEF,0xEF,0xFF,0xFF,0x77,0x77,0xF7,0xF7,0xBB,0xBB,0xBB,
0xBB,0xBB,0xBB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xB7,
0xB7,0x77,0x77,0xF6,0xF6,0xEE,0xEE,0xDE,0xDE,0x5D,0x5D,0x19,0x19,0x01,0x01,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x07,0x17,0x17,0x3B,
0x3B,0x3B,0x3B,0x1D,0x1D,0x1D,0x1D,0x1D,0x1D,0x0D,0x0D,0x1D,0x1D,0x1D,0x1D,0x1F,
0x1F,0xFB,0xFB,0xF7,0xF7,0xF7,0xF7,0x7E,0x7E,0xBE,0xBE,0xDD,0xDD,0xDF,0xDF,0xEF,
0xEF,0xFF,0xFF,0x77,0x77,0xF7,0xF7,0xBF,0xBF,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xB7,0xB7,0xF7,0xF7,0x77,0x77,0xEF,0xEF,0xEF,
0xEF,0xDF,0xDF,0xBD,0xBD,0xBE,0xBE,0x7E,0x7E,0xF7,0xF7,0xF7,0xF7,0xFB,0xFB,0x1F,
0x1F,0x1D,0x1D,0x1D,0x1D,0x0D,0x0D,0x1D,0x1D,0x1D,0x1D,0x1F,0x1F,0x3B,0x3B,0x3B,
0x3B,0x17,0x17,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0E,0x0F,
0x0F,0x0F,0x0F,0x3B,0x3B,0x3D,0x3D,0x3F,0x3F,0x6F,0x6F,0x77,0x77,0x7D,0x7D,0x3E,
0x3E,0xDE,0xDE,0xF7,0xF7,0xF7,0xF7,0x3B,0x3B,0x3B,0x3B,0x1D,0x1D,0x1D,0x1D,0x1D,
0x1D,0x1D,0x1D,0x1D,0x1D,0x3B,0x3B,0x3B,0x3B,0xF7,0xF7,0xF7,0xF7,0xDE,0xDE,0x3E,
0x3E,0x7D,0x7D,0x77,0x77,0x6F,0x6F,0x3E,0x3E,0x3D,0x3D,0x3B,0x3B,0x0F,0x0F,0x0F,
0x0F,0x0E,0x0E,0x00,0x00,0x00,0x00,0x00,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 main()
{

//oled 初始化
Oled_Init();

// 选择一个位置
// 选择页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
// 选择一个page0 1011 0000 == 0xB0

Oled_Write_Cmd(0xB0);
Oled_Show_Image(BMP1);



while(1);

}
705b8c6db0fe5ca8b8d9601c3f984b1