IIC
标签:
1、标准速率:100kbit/s、快速:400kbit/s、高速:4Mbit/s
2、2线通信协议
3、起始与停止:SCL高时,SDA由 高 --> 低(↓) 变化,起始信号;SDA由 低 --> 高(↑) 变化,停止信号
4、空闲状态:SDA和SCL都处于高电平状态
5、数据传输与应答:数据必须是8位,且高位在前(MSB),第9个脉冲周期由接收方发送应答信号(发送方同时等待这个应答信号),即接收方将SDA拉低(之前SDA为高)。(有时会将应答超时视作已接受到正确数据,有的地方则必须等待到应答信号,下面的例中就是后者)。
6、地址格式:7-4bit为器件类型,半导体公司生产时就已经固定了。3-1bit为器件地址位,一般用户自定义,例如EEPROM外部的3个引脚(A0,A1,A2)硬件电路的接法决定了其数值,所以一路IIC总线上同一型号的IC最多能接8个。最后一位就是R/W标记位了,0为写命令,1为读命令。
7、IIC总线进行数据传输时,SCL为高电平时SDA必须保持稳定才有效,只有SCL为低电平时才允许SDA有变化。
8、PHILIPS(飞利浦)开发
9、双向串行总线协议
C语言实现过程(基于摄像头NT99141控制协议的IIC通信实例)
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define Delay( n)
//以下为伪定义,实际以芯片IO口配置为主
#define SET_SDA_OUT( )
#define SDA_OUT( )
#define SDA_H( )
#defien SDA_L( )
#define SET_SDA_IN( )
#defien SDA_IN( )
#defien SCL_H( )
#define SCL_L( )
#define delay( )
typedef u8 unsigned char;
void Start(void)
{
SDA_H( );
delay()
SCL_H;
delay( ); //SCL为高 SDA变低 ↓,起始信号
SDA_L( );
delay( );
SDA_L( );
delay( );
}
void Stop(void)
{
SCL_L( );
delay( );
SDA_L( );
delay( );
SCL_H( );
delay( );//SCL为高 SDA变高↑,停止信号
SDA_H( );
delay( );
}
u8 WaitAck(void)
{
u8 tmp = 200;
SDA_H( );delay( );//拉高,等待应答被拉低
SET_SDA_IN( );delay( );
SCL_H( );delay( );
while(SDA_IN( ))
{
if(--tmp == 0)
{
Stop( );
return 0;
}
}
SCL_L( );
return 1;
}
void Ack(void)
{
SCL_L( );
delay( );
SDA_L( );//应答,拉低
delay( );
SCL_H( );
delay( );
SCL_L( );
delay( );
}
void NoAck(void)
{
SCL_L( );
delay( );
SDA_H( );
delay( );
SCL_H( );
delay( );
SCL_L( );
delay( );
}
u8 WriteByte(u8 data)
{
u8 i,ret = 0;
SCL_L( );
delay( );
for(i = 0 ; i < 8 ; i++)
{
if(data & 0x80)
{
SDA_H( );
}
else
{
SDA_L( );
}
data <<= 1;
delay( );
SCL_H( );
delay( );
SCL_L( );
delay( );
}
delay( );
ret = WaitAck( );//发送完一个字节后等待对方发送应答信号
SET_SDA_OUT( );
return (ret);//返回应答状态,为0证明应答失败,为1应答正常
}
u8 ReadByte(void)
{
u8 i,data = 0;
SET_SDA_IN;//需要设置SDA为输入以及是否上拉
delay( );
for(i = 0; i < 8 ; i++)
{
SCL_L( );
delay( );
SCL_H( );
delay( );
data <<= 1;
if(SDA_IN) //此处直接读取SDA的状态
{
data += 1;
}
}
return data;
}
u8 WriteAddr(ADDR_T addr,u8 data)
{
u8 tmp = 0;
Start( );
if(0 == WriteByte(WCMD))goto _return;//发送写命令,本例中必须等到应答信号,否则认为丛机接收失败
//Delay(10);//选择性延时
if(0 == WriteByte(addr))goto _return;//发送写地址
//Delay(10);//选择性延时
if(0 == WriteByte(data))goto _return;//发送数据
tmp = 1;
_return:
Stop( );
return tmp;
}
u8 ReadAddr(u8 addr,u8 *data)
{
u8 tmp = 0;
Start( );
if(0 == WriteByte(WCMD))goto _return;//发送写命令
//Delay(10);//选择性延时
if(0 == WriteByte(addr))goto _return;//发送读地址
Stop( );
//Delay(10);//选择性延时
Start( );
if(0 == WriteByte(RCMD))goto _return;//发送读命令
//Delay(10);//选择性延时
*data = ReadByte( ); //读数据
_return:
Stop( );
return tmp;
}