程序如下,上位机从2号寄存器开始读取5个字节。
bit isda; //设备地址标志
bit isma; //存储地址标志
unsigned char AddrSend;
unsigned char AddrRev;
unsigned char pdata BufferSend[10];
unsigned char pdata BufferRev[10];
void I2C_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //结构定义
GPIO_InitStructure.Pin = GPIO_Pin_4 | GPIO_Pin_5; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P2,&GPIO_InitStructure); //初始化
P_SW2 |= 0x80;
//P_SW2 |= 0x00; //SDA/P1.4下降沿唤醒
P_SW2 |= 0x10; //SDA_2/P2.4下降沿唤醒
//P_SW2 |= 0x30; //SDA_4/P3.3下降沿唤醒
I2CCFG = 0x80; //使能I2C从机模式
I2CSLADR = 0x28; //设置从机设备地址寄存器I2CSLADR=0101_1010B
//即I2CSLADR[7:1]=010_1101B,MA=0B。
//由于MA为0,主机发送的的设备地址必须与
//I2CSLADR[7:1]相同才能访问此I2C从机设备。
//主机若需要写数据则要发送5AH(0101_1010B)
//主机若需要读数据则要发送5BH(0101_1011B)
I2CSLST = 0x00;
I2CSLCR = 0x78; //使能从机模式中断
EA = 1;
isda = 1; //用户变量初始化
isma = 1;
AddrSend = 0;
AddrRev =0;
//当发送寄存器的第一个要发送的数据最高位为1时可以被上位机正常读取,从第二个字节开始,如果最高位为1,将直接触发停止条件,之后的数据无法读取。
//如果所有字节的最高位都不为1,则全部可以正常读取。
BufferSend[0] =0x81;
BufferSend[1] =0x82;
BufferSend[2] =0x83;
BufferSend[3] =0x84;
BufferSend[4] =0x85;
BufferSend[5] =0x86;
BufferSend[6] =0x87;
BufferSend[7] =0x88;
BufferSend[8] =0x89;
BufferSend[9] =0x90;
I2CTXD = BufferSend[AddrSend];
}
//=======================================================================================================================================================================
void I2C_Isr() interrupt 24
{
push(P_SW2); //将 切换控制寄存器 进栈处理
P_SW2 |= 0x80;
if(I2CSLST & 0x40) //收到开始信号
{
I2CSLST &= ~0x40; //处理START事件,开始信号清零 STAIF 位清零
}
else if(I2CSLST & 0x20) //从机模式时接收到 1 字节的数据后的中断请求位
{
I2CSLST &= ~0x20; //处理RECV事件,1 字节的数据 RXIF 位清零
if(isda) //设备地址,第一个字节是设备地址
{
isda = 0; //处理RECV事件(RECV DEVICE ADDR)
//deviceID_addr = I2CRXD;
}
else if(isma) //寄存器地址,第二个字节为寄存器地址
{
isma = 0; //处理RECV事件(RECV MEMORY ADDR)
AddrSend = I2CRXD;
I2CTXD = BufferSend[AddrSend];
//memory_addr = I2CRXD;
//IICdata_addr =0;
} //由于初始化的时候,IIC接收所有设备地址 ,不过从这里可继续添加 else if 语句进行判断特点指令
else //数据1 和 数据2
{
BufferRev[AddrRev++] = I2CRXD; //处理RECV事件(RECV DATA)
//if(IICdata_addr >= 2) IICdata_addr = 0;
//I2C_Buffer[IICdata_addr++] = I2CRXD; //处理 RECV 事件(数据1 和 数据2)
}
}
else if(I2CSLST & 0x10) //从机模式时发送完成 1 字节的数据后的中断请求位
{
I2CSLST &= ~0x10; //处理SEND事件,从机模式时发送完成1字节的数据后的中断请求位
if (I2CSLST & 0x02) //从机模式时,接收到的 ACK 数据
{
I2CTXD = 0xff; //接收到NAK则停止读取数据
}
else //接收到 ACK 则继续读取数据 (重点)可持续发送 数据出去 主机觉得不断开
{
I2CTXD = BufferSend[++AddrSend]; //接收到ACK则继续读取数据
/*
if(deviceID_addr == 0xC3) //判断是否发出了24个字节 这里是我芯片特定的规律
{
I2CTXD = buffer1_24byte[++Read_organize_one];
if(Read_organize_one >= 24)
{
//printf("打印出_I2CTXD:%X ADD:%d\r\n", buffer1_24byte[Read_organize_one-1],Read_organize_one-1); //打印会影响数据输出准确性
Read_organize_one = 0;
I2CSLST &= ~0x10; //处理 SEND 事件 从机模式时发送完成1字节的数据后的中断请求位
I2CSLST &= ~0x08; //处理 STOP 事件 从机模式时接收到STOP信号后的中断请求位
}
}
if(deviceID_addr == 0xC5) //判断是否发出了24个字节 这里是我芯片特定的规律
{
I2CTXD = buffer2_24byte[++Read_organize_two];
if(Read_organize_two >= 24)
{
Read_organize_two = 0;
I2CSLST &= ~0x10; //处理 SEND 事件 从机模式时发送完成1字节的数据后的中断请求位
I2CSLST &= ~0x08; //处理 STOP 事件 从机模式时接收到STOP信号后的中断请求位
}
}
*/
}
}
else if(I2CSLST & 0x08) //从机模式时接收到 STOP 信号后的中断请求位
{
I2CSLST &= ~0x08; //处理STOP事件
isda = 1;
isma = 1;
AddrSend = 0;
AddrRev =0;
}
_pop_(P_SW2); //出栈处理
}
//=======================================================================================================================================================================

当吧寄存器的数据修改为最高位均不为1,则正常。如下:
BufferSend[0] =0x01;
BufferSend[1] =0x72;
BufferSend[2] =0x03;
BufferSend[3] =0x74;
BufferSend[4] =0x65;
BufferSend[5] =0x46;
BufferSend[6] =0x77;
BufferSend[7] =0x48;
BufferSend[8] =0x59;
BufferSend[9] =0x90;
