FYP0303 发表于 2024-12-10 15:05:43

AI8H1K28作为IIC从机,意外触发停止条件

<p>程序如下,上位机从2号寄存器开始读取5个字节。</p>
<p>bit isda;                                       //设备地址标志<br />
bit isma;                                       //存储地址标志<br />
unsigned char AddrSend;<br />
unsigned char AddrRev;<br />
unsigned char pdata BufferSend;<br />
unsigned char pdata BufferRev;</p>
<p>void I2C_GPIO_Config(void)<br />
{<br />
GPIO_InitTypeDef        GPIO_InitStructure;                //结构定义</p>
<pre><code>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,&amp;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=010_1101B,MA=0B。
                                          //由于MA为0,主机发送的的设备地址必须与
                                          //I2CSLADR相同才能访问此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        =0x81;
BufferSend        =0x82;
BufferSend        =0x83;
BufferSend        =0x84;
BufferSend        =0x85;
BufferSend        =0x86;
BufferSend        =0x87;
BufferSend        =0x88;
BufferSend        =0x89;
BufferSend        =0x90;

I2CTXD = BufferSend;
</code></pre>
<p>}<br />
//=======================================================================================================================================================================</p>
<p>void I2C_Isr() interrupt 24<br />
{<br />
<em>push</em>(P_SW2);                                                                //将 切换控制寄存器 进栈处理<br />
P_SW2 |= 0x80;</p>
<pre><code>if(I2CSLST &amp; 0x40)                                                        //收到开始信号
{
    I2CSLST &amp;= ~0x40;                     //处理START事件,开始信号清零 STAIF 位清零
}
else if(I2CSLST &amp; 0x20)                                                //从机模式时接收到 1 字节的数据后的中断请求位
{
    I2CSLST &amp;= ~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;
                //memory_addr = I2CRXD;
                //IICdata_addr =0;
    }                                        //由于初始化的时候,IIC接收所有设备地址 ,不过从这里可继续添加else if 语句进行判断特点指令
    else                                //数据1 和 数据2
    {
      BufferRev = I2CRXD;            //处理RECV事件(RECV DATA)
                //if(IICdata_addr &gt;= 2) IICdata_addr = 0;
                //I2C_Buffer = I2CRXD; //处理 RECV 事件(数据1 和 数据2)
    }
}
else if(I2CSLST &amp; 0x10)                                                //从机模式时发送完成 1 字节的数据后的中断请求位
{
    I2CSLST &amp;= ~0x10;                     //处理SEND事件,从机模式时发送完成1字节的数据后的中断请求位
    if (I2CSLST &amp; 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 &gt;= 24)
                        {
                                //printf(&quot;打印出_I2CTXD:%X ADD:%d\r\n&quot;, buffer1_24byte,Read_organize_one-1); //打印会影响数据输出准确性
                                Read_organize_one = 0;
                                I2CSLST &amp;= ~0x10; //处理 SEND 事件                                        从机模式时发送完成1字节的数据后的中断请求位
                                I2CSLST &amp;= ~0x08; //处理 STOP 事件                                                从机模式时接收到STOP信号后的中断请求位
                        }
                }
                if(deviceID_addr == 0xC5) //判断是否发出了24个字节        这里是我芯片特定的规律
                {
                        I2CTXD = buffer2_24byte[++Read_organize_two];
                        if(Read_organize_two &gt;= 24)
                        {
                                Read_organize_two = 0;
                                I2CSLST &amp;= ~0x10; //处理 SEND 事件                                         从机模式时发送完成1字节的数据后的中断请求位
                                I2CSLST &amp;= ~0x08; //处理 STOP 事件                                                从机模式时接收到STOP信号后的中断请求位
                        }       
                }
                */
    }
}
else if(I2CSLST &amp; 0x08)                                                //从机模式时接收到 STOP 信号后的中断请求位
{
    I2CSLST &amp;= ~0x08;                     //处理STOP事件
    isda = 1;
    isma = 1;
        AddrSend = 0;
        AddrRev        =0;
}

_pop_(P_SW2);                                                                //出栈处理
</code></pre>
<p>}</p>
<p>//=======================================================================================================================================================================</p>
<p><img src="data/attachment/forum/202412/10/150359caqzin7zi836mj88.png" alt="001.png" title="001.png" /></p>
<p>当吧寄存器的数据修改为最高位均不为1,则正常。如下:</p>
<p>BufferSend        =0x01;<br />
BufferSend        =0x72;<br />
BufferSend        =0x03;<br />
BufferSend        =0x74;<br />
BufferSend        =0x65;<br />
BufferSend        =0x46;<br />
BufferSend        =0x77;<br />
BufferSend        =0x48;<br />
BufferSend        =0x59;<br />
BufferSend        =0x90;</p>
<p><img src="data/attachment/forum/202412/10/150459ffqkf0rkxlxx7sqe.png" alt="002.png" title="002.png" /></p>

国学芯用 发表于 2024-12-10 15:41:28

程序打包在这里

DebugLab 发表于 2024-12-10 17:24:38

和最高位有关,用示波器看一下是不是上升沿速度不够
打开内部4K上拉

DebugLab 发表于 2024-12-10 17:45:01

或者主机上拉,或者外接上拉电阻

DebugLab 发表于 2024-12-10 17:46:16

看您的程序中只配置为准双向了,没有打开内部4K上拉

页: [1]
查看完整版本: AI8H1K28作为IIC从机,意外触发停止条件