IIC协议
-
IIC协议概述
IIC全称Inter-Integrated Circuit (集成电路总线)是由PHILIPS公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备。IIC属于半双工同步通信方式。
-
特点
-
简单性和有效性
由于接口直接在组件之上,因此IIC总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件。
-
多主控(multimastering)
其中任何能够进行发送和接收的设备都可以成为主总线。一个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主控。
-
-
构成
IIC串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL,其时钟信号是由主控器件产生。所有接到IIC总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。对于并联在一条总线上的每个IC都有唯一的地址。
-
IIC协议
IIC总线在传输数据的过程中一共有三种类型信号,分别为:开始信号、结束信号和应答信号。
起始位,停止位,数据位,速度。
这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。
初始(空闲)状态
因为IIC的 SCL 和SDA 都需要接上拉电阻,保证空闲状态的稳定性;
所以IIC总线在空闲状态下SCL 和SDA都保持高电平。
void IIC_init()//IIC协议初始化,全部拉高 { scl = 1; _nop_(); sda = 1; _nop_(); }
开始信号:
//产生IIC起始信号 //1.先拉高SDA,再拉高SCL,空闲状态 //2.拉低SDA void IIC_Start() //启动信号 { sda=1; //确保SDA线为高电平 _nop_(); scl=1; //确保SCL高电平 _nop_(); sda=0; //在SCL为高时拉低SDA线,即为起始信号 _nop_(); scl=0; //钳住I2C总线,准备发送或接收数据 }
停止信号:
//产生IIC停止信号 //1.先拉低SDA,再拉低SCL //2.拉高SCL //3.拉高SDA //4.停止接收数据 void IIC_Stop(void) { scl = 1; sda = 0; //STOP:当SCL高时,数据由低变高 _nop_(); sda = 1; //发送I2C总线结束信号 _nop_(); }
在起始条件产生后,总线处于忙状态,由本次数据传输的主从设备独占,其他I2C器件无法访问总线;而在停止条件产生后,本次数据传输的主从设备将释放总线,总线再次处于空闲状态。
-
应答信号
每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据。
应答信号:主机SCL拉高,读取从机SDA的电平,为低电平表示产生应答
应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;
应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
-
数据发送的时序
SDA线上的数据在SCL时钟“高”期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的“高”或“低”状态才可以改变。输出到SDA线上的每个字节必须是8位,数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。
当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位ACK, 此时才认为一个字节真正的被传输完成 ,如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。
void IIC_send_byte(char data_send) { int i; for(i=0;i<8;i++){ scl = 0;//拉低,才可以进行sda的变化 sda = data_send & 0x80;//将字节的最高位给sda _nop_();//延时 scl = 1;//拉高开始发送 _nop_();//给数据发送的时间 data_send << 1;//字节数据左移一位 } }
OLED
OLED,即有机发光二极管( Organic Light Emitting Diode )。OLED由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。
Oled的IIC协议
!
-
从属地址(Slave Address)格式为:b0111 10(SA0)(RW#)
SA0:0或1可以分别代表两个oled
RW#:0代表设置为写入模式
∴Slave Address:0x78
-
Control Byte:(Co)(D/C)000000
Co为0
D/C为0写入命令:0x00;
D/C为1写入数据:0x70;
写命令/数据的代码:
/*
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 data_cmd)
{
//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(data_cmd);
//7. ACK
IIC_ack();
//8. STOP
IIC_stop();
}
void Oled_Write_Data(char data_data)
{
//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(data_data);
//7. ACK
IIC_ack();
//8. STOP
IIC_stop();
}
最为常见的GDDRAM寻址模式——页模式
GDDRAM是位映射静态RAM,大小为 128x64 位。GDDRAM分为8页(PAGE0~PAGE7),每页内 1个SEG对应1Byte数据,一页由 128 Byte 组成。一帧显示数据为 1024 Byte(1KB)。**即屏幕每8行像素点(8PIXEL)记为一页(PAGE),64行即为8页,则屏幕变为128列(ROW)8页(PAGE),**若要显示整个屏幕,则需要1288个1字节数。
页寻址模式下,寻址只在一页(PAGEn)内进行,地址指针不会跳到其他页。每次向GDDRAM写入1byte显示数据后,列指针会自动+1。**当128列都寻址完之后,列指针会重新指向SEG0而页指针仍然保持不变。**通过页寻址模式我们可以方便地对一个小区域内数据进行修改。
设置页寻址模式
配置成页寻址模式需要两条指令
Oled_Write_Cmd(0x20);//Set Memory
Oled_Write_Cmd(0x02);//页寻址模式
页地址选择
页地址为:1011 0xxx
Oled_Write_Cmd(0xB0);//第一页
确定列的位置
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);//第1列
Oled_Write_Cmd(0x0F);
Oled_Write_Cmd(0x17);//第128列
代码:显示一个点
void main()
{
IIC_init();//IIC初始化
Oled_Init();//OLED初始化
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);//确认页寻址模式
Oled_Clear();//清屏函数
Oled_Write_Cmd(0xB0);//选择PAGE0 1011 0000
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);//第0列
Oled_Write_Data(0x08);//显示一个点
while(1);
}
代码:显示一个A
/*-- 文字: 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;
IIC_init();//IIC初始化
Oled_Init();//OLED初始化
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);//确认页寻址模式
Oled_Clear();//清屏函数
//选择PAGE0 1011 0000 0xB0 第0列
Oled_Write_Cmd(0xB0);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i=0;i<8;i++){
Oled_Write_Data(A1[i]);
}
//选择PAGE1 1011 0001 0xB1 第0列
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);
}
代码:实现一个图片
/*-- 调入了一幅图像:D:\Desktop\比奇堡图像.bmp --*/
/*-- 宽度x高度=128x64 --*/
code unsigned char image[]={
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x18,0x10,0xD0,0xD0,0xF0,0x1E,0x13,0x18,0x08,0x08,0x08,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x80,0x80,0xC0,0x70,0x38,0xEF,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x7F,0x40,0xC0,0x41,0x41,0x61,0x3B,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,0x01,0x1F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,
0x20,0x38,0x28,0x2C,0x26,0x23,0x21,0x20,0x21,0x23,0x26,0x24,0x2C,0x28,0x28,0xA0,
0xE0,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x10,0x10,0x00,0x00,0x00,0x00,0x00,
0x04,0x06,0x02,0x03,0x01,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x04,
0x04,0x04,0x84,0xC4,0x64,0x34,0xFF,0x24,0x64,0xC4,0x84,0x04,0x04,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xFC,0x47,0x40,0x40,0x40,0x60,0x20,0x20,0x20,0x20,0x20,
0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x80,0xC0,0x70,0x18,0x0C,0x06,0x02,0x03,0x01,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xFE,0x04,0x04,0x04,0x04,0x04,0x0C,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
0x00,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,0x00,0x00,0x00,0x00,0x00,0x04,
0x06,0x83,0x01,0x00,0x00,0x0F,0x01,0x00,0x00,0x00,0x01,0x03,0x02,0x06,0x0C,0x08,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,
0x1F,0x10,0x10,0x10,0x10,0x18,0x08,0x0C,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x10,0x11,0xFF,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x7F,0x40,0x60,0x20,0x30,0x10,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x78,0x60,0x20,0x30,0x10,0x18,0x08,0x0C,0x04,
0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xE0,0x3C,
0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x03,0x03,0x06,0x04,0x04,0x04,0x06,0x06,0x03,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x02,0x02,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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 int i,j;
for(i=0;i<8;i++){
Oled_Write_Cmd(0xB0 + i);//page
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);//从第0列开始
for(j=(128 * i);j<(128 *( i+1));j++){
Oled_Write_Data(image[j]);
}
}
}
void main()
{
IIC_init();//IIC初始化
Oled_Init();//OLED初始化
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);//确认页寻址模式
Oled_Clear();//清屏函数
Oled_show_image(image);//显示图片
while(1);
}