问答

汇集网友智慧,解决技术难题

21ic问答首页 - 关于PIC18F25K42的I2C通讯问题

PIC18 I2c PIC18F 通讯 TE

关于PIC18F25K42的I2C通讯问题

南京棣拓2022-09-06
本帖最后由 pzsh 于 2022-9-7 09:21 编辑

MCU型号:PIC18F25K42实现功能:做I2C从机,只接收主机发送的数据即可,不需要发送数据给主机,每次数据包长度为2个字节,发送间隔大约44ms左右。
问题描述:在设备初始化后,从机可以接收到主机发送来的数据,但是一般在接收到几个数据包后,从机的I2C就会出现问题。
1、通过逻辑分析仪看出,出问题那个数据包,最后一个字节的第8个时钟拉低后就一直处于低状态,导致I2C无法正常工作。
2、通过debug发现,出问题那个数据包,程序是没有进入I2C中断的。
3、出问题后I2C的时钟线一直处于被拉低状态,直到对从机复位,才可以恢复正常。
后期经过调试发现,只要在I2C的中断里面加上几十个NOP();这个问题就可以解决。想请教下有没有大牛可以帮忙解答下困惑,谢谢!
程序代码都是通过MCC生成的。

I2C的初始化配置
void I2C1_Initialize(void)
{
                   // ADR 34;
                I2C1ADR0 = 0x22;
                // ADR 127;
                I2C1ADR1 = 0xFE;
                // ADR 0;
                I2C1ADR2 = 0x00;
                // ADR 0;
                I2C1ADR3 = 0x00;
                // TXU 0; CSD Clock Stretching enabled; ACKT 0; RXO 0; ACKDT Acknowledge; ACKSTAT ACK received; ACKCNT Not Acknowledge;
                I2C1CON1 = 0x80;
                // ABD enabled; GCEN disabled; ACNT disabled; SDAHT 300 ns hold time; BFRET 8 I2C Clock pulses; FME disabled;
                I2C1CON2 = 0x00;
                // CLK Fosc/4;
                I2C1CLK = 0x00;
                // CNT 255;
                I2C1CNT = 0xFF;
                // CSTR Enable clocking; S Cleared by hardware after Start; MODE four 7-bit address; EN enabled; RSEN disabled;
                I2C1CON0 = 0x80;

    PIR2bits.I2C1RXIF=0;
    PIR3bits.I2C1TXIF=0;
    PIR3bits.I2C1EIF=0;
    I2C1ERRbits.NACKIF=0;
    PIR3bits.I2C1IF=0;
    I2C1PIRbits.PCIF=0;
    I2C1PIRbits.ADRIF=0;

    PIE2bits.I2C1RXIE=1;//enable I2C RX interrupt
    PIE3bits.I2C1TXIE=1;//enable I2C TX interrupt
    PIE3bits.I2C1EIE=1;//enable I2C error interrupt
    I2C1ERRbits.NACKIE=1;//enable I2C error interrupt for NACK
    PIE3bits.I2C1IE=1;//enable I2C  interrupt
    I2C1PIEbits.PCIE=1;//enable I2C interrupt for stop condition
    I2C1PIEbits.ADRIE=1;//enable I2C interrupt for I2C address match condition
        

    I2C1PIR = 0;//    ;Clear all the error flags
    I2C1ERR = 0;

}

中断配置
void __interrupt() INTERRUPT_InterruptManager (void)
{
    // interrupt handler
    if(PIE3bits.TMR0IE == 1 && PIR3bits.TMR0IF == 1)
    {
        TMR0_ISR();
    }
    else if(PIE3bits.I2C1EIE == 1 && PIR3bits.I2C1EIF == 1)
    {
        I2C1_ISR();
    }
    else if(PIE2bits.I2C1RXIE == 1 && PIR2bits.I2C1RXIF == 1)
    {
        I2C1_ISR();
    }
    else if(PIE3bits.I2C1IE == 1 && PIR3bits.I2C1IF == 1)
    {
        I2C1_ISR();
    }
    else if(PIE3bits.I2C1TXIE == 1 && PIR3bits.I2C1TXIF == 1)
    {
        I2C1_ISR();
    }
    else if(PIE3bits.U1TXIE == 1 && PIR3bits.U1TXIF == 1)
    {
        UART1_TxInterruptHandler();
    }
    else if(PIE3bits.U1RXIE == 1 && PIR3bits.U1RXIF == 1)
    {
        UART1_RxInterruptHandler();
    }
    else
    {
        //Unhandled Interrupt
    }
}

I2C的中断处理函数
void I2C1_ISR ( void )
{

    uint8_t  I2C1_data = 0x55;
    uint8_t  i=0;
    if ((I2C1STAT1bits.RXBF)||(PIR2bits.I2C1RXIF))
    {
                PIR2bits.I2C1RXIF=0;
        //I2C1_data = I2C1RXB;
        I2C1_RxBuffer[I2C1_RxCount]=I2C1RXB;
        if(I2C1_RxBuffer[I2C1_RxCount] == 0)
        {
            I2C1_RxCount++;            
        }else
        {
            I2C1_RxFlag = 1;
            I2C1_RxCount = 0;
        }
        if(I2C1_RxCount>1)
        {
            I2C1_RxCount=0;
        }  
    }
    if(1 == I2C1STAT0bits.R)
    {

        if (I2C1PIRbits.PCIF)
        {
            I2C1PIRbits.PCIF=0;
                        PIR3bits.I2C1IF=0;
            I2C1STAT1bits.CLRBF=1;//clear I2C1TXB and TXBE
                        I2C1CNT=0xFF;
        }
        if (I2C1ERRbits.NACKIF)
        {
            I2C1ERRbits.NACKIF=0;
                        PIR3bits.I2C1EIF=0;
            I2C1STAT1bits.CLRBF=1;//clear I2C1TXB and TXBE
            I2C1_StatusCallback(I2C1_SLAVE_READ_COMPLETED);
        }
        else if(PIR3bits.I2C1TXIF)
        {
                        PIR3bits.I2C1TXIF=0;
            // callback routine should write data into I2C1TXB
            I2C1_StatusCallback(I2C1_SLAVE_READ_REQUEST);
        }
        if (I2C1PIRbits.ADRIF)
        {
            I2C1PIRbits.ADRIF=0;
                        PIR3bits.I2C1IF=0;
        }

    }
    else if((I2C1PIRbits.ADRIF))
    {
        I2C1PIRbits.ADRIF=0;
                PIR3bits.I2C1IF=0;
        // callback routine should prepare to receive data from the master
        I2C1_StatusCallback(I2C1_SLAVE_WRITE_REQUEST);
    }
    else
    {
        I2C1_slaveWriteData   = I2C1_data;
                if (I2C1PIRbits.PCIF)
        {
            I2C1PIR=0;
                        PIR3bits.I2C1IF=0;
            I2C1STAT1bits.CLRBF=1;
                        I2C1CNT=0xFF;
        }

        // callback routine should process I2C1_slaveWriteData from the master
        I2C1_StatusCallback(I2C1_SLAVE_WRITE_COMPLETED);
    }
    I2C1CON0bits.CSTR=0;
    //下面这个循环加了后,问题就解决了
    for(i=0;i<50;i++)
    {
        NOP();
    }
}


回答 +关注 14
1661人浏览 4人回答问题 分享 举报
4 个回答
  • 同意楼上,先把别的屏蔽掉,特别是中断里的,看看是不是其他有影响。
  • 你不是没有发送吗,怎么还有发送中断的,你调东西,既然出了问题,就应该单一一点,专心调这个IIC,别的都屏蔽掉,怎么还有串口这些东西在里面,七七八八的,感觉好乱。
    既然从机只有接收,那中断处理就不需要读的操作了,只需要关心写的操作,写操作又分写地址和写数据,写地址直接从寄存器读出来,剩下的就是数据,进入中断也表示从机已经应答,你有没有释放总线?
    MCC只能做个辅助,还是要多看数据手册,看他7位寻址接收的步骤。

  • 现在我的解决办法是在I2C的中断里面加了50个循环NOP(),加了之后就没有出现这个问题了。
    但是还是希望能解决根本的问题,而不是通过加NOP来解决。
  • 问题解决了吗?

您需要登录后才可以回复 登录 | 注册