一些细节上的东西容易忘记,其实貌似也不需要记那么多,需要用的时候调用就可以了;
不过还是记一下吧,以后可能会看。
在看源代码的时候发现I2C函数里面有一些不懂,搜了一下发现是时序协议不清楚。
ref@http://www.cnblogs.com/BitArt/archive/2013/05/28/3103917.html
- 空闲状态:
SDA和SCL都为高电平。
此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
所以,在传输完一个Byte之后:
//if SDA==SCL==1,I2C is free
BS004_I2C_SDA_1; //free I2C
BS004_I2C_NOP;
BS004_I2C_SCL_1;
BS004_I2C_NOP;
- 每次传输一个bit,时钟总线SCL都需要跳变一下
这个跟数电里面差不多吧,数据要跟着时钟走。时钟就是脉搏,就是节拍器。
并且数据的跳变也是有要求的:
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定;
只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
所以要人为的做这个跳变:
for(i=0;i<8;i++)
{
if(bs004_i2c_data&0x80) BS004_I2C_SDA_1; //set bit
else BS004_I2C_SDA_0;
//
bs004_i2c_data<<=1;
BS004_I2C_NOP;
//
BS004_I2C_SCL_1; //why do we do this?
BS004_I2C_NOP;
BS004_I2C_SCL_0;
BS004_I2C_NOP;
}
- ACK应答
应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。
- 协议
在发送start信号之后,我们需要发送器件的地址+读/写 信号
不过如果我们要写的地址不是器件的起始地址呢?我们在后面再发送一个偏移量。
虽然这一点并没有在标准的协议中看见,但是有人这么使用:
1、主机向所要访问的设备发送一个起始信号,标志着I2C通信开始,同时主机把设备地址和“写”操作命令发出,若操作成功,设备会发送一个应答信号。
2、在随机“写”操作的时候,一般发送的第一个数据作为偏移地址。在偏移地址发送成功后,设备会送发一个应答信号。同时产生一个中断,中断处理程序把刚得到的偏移地址保存起来。
3、主机向所要访问的设备再次发送一个起始信号,同时主机把设备地址和“读”操作命令发出,此时设备产生一个中断,中断处理程序把刚刚保存起来的偏移地址寻址,把需要发送的数据得到。操作成功后,发送一个应答信号,标志着准备发送数据给上位机。
4、在设备发送一个应答信号之后,产生一个中断信号,把刚刚准备好发送数据发送出去