21ic问答首页 - 关于PIC18F25K42的I2C通讯问题
关于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();
}
}
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();
}
}
赞0
评论
2022-09-07
赞0
既然从机只有接收,那中断处理就不需要读的操作了,只需要关心写的操作,写操作又分写地址和写数据,写地址直接从寄存器读出来,剩下的就是数据,进入中断也表示从机已经应答,你有没有释放总线?
MCC只能做个辅助,还是要多看数据手册,看他7位寻址接收的步骤。
评论
2022-09-07
赞0
现在我的解决办法是在I2C的中断里面加了50个循环NOP(),加了之后就没有出现这个问题了。
但是还是希望能解决根本的问题,而不是通过加NOP来解决。
评论
2022-09-07
赞0
评论
2022-09-06
您需要登录后才可以回复 登录 | 注册