本帖最后由 flove00 于 2019-1-18 17:37 编辑
刚好有用到003做I2c从机,目前使用过程中发现一些问题。当发生干扰导致i2c通信失败之后,003 i2c端口就死掉了,无法进入中断。不知道应该怎么配置i2c死掉后可以自动恢复。目前只能做i2c从机通信丢失超过1s,重置i2c端口配置来解决。有解决的童鞋请告知一下,谢谢。以下是我的代码仅供参考。
//***********************************************************************************************************
// N76E003-series I2C slave mode demo code, the Slave address = 0xA4
//
// ____________ _____________
// | | SDA | |
// | |<-------->| |
// | | | |
// |029(M) | | N76E003(S) |
// |(I2C_Master)| | (I2C_Slave) |
// | | SCL | |
// | |--------->| |
// |____________| |_____________|
//
//***********************************************************************************************************
#define EEPROM_SLA 0x86
xdata volatile unsigned char I2C_trans_data[D_I2C_length_max];
xdata volatile unsigned char I2C_rec_data[D_I2C_length_max];
xdata unsigned char I2C_SP=0;
bit F_I2C_REC_OK = 0;
//========================================================================================================
void I2C_ISR(void) interrupt 6
{
switch (I2STAT)
{ /*总线错误*/
case 0x00: //00H,bus error occurs
STO = 1;//recover from bus error
break;
/*从机接受地址应答*/
case 0x60: //60H, own SLA+W received, ACK returned
AA = 1;//接收到正确地址并应答
I2C_SP = 0;
break;
/*从机接受仲裁失败*/
case 0x68://68H, arbitration lost in SLA+W/R
AA = 0;
STA = 1;//仲裁丢失,尝试重新起始信号
break;
/*从机接收数据应答*/
case 0x80:
I2C_rec_data[I2C_SP] = I2DAT;
I2C_SP++;
if (I2C_SP >=D_I2C_length_max)
{
AA = 0;//最后数据不应达,应与主机匹配发送的数据长度
F_I2C_REC_OK = 1;
}
else
AA = 1;
break;
/*从机接收地址无应答*/
case 0x88:
I2C_rec_data[I2C_SP] = I2DAT;//好像没什么用处
I2C_SP = 0;//等待下一次地址信号
AA = 1;
break;
/*从机发送重复开始或停止信号*/
case 0xA0:
AA = 1;
I2C_SP = 0;
break;
/*从机发送地址应答*/
case 0xA8:
I2DAT = I2C_trans_data[I2C_SP];//第一位
I2C_SP=1;
AA = 1;//读取时收到的地址正确,发送应答信号
break;
/*从机发送仲裁失败*/
case 0xB0:
I2DAT = I2C_trans_data[I2C_SP];//虚假数据?
AA = 0;
I2C_SP = 0;
STA = 1;
break;
/*从机发送数据应答*/
case 0xB8:
I2DAT = I2C_trans_data[I2C_SP];
I2C_SP++;
if (I2C_SP >= D_I2C_length_max)
AA = 0;
else
AA = 1;
break;
/*从机发送数据无应答*/
case 0xC0:
AA = 1;
break;
/*从机发送最后数据应答*/
case 0xC8:
AA = 1;
break;
default:
{
Init_I2C_Slave();
};
}
SI = 0;
while(STO);
}
//========================================================================================================
void Init_I2C_Slave(void)
{
clr_EI2C;
clr_I2CEN;
clr_AA;
P13_Quasi_Mode; //set SCL (P13) is Quasi mode
P14_Quasi_Mode; //set SDA (P14) is Quasi mode
SDA = 1; //set SDA and SCL pins high
SCL = 1;
set_P1SR_3; //set SCL (P13) is Schmitt triggered input select.
set_EI2C; //enable I2C interrupt by setting IE1 bit 0
// set_EA;
I2ADDR = EEPROM_SLA; //define own slave address
set_I2CEN; //enable I2C circuit
set_AA;
Array_Init(I2C_trans_data,D_I2C_length_max);
Array_Init(I2C_rec_data,D_I2C_length_max);
I2C_reset_cnt=D_I2C_reset_cnt;
}
主机每32ms发一次数据,若i2c从机发生错误,通信丢失1s后重置i2c端口。
xdata volatile unsigned char Comm_I2C_Rec[D_I2C_length_max];
xdata volatile unsigned char Comm_I2C_Trans[D_I2C_length_max];
xdata unsigned char I2C_test_cnt;
xdata unsigned char I2C_reset_cnt;
xdata unsigned char i2c_err=0;
void I2C_Get_Data(void)
{
disp_data[0]=Comm_I2C_Rec[1];
disp_data[1]=Comm_I2C_Rec[2];
disp_data[2]=Comm_I2C_Rec[3];
}
void I2C_Send_Data(void)
{
Comm_I2C_Trans[1] = 1;
Comm_I2C_Trans[2] = 1;
Comm_I2C_Trans[3] = I2C_test_cnt;
Comm_I2C_Trans[4] = 1;
Comm_I2C_Trans[5] = 1;
Comm_I2C_Trans[6] = 1;
Comm_I2C_Trans[7] = 1;
}
/*主机I2C周期应选在16ms~64ms之间,若频率过快,可能会未解码完成,新的I2C
中断产生并被覆盖。
*/
void Comm_I2C_Slave(void)
{
xdata unsigned char sum=0;
static unsigned char err_cnt=0;
if(F_I2C_REC_OK)
{
move_ram(I2C_rec_data,Comm_I2C_Rec,D_I2C_length_max);//复制接收到的数据
sum = check_sum_char(Comm_I2C_Rec,(D_I2C_length_max-2));//校验
if((Comm_I2C_Rec[0]==0xAA) &&(Comm_I2C_Rec[D_I2C_length_max-1]==0x55)
&&(Comm_I2C_Rec[(D_I2C_length_max-2)]==sum)
)
{
err_cnt=0;
I2C_Get_Data();
I2C_Send_Data();
test_disp++;
Comm_I2C_Trans[0] =0x55;
Comm_I2C_Trans[D_I2C_length_max-1]=0xAA;
sum = check_sum_char(Comm_I2C_Trans,(D_I2C_length_max-2));//校验
Comm_I2C_Trans[(D_I2C_length_max-2)]=sum;
move_ram(Comm_I2C_Trans,I2C_trans_data,D_I2C_length_max);//复制需要发送的数据
I2C_reset_cnt=D_I2C_reset_cnt;
}
F_I2C_REC_OK = 0;
I2C_rec_data[0]=0;
I2C_rec_data[(D_I2C_length_max-2)]=0;
I2C_rec_data[(D_I2C_length_max-1)]=0;
Comm_I2C_Rec[(D_I2C_length_max-2)]=0;
Comm_I2C_Rec[(D_I2C_length_max-1)]=0;
}
else
{
while(SI != 0)//发生I2C总线故障时做以下处理
{
if(I2STAT == 0x00)
{
STO = 1;
}
SI = 0;
if(SI != 0)
{
I2CEN = 0;
I2CEN = 1;
SI = 0;
I2CEN = 0;
}
err_cnt++;
if(err_cnt>=5)
{
err_cnt=0;
Init_I2C_Slave();
}
}
}
if(I2C_reset_cnt==0)
{
Init_I2C_Slave();
F_err_I2c=1;
i2c_err++;
}
/*
if(F_err_I2c)
{
disp_data[0]=0;
disp_data[1]=0;
DispTemp(i2c_err,0);
}
*/
}
/******************主机到从机的数据******************************/
//****************************从机到主机*************************************//
|
早说呀,我免费给你申请一块开发板玩玩,我是新唐一级代理商,有机会多交流沟通。