- 全称 Inter-Integrated Circuit (集成电路总线)
- 是由 PHILIPS 公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备
- 属于半双工同步通信方式
#include "reg52.h"
#include "intrins.h"
sbit scl = P0^1;
sbit sda = P0^3;
void IIC_start(){
sda = 1;
scl = 1;
_nop_();//5us
sda = 0;
_nop_();
}
void IIC_stop(){
sda = 0;
scl = 1;
_nop_();
sda = 1;
_nop_();
}
char IIC_ACK(){//Answer back
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();
}
PAGE地址选择
如果写入0x08(b00001000)会显示什么呢
void Oled_Init(){
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;
//1. OLED初始化
Oled_Init();
//2. 选择一个位置
//2.1 确认页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
//2.2 选择PAGE0 1011 0000 即 0xB0
Oled_Write_Cmd(0xB0);
//3. 显示一个点
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
while(1);//不让程序结束
}
void main(){
int a = 10;
//1. OLED初始化
Oled_Init();
//2. 选择一个位置
//2.1 确认页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
//2.2 选择PAGE0 1011 0000 即 0xB0
Oled_Write_Cmd(0xB0);
Oled_Write_Cmd(0x00);//列地址选择要用两个字节
Oled_Write_Cmd(0x10);//定位到首列
//3. 显示一个点*8
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_Cmd(0xB5);//在0xB5行显示........
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
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_Cmd(0xB6);//列是递增的
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
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_Cmd(0x0f);
Oled_Write_Cmd(0x17);//在0xB6行的最后一列显示一个点
Oled_Write_Data(0x08);
while(1);//不让程序结束
}
/*-- 文字: 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 = 0;
//1. OLED初始化
Oled_Init();
//2. 选择一个位置
//2.1 确认页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
Oled_Clear(); //清屏函数
//2.2 选择PAGE0 1011 0000 即 0xB0
Oled_Write_Cmd(0xB0);
Oled_Write_Cmd(0x00);//列地址选择要用两个字节
Oled_Write_Cmd(0x10);//定位到首列
for(i = 0;i < 8;i++){//显示‘A’的上半部分
Oled_Write_Data(A1[i]);
}
Oled_Write_Cmd(0xB1);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);//定位到首列
for(i = 0;i < 8;i++){//显示‘A’的下半部分
Oled_Write_Data(A2[i]);
}
while(1);//不让程序结束
}
/*-- 文字: 我 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char w1[16] = {0x20,0x24,0x24,0x24,0xFE,0x23,0x22,0x20,0x20,0xFF,0x20,0x22,0x2C,0xA0,0x20,0x00};
code char w2[16] = {0x00,0x08,0x48,0x84,0x7F,0x02,0x41,0x40,0x20,0x13,0x0C,0x14,0x22,0x41,0xF8,0x00};
/*-- 文字: 记 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char j1[16] = {0x40,0x40,0x42,0xCC,0x00,0x00,0x00,0x84,0x84,0x84,0x84,0x84,0xFC,0x00,0x00,0x00};
code char j2[16] = {0x00,0x00,0x00,0x7F,0x20,0x10,0x00,0x3F,0x40,0x40,0x40,0x40,0x41,0x40,0x70,0x00};
/*-- 文字: 得 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char d1[16] = {0x00,0x10,0x88,0xC4,0x33,0x00,0xBE,0xAA,0xAA,0xAA,0xAA,0xAA,0xBE,0x80,0x00,0x00};
code char d2[16] = {0x02,0x01,0x00,0xFF,0x00,0x02,0x0A,0x12,0x02,0x42,0x82,0x7F,0x02,0x02,0x02,0x00};
/*-- 文字: - --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char h1[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
code char h2[16] = {0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
/*-- 文字: 赵 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char z1[16] = {0x40,0x48,0x48,0x48,0xFF,0x48,0x48,0x00,0x04,0x08,0x30,0xC0,0x30,0x0E,0x00,0x00};
code char z2[16] = {0x80,0x60,0x1F,0x20,0x7F,0x44,0x44,0x40,0x48,0x44,0x43,0x40,0x43,0x4C,0x40,0x00};
/*-- 文字: 雷 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char l1[16] = {0x20,0x18,0x0A,0xAA,0xAA,0xAA,0x0A,0xFE,0x0A,0xAA,0xAA,0xAA,0x0A,0x28,0x18,0x00};
code char l2[16] = {0x00,0x00,0xFE,0x92,0x92,0x92,0x92,0xFE,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,0x00};
void main(){
int i = 0;
//1. OLED初始化
Oled_Init();
//2. 选择一个位置
//2.1 确认页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
Oled_Clear(); //清屏函数
//2.2 选择PAGE0 1011 0000 即 0xB0
Oled_Write_Cmd(0xB0);
Oled_Write_Cmd(0x00);//列地址选择要用两个字节
Oled_Write_Cmd(0x10);//定位到首列
for(i = 0;i < 16;i++){//显示‘xxxxx’的上半部分
Oled_Write_Data(w1[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(j1[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(d1[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(h1[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(h1[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(z1[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(l1[i]);
}
Oled_Write_Cmd(0xB1);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);//定位到首列
for(i = 0;i < 16;i++){//显示‘xxxxx’的下半部分
Oled_Write_Data(w2[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(j2[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(d2[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(h2[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(h2[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(z2[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(l2[i]);
}
while(1);//不让程序结束
}
打开画图app,画简单的图像
保存为bmp格式(未经压缩,可轻松导入取模软件而无需解压(相比于会压缩的jpg))
打开“字模提取”app,“基本操作”、“打开图像图标”
“取模方式”、“C51 格式”
code unsigned char bmpImage[] = {....128*8....
/*-- 调入了一幅图像:E:\学习\嵌入式学习\Jessie\code\Keil\19. OLED编程案例\我记得.bmp --*/
/*-- 宽度x高度=128x64 128x8(x8位)--*/};
void Oled_Show_Image(unsigned char *image){
unsigned char i;//0 到 255,char: -128 到 127,So不能用char
unsigned int j;
for(i = 0;i < 8;i++){
//PAGE0--PAGE7
Oled_Write_Cmd(0xB0 + i);
//每个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]);
}
}
}
void main(){
//1. OLED初始化
Oled_Init();
//2. 选择一个位置
//2.1 确认页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
Oled_Clear(); //清屏函数
Oled_Show_Image(bmpImage);
while(1);//不让程序结束
}