所以为什么同一IIC总线上同一型号的IC只能最多共挂8片同种类芯片的原因了
操作I2C总线,无非就是主机和丛机之间数据交换,大致分以下三种情况:
这个电路是基于LPC2368 ARM7芯片进行设计的,使用其内部的I2C接口作为主设备,使用ADT75和SC16IS740作为两个从设备的I2C总线应用。
ADT75是一个带I2C接口的温度传感器器件。 它的数据手册上说明:地址跟A0、A1、A2引脚的接法有关。
我们这里的实例是将A0、A1、A2全部接到高电平上,因此其地址是:1001111(即0x4F),又因根据协议再给地址添加一个最低位(方向位,默认给写方向),因此最后这个温度传感器作为从设备的地址是:10011110(即0x9E)。
LPC2368中有三个I2C总线接口,分别表示为I2C0、I2C1和I2C2,每个I2C接口都包含7个寄存器。它们分别是:
I2C控制置位寄存器(I2CONSET): 8位寄存器,各位不同的设置是对I2C总线不同的控制。
位
|
符号
|
描述
|
复位值
|
1:0
|
-
|
保留,用户软件不要向其写入1。从保留位读出的值未被定义 |
NA
|
2
|
AA
|
声明应答标志。为1时将为需要应答的情况产生一个应答 |
0
|
3
|
SI
|
I2C中断标志。当I2C状态改变时该位置位 |
0
|
4
|
STO
|
总线停止条件控制。1发出一个停止条件,当总线检测到停止条件时,STO自动清零
|
0
|
5
|
STA
|
总线起始条件控制。1进入主模式并发出一个起始条件
|
0
|
6
|
I2EN
|
总线使能控制。1为使能 |
0
|
7
|
-
|
保留,用户软件不要向其写入1。从保留位读出的值未被定义 |
NA
|
I2C控制清零寄存器(I2CONCLR): 8位寄存器,对I2CONSET寄存器中的相应为清零。
位
|
符号
|
描述
|
复位值
|
1:0
|
-
|
保留,用户软件不要向其写入1。从保留位读出的值未被定义 |
NA
|
2
|
AAC
|
声明应答标志清零位。向该位写入1清零I2CONSET寄存器中的AA位 |
0
|
3
|
SIC
|
中断标志清零位。向该位写入1清零I2CONSET寄存器中的SI位 |
0
|
4
|
-
|
保留,用户软件不要向其写入1。从保留位读出的值未被定义 |
NA
|
5
|
STAC
|
起始条件清零位。向该位写入1清零I2CONSET寄存器中的STA位 |
0
|
6
|
I2ENC
|
总线禁能控制。写入1清零I2CONSET寄存器中的I2EN位 |
0
|
7
|
-
|
保留,用户软件不要向其写入1。从保留位读出的值未被定义 |
NA
|
I2C状态寄存器(I2STAT): 8位只读寄存器,用于监控总线的实时状态(可能存在26种状态)。
位
|
符号
|
描述
|
复位值
|
2:0
|
-
|
这3个位不使用且总是为0 |
0
|
7:3
|
Status
|
这些位给出I2C接口的实时状态,不同的值代表不同的状态,状态码请参考数据手册 |
0x1F
|
I2C数据寄存器(I2DAT): 8位寄存器,在SI置位期间,I2DAT中的数据保持稳定。
位
|
符号
|
描述
|
复位值
|
7:0
|
Data
|
该寄存器保留已经接收到或者准备要发送的数据值
|
0
|
I2C从地址寄存器(I2ADR): 8位寄存器,I2C总线为从模式时才使用。主模式中该寄存器无效。
位
|
符号
|
描述
|
复位值
|
0
|
GC
|
通用调用使能位
|
0
|
7:1
|
Address
|
从模式的I2C器件地址 |
0x00
|
SCH占空比寄存器(I2SCLH): 16位寄存器,用于定义SCL高电平所保持的PCLK周期数。
位
|
符号
|
描述
|
复位值
|
15:0
|
SCLH
|
SCL高电平周期选择计数 |
0x0004
|
SCL占空比寄存器(I2SCLL): 16位寄存器,用于定义SCL低电平所保持的PCLK周期数。
位
|
符号
|
描述
|
复位值
|
15:0
|
SCLL
|
SCL低电平周期选择计数 |
0x0004
|
0x08:
表明主设备向总线已发出了一个起始条件;
0x10: 表明主设备向总线已发出了一个重复的起始条件;
0x18: 表明主设备向总线已发送了一个从设备地址(写方向)并且接收到从设备的应答;
0x20: 表明主设备向总线已发送了一个从设备地址(写方向)并且接收到从设备的非应答;
0x28: 表明主设备向总线已发送了一个数据字节并且接收到从设备的应答;
0x30: 表明主设备向总线已发送了一个数据字节并且接收到从设备的非应答;
0x40: 表明主设备向总线已发送了一个从设备地址(读方向)并且接收到从设备的应答;
0x48: 表明主设备向总线已发送了一个从设备地址(读方向)并且接收到从设备的非应答;
0x50: 表明主设备从总线上已接收一个数据字节并且返回了应答;
0x58: 表明主设备从总线上已接收一个数据字节并且返回了非应答;
例1:轮询方式:
#define SC16IS740_ADDR
0x92
#define ADT75A_ADDR
0x9E
#define ADT75A_TEMP
0x00
#define CHANNEL_GPRS
0
#define CHANNEL_TEMPERATURE
1
#define BIT(x) (1 <</SPAN><</SPAN> x)
#define I2C_EN
BIT(6)
#define I2C_STA
BIT(5)
#define I2C_STO
BIT(4)
#define I2C_SI
BIT(3)
#define I2C_AA
BIT(2)
#define SAFETY_COUNTER_LIMIT
3000
void I2C0_Init(void)
{
PINSEL0 |= (0x03 <</SPAN><</SPAN> 0) | (0x03 <</SPAN><</SPAN> 2);
PCONP |= (0x01 <</SPAN><</SPAN> 7 );
I20CONCLR = (0x01 <</SPAN><</SPAN> 2) | (0x01 <</SPAN><</SPAN> 3) | (0x01 <</SPAN><</SPAN> 5) | (0x01 <</SPAN><</SPAN> 6);
I20CONSET = (0x01 <</SPAN><</SPAN> 6);
I20SCLH = 0x5A;
I20SCLL = 0x5A;
}
BOOL I2C0_ReadRegister(uint32
channel, uint8
registerAddress, uint8 *pData)
{
uint32 loopSafetyCounter = 0;
uint32 addressSendSafetyCounter = 0;
do
{
I20CONSET = I2C_STA | I2C_SI;
I20CONCLR = I2C_SI;
loopSafetyCounter = 0;
while (~I20CONSET & I2C_SI)
{
loopSafetyCounter ++;
if (loopSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
}
if(channel == CHANNEL_GPRS)
I20DAT = SC16IS740_ADDR;
else if(channel == CHANNEL_TEMPERATURE)
I20DAT = ADT75A_ADDR;
I20CONCLR = I2C_STA | I2C_SI;
loopSafetyCounter = 0;
while (~I20CONSET & I2C_SI)
{
loopSafetyCounter ++;
if (loopSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
}
addressSendSafetyCounter ++;
if (addressSendSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
} while (I20STAT != 0x18);
I20DAT = registerAddress <</SPAN><</SPAN> 3;
I20CONCLR = I2C_SI;
loopSafetyCounter = 0;
while (~I20CONSET & I2C_SI)
{
loopSafetyCounter ++;
if (loopSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
}
I20CONSET = I2C_STA | I2C_SI;
I20CONCLR = I2C_SI;
loopSafetyCounter = 0;
while (~I20CONSET & I2C_SI)
{
loopSafetyCounter ++;
if (loopSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
}
if(channel == CHANNEL_GPRS)
I20DAT = SC16IS740_ADDR | 0x01;
else if(channel == CHANNEL_TEMPERATURE)
I20DAT = ADT75A_ADDR | 0x01;
I20CONCLR = I2C_STA | I2C_SI;
loopSafetyCounter = 0;
while (~I20CONSET & I2C_SI)
{
loopSafetyCounter ++;
if (loopSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
}
I20CONCLR = I2C_SI | I2C_AA;
loopSafetyCounter = 0;
while (~I20CONSET & I2C_SI)
{
loopSafetyCounter ++;
if (loopSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
}
*pData = I20DAT;
I20CONSET = I2C_STO;
I20CONCLR = I2C_SI;
loopSafetyCounter = 0;
while (I20CONSET & I2C_STO)
{
loopSafetyCounter ++;
if (loopSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
}
return TRUE;
}
BOOL I2C0_WriteRegister(uint32
channel, uint8
registerAddress, uint8
data)
{
uint32 loopSafetyCounter = 0;
uint32 addressSendSafetyCounter = 0;
do
{
I20CONSET = I2C_STA | I2C_SI;
I20CONCLR = I2C_SI;
loopSafetyCounter = 0;
while (~I20CONSET & I2C_SI)
{
loopSafetyCounter ++;
if (loopSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
}
if(channel == CHANNEL_GPRS)
I20DAT = SC16IS740_ADDR;
else if(channel == CHANNEL_TEMPERATURE)
I20DAT = ADT75A_ADDR;
I20CONCLR = I2C_STA | I2C_SI;
loopSafetyCounter = 0;
while (~I20CONSET & I2C_SI)
{
loopSafetyCounter ++;
if (loopSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
}
addressSendSafetyCounter ++;
if (addressSendSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
} while (I20STAT != 0x18);
I20DAT = registerAddress <</SPAN><</SPAN> 3;
I20CONCLR = I2C_SI;
loopSafetyCounter = 0;
while (~I20CONSET & I2C_SI)
{
loopSafetyCounter ++;
if (loopSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
}
I20DAT = data;
I20CONCLR = I2C_SI;
loopSafetyCounter = 0;
while (~I20CONSET & I2C_SI)
{
loopSafetyCounter ++;
if (loopSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
}
I20CONSET = I2C_STO;
I20CONCLR = I2C_SI;
loopSafetyCounter = 0;
while (I20CONSET & I2C_STO)
{
loopSafetyCounter ++;
if (loopSafetyCounter > SAFETY_COUNTER_LIMIT)
{
return FALSE;
}
}
return TRUE;
}