本帖最后由 thammer 于 2015-3-27 20:03 编辑
主从机都是KL16,从机以中断方式接收,中断服务程序如下:extern uint8_t Rx_Count,Tx_Count;
extern uint8_t I2C0_RxBuf[I2C0_ReceBufSize];
extern uint8_t I2C0_TxBuf[I2C0_ReceBufSize];
void I2C0_IRQHandler(void)
{
// uint8_t u8_Resigter;
static uint8_t u8_SlaverMOde = 0;
//u8_Resigter = I2C0_S;
/*-----------------地址匹配事件-----------------------------*/
// if(((u8_Resigter & I2C_S_IAAS_MASK)!=0)||((u8_Resigter & I2C_S_RAM_MASK)!=0))//从机地址匹配--寄存器I2C_C1写入任何值清零--设置模式中已经相当清零(I2C_C1写入一次)
// {
// //u8_ReadAddress = I2C0_D;//读取从机地址
// }
printf("I2C int \r\n");
/*-----------------停止事件----------------------------*/
if((I2C0->FLT & I2C_FLT_STOPF_MASK)!=0)
{
I2C0->FLT |= I2C_FLT_STOPF_MASK;//写1 清零 停止位标志清零,需要先清零stopf,再清零IICIF
I2C0->S |= (1 << 1); // I2C_S_IICIF_MASK--清零中断标志
I2C0->C1 &= ~(1 << 3); //I2C_C1_TXAK_MASK 返回非应答
printf("I2C stop event \r\n");
}
I2C0->S |= (1 << 1); // I2C_S_IICIF_MASK--清中断标志
/*-----------------Arbitration Lost事件----------------------------*/
if((I2C0->S & I2C_S_ARBL_MASK)!=0)
{
I2C0->S |= I2C_S_ARBL_MASK;//写1清零 清除ARBL
printf("I2C ARBL \r\n");
if (!(I2C0->S & I2C_S_IAAS_MASK)) //如果地址不是从机地址,跳出
{ /* IAAS 非 1 */
return;
}
}
/*-----------------从机接收处理 ----------------------------*/
if ((I2C0->S & I2C_S_IAAS_MASK)==I2C_S_IAAS_MASK) //地址匹配事件
{
printf("I2C Address \r\n");
if((I2C0->S & I2C_S_SRW_MASK)!=0)//从机发送模式
{
printf("I2C Tx \r\n");
i2c0_Put_Tx_Mode;
u8_SlaverMOde = 0;//从发送
I2C0->D = 0x23;//I2C0_TxBuf[Tx_Count++];//从机发送数据
}
else //从机接收模式
{
printf("I2C Rx \r\n");
i2c0_Put_Rx_Mode;
u8_SlaverMOde = 1;//从接收
if (I2C0->D); //读一次
}
}
else
{
printf("I2C dataing \r\n");
switch (u8_SlaverMOde)
{
case 0://从发送
printf("I2C Send \r\n");
if (I2C0->S & 0x01 ) //从机发送 主机ACK应答失败 停止发送
{/* 应答检测 */
/* 主机应答失败,停止发送 */
I2C0->C1 &= ~(1 << 4); //设置为接收模式 /* 接收模式 */
if (I2C0->D) ; /* 读一次 */
printf("I2C ACK error \r\n");
}
else //从机发送 主机ACK应答成功
{
#if 0
if(Tx_Count<I2C0_ReceBufSize) /* 发送其他数据 */
{
I2C0->D = I2C0_TxBuf[Tx_Count++];
printf("send Data:%p\r\n",I2C0_TxBuf[Tx_Count]);
}
else
{
Tx_Count = 0;
I2C0->D = I2C0_TxBuf[Tx_Count++];
}
#else
I2C0->D = 0x12;
#endif
}
break;
case 1://从接收
printf("I2C Rece \r\n");
if(Rx_Count<I2C0_ReceBufSize)
{
I2C0_RxBuf[Rx_Count++]=I2C0->D;
}
else
{
Rx_Count = 0;
I2C0_RxBuf[Rx_Count++]=I2C0->D;
}
printf("%p\r\n",I2C0_RxBuf[0]);
break;
default :
printf("I2C defalut \r\n");
i2c0_Put_Rx_Mode; /* 接收模式 */
if(I2C0->D) ; /* 读一次 */
break;
}
}
//I2C0_S |= I2C_S_IICIF_MASK;//写1 清零
}
主机能正确读到第一次的数据0x23,之后SCL,SDA被拉低。错误发生在:
if (I2C0->S & 0x01 ) //从机发送 主机ACK应答失败 停止发送
{/* 应答检测 */
/* 主机应答失败,停止发送 */
I2C0->C1 &= ~(1 << 4); //设置为接收模式 /* 接收模式 */
if (I2C0->D) ; /* 读一次 */
printf("I2C ACK error \r\n");
}
从机接收流程:
地址匹配中断-->切换为接收模式--->接收数据--->地址匹配中断--->切换为发送模式紧跟着发送第一个字节---->接收到停止中断,非应答,从机一个字节发送完成
但是看打印实际跑的流程是:
地址匹配中断-->切换为接收模式--->接收数据--->地址匹配中断--->切换为发送模式紧跟着发送第一个字节---->(未收到停止中断)准备发送第二个字节前检测到主机对第一一个字节无应答,卡死。
这里,应该不是主机没应答,而是SCL,SDA被从机拉死。请问这是什么原因?
下面是主机发送程序:
unsigned char I2C0_ReadRegister(unsigned char SlaveID,unsigned char u8RegisterAddress)
{
unsigned char result;
//unsigned char SlaveID;
uint8_t I2C_Temp;
/* Send Slave Address */
I2C0_StartTransmission(SlaveID,MWSR);
i2c0_Wait;
/* Write Register Address */
I2C0->D = u8RegisterAddress;
i2c0_Wait;
/* Do a repeated start */
I2C0->C1 |= I2C_C1_RSTA_MASK;
/* Send Slave Address */
//I2C0->D = ((unsigned char) (ACCEL_I2C_ADDRESS << 1)|0x01); //read address
I2C0->D = (unsigned char) (SlaveID|0x01); //read address
i2c0_Wait;
/* Put in Rx Mode */
I2C0->C1 &= (~I2C_C1_TX_MASK);
/* Turn off ACK since this is second to last byte being read*/
I2C0->C1 |= I2C_C1_TXAK_MASK;
/* Dummy read */
result = I2C0->D ;
I2C_Temp = result;
i2c0_Wait;
/* Send stop since about to read last byte */
i2c0_Stop;
/* Read byte */
result = I2C0->D ;
I2C_Temp = result;
return I2C_Temp;
}
|