这几天在看IIC的协议以及周立功的一些例程,程序中有些问题总是不能理解,应该是我对协议没有吃透,所以这里提出来,希望能够得到解答(中断处理程序中的):
void __irq IRQ_I2C0(void)
{
switch (I2STAT & 0xF8) /* 读取I2C状态寄存器I2DAT */
{
case 0x08: /* 已发送起始条件,主发送和主接收都有 */
{ /* 装入SLA+W或者SLA+R */
if(I2C_suba_en == 1) /* SLA+R,指定子地址读 */
{
I2DAT = I2C_sla & 0xFE; /* 先写入地址 */
}
else /* SLA+W */
{
I2DAT = I2C_sla; /* 否则直接发送从机地址 */
}
/* 清零SI位 */
I2CONCLR = (1 << 3)| /* SI */
(1 << 5); /* STA */
}
break;
case 0x10: /*已发送重复起始条件,主发送和主接收都有 */
{ /* 装入SLA+W或者SLA+R */
I2DAT = I2C_sla; /* 重起总线后,重发从地址*/
I2CONCLR = 0x28; /* 清零SI,STA */
}
break;
case 0x18:
case 0x28: /* 已发送I2DAT中的数据,已接收ACK */
{
if (I2C_suba_en == 0)
{
if (I2C_num > 0)
{ I2DAT = *I2C_buf++;
I2CONCLR = 0x28; /* 清零SI,STA */
I2C_num--;
}
else /* 没有数据发送了 */
{ /* 停止总线 */
I2CONSET = (1 << 4); /* STO */
I2CONCLR = 0x28; /* 清零SI,STA */
I2C_end = 1; /* 总线已经停止 */
}
}
if(I2C_suba_en == 1) /* 若是指定地址读,则重新启动总线 */
{
if (I2C_suba_num == 2)
{
I2DAT = ((I2C_suba >> 8) & 0xff);
I2CONCLR = 0x28; /* 清零SI,STA */
I2C_suba_num--;
break;
}
if(I2C_suba_num == 1)
{ I2DAT = (I2C_suba & 0xff);
I2CONCLR = 0x28; /* 清零SI,STA */
I2C_suba_num--;
break;
}
if (I2C_suba_num == 0)
{ I2CONSET = 0x20;
I2CONCLR = 0x08;
I2C_suba_en = 0; /* 子地址己处理 */
break;
}
}
if (I2C_suba_en == 2) /* 指定子地址写,子地址尚未指定,则发送子地址 */
{
if (I2C_suba_num > 0)
{
if (I2C_suba_num == 2)
{ I2DAT = ((I2C_suba >> 8) & 0xff);
I2CONCLR = 0x28;
I2C_suba_num--;
break;
}
if (I2C_suba_num == 1)
{
I2DAT = (I2C_suba & 0xff);
I2CONCLR = 0x28;
I2C_suba_num--;
I2C_suba_en = 0;
break;
}
}
}
}
break;
case 0x40: /* 已发送SLA+R,已接收ACK */
{
if (I2C_num <= 1) /* 如果是最后一个字节 */
{
I2CONCLR = 1 << 2; /* 下次发送非应答信号 */
}
else
{
I2CONSET = 1 << 2; /* 下次发送应答信号 */
}
I2CONCLR = 0x28; /* 清零SI,STA */
}
break;
case 0x20: /* 已发送SLA+W,已接收非应答 */
case 0x30: /* 已发送I2DAT中的数据,已接收非应答 */
case 0x38: /* 在SLA+R/W或数据字节中丢失仲裁 */
case 0x48: /* 已发送SLA+R,已接收非应答 */
{
I2CONCLR = 0x28;
I2C_end = 0xFF;
}
break;
case 0x50: /* 已接收数据字节,已返回ACK */
{
*I2C_buf++ = I2DAT;
I2C_num--;
if (I2C_num == 1) /* 接收最后一个字节 */
{ I2CONCLR = 0x2C; /* STA,SI,AA = 0 */
}
else
{ I2CONSET = 0x04; /* AA=1 */
I2CONCLR = 0x28;
}
}
break;
case 0x58: /* 已接收数据字节,已返回非应答 */
{
*I2C_buf++ = I2DAT; /* 读取最后一字节数据 */
I2CONSET = 0x10; /* 结束总线 */
I2CONCLR = 0x28;
I2C_end = 1;
}
break;
default:
break;
}
VICVectAddr = 0x00; /* 中断处理结束 */
}
Question1:当状态为40H时(已经发送SLA+R),程序判断是否是最后一个字节,然后判断下次是发送应答信号还是非应答信号,所以我想问,为什么在发送完SLA+W时没有这个判断过程。
Question2:关于状态30与状态58----为什么已发送I2DAT中的数据,已接受非应答信号(30H)这个状态就是属于总线出错,而已接受数据字节,已返回非应答信号(58H)这个状态就是代表是最后一个字节,结束总线。 |