I2C总线时序,只写,有应答(oled)
I2C通讯接口由从机地址位SA0,I2C总线数据信号(SDAout/D2输出和SDAin/D1输入)和I2C总线时钟信号SCL(D0)组成。数据和时钟信号线都必须接上上拉电阻。RES#用来初始化设备。
a.从机地址位(SA0)
SSD1306在发送或接受任何信息之前必须识别从机地址。设备将会响应从机地址,后面跟着从机地址位(SA0位)和读写选择位(R/W#位),格式如下:
b7 b6 b5 b4 b3 b2 b1 b0
0 1 1 1 1 0 SA0 R/W#
SA0位为从机地址提供了一个位的拓展。 0111100或0111101都可以做为SSD1306的从机地址。D/C#引脚用作SA0用于从机地址选择。
R/W#位用来决定I2C总线接口的操作模式。R/W# = 1,读模式。R/W# = 0 写模式
b.I2C总线数据信号SDA
SDA作为发送者和接受者之间的通讯通道。数据和应答都是通过SDA发送。
应该注意的是ITO轨道电阻和SDA引脚上的上拉电阻会变成一个潜在的电压分压器。结果就是SDA上的应答可能不能达到有效的逻辑0。
SDAin和SDAout绑定到了一起作为SDA。SDAin引脚必须连接到SDA。SDAout引脚可以不连接。当SDAout引脚不连接,应答信号将会被I2C总线忽略。
c.I2C总线时钟信号SCL
I2C总线上的信息传输任务追随一个时钟信号,SCL。每个数据位的传输任务发生在SCL的单个的时钟周期中。
I2C总线接口提供了写数据和命令到设备的接口。关于I2C总线的写模式的时序请参考下图:**
写模式
1.主机设备通过开始条件初始化数据通讯。开始条件的定义在下面的图中展示。开始条件是在SCL保持高的状态下将SDA从高拉低。
2.从机地址紧跟着开始条件。对于SSD1306,从机地址可以通过改变SA0到LOW或HIGH(D/C引脚作为SA0)设成“b0111100”或“b0111101”。
3.写模式的建立是通过设置R/W#位为逻辑0实现的。
4.应答位信号在接收到一个字节的数据后生成,包括从机地址和R/W#位组成的一个字节数据。可以参考下面的应答位信号的图示。应答位的定义是在应答位相关的时钟脉冲的高周期中把SDA线拉低。
5.传输完从机地址之后,控制字节或数据字节开始通过SDA传输。一个控制字节主要由Co和D/C#位后面再加上六个0组成的。
a)如果Co为设为逻辑0,后面传输的信息就只包含数据字节。
b)D/C为决定了下个数据字节是作为命令还是数据。如果D/C#位设为0,下一个数据就是命令。如果D/C#位设为1,下一个数据就是数据,并会被存放在GDDRAM中。GDDRAM列地址(16位最高位无效)指针将会在每次数据写入之后自动加1.
6.应答位将会在接收到每个控制字节或数据字节之后生成。
7.写模式会在用了停止条件之后结束。停止条件:将SDA从低拉高,而SCL保持高。
#include "reg52.h"
#include "intrins.h"
#define high 1
#define low 0
#defing I2Cdelay() {_nop_();_nop_();_nop_();_nop_();}
/*************Pin Define***************/
sbit SCL=P1^0;
sbit SDA=P1^1;
/****************************************************/
void IIC_Start();
void IIC_Stop();
void Write_IIC_Command(unsigned char IIC_Command);
void Write_IIC_Data(unsigned char IIC_Data);
bit Write_IIC_Byte(unsigned char IIC_Byte);
/**********************************************
//IIC Start
**********************************************/
void IIC_Start()
{
SDA = high;
SCL = high;
I2Cdelay();
SDA = low;
I2Cdelay();
SCL = low;
}
/**********************************************
//IIC Stop
**********************************************/
void IIC_Stop()
{
SCL = low;
SDA = low; //首先确保SDA,SCL都是低电平
I2Cdelay();
SCL = high; //先拉高SCL
I2Cdelay();
SDA = high; //在拉高SDA
}
/**********************************************
// IIC Write byte 发送数据两种方法
第一种:
**********************************************/
bit Write_IIC_Byte(unsigned char IIC_Byte)
{
unsigned char i;
bit Ack_Bit; //应答信号
for(i=0;i<8;i++)
{
if(IIC_Byte & 0x80) //1?0?
SDA=high;
else
SDA=low;
//Delay_us(1);
SCL=high;
I2Cdelay();
SCL=low;
//Delay_us(1);
IIC_Byte<<=1; //loop
}
SDA = high; //释放IIC SDA总线为主器件接收从器件产生应答信号
I2Cdelay();
SCL = high; //第9个时钟周期
I2Cdelay();
Ack_Bit = SDA; //读取应答信号
SCL = low;
return Ack_Bit;
}
/**********************************************
// IIC Write byte 发送数据两种方法
第二种:
bit Write_IIC_Byte(unsigned char IIC_Byte)
{
unsigned char i;
bit Ack_Bit; //应答信号
for(i=0&0x80;i!=0;i>>=1) //从高位到低位依次进行
{
if((i&dat)==0) //将该位值输出到SDA上
SDA=low;
else
SDA=high;
I2Cdelay();
SCL=high; //拉高SCL
I2Cdelay();
SCL=low; //拉低SLC,完成一个位周期
}
SDA = high; //释放IIC SDA总线为主器件接收从器件产生应答信号
I2Cdelay();
SCL = high; //第9个时钟周期
I2Cdelay();
Ack_Bit = SDA; //读取应答信号
SCL = low; //拉低时钟,完成应答,并保持住总线
return Ack_Bit; //返回从机应答值
}
**********************************************/
/**********************************************
// IIC Write Command
**********************************************/
void Write_IIC_Command(unsigned char IIC_Command)
{
IIC_Start();
Write_IIC_Byte(0x78); //Slave address,SA0=0
Write_IIC_Byte(0x00); //write command
Write_IIC_Byte(IIC_Command);
IIC_Stop();
}
/**********************************************
// IIC Write Data
**********************************************/
void Write_IIC_Data(unsigned char IIC_Data)
{
IIC_Start();
Write_IIC_Byte(0x78);
Write_IIC_Byte(0x40); //write data
Write_IIC_Byte(IIC_Data);
IIC_Stop();
}