硬件I2C主机模式如何实现I2C地址扫描
想知道总线上有哪些I2C器件,在Arduino中发现有这个函数,所以在模拟I2C中利用应答信号也可以扫描到,现在用STC8H的硬件I2C没有实现的思路。
模拟I2C的时候,利用WairACK失败判断没有这个地址
现在在STC8H硬件I2C中,想在wait中加入超时来判断,但实际发现不论是否有这个从地址存在,都会进中断,不知道是不是哪儿写错了.
发到这里看看有没有人讨论一下
//模式i2c
bool I2C_WaitAck(void) //返回为:=1有ACK,=0无ACK
{
I2C_SCL_L();
I2C_delay();
I2C_SDA_H();
I2C_delay();
I2C_SCL_H();
I2C_delay();
if(I2C_SDA_read)
{
I2C_SCL_L();
#ifdef DEBUG
printf("I2C_WaitAck Fail!\r\n");
#endif
return FALSE;
}
I2C_SCL_L();
return TRUE;
}
//硬件i2c
void I2C_Init(void)
{
P_SW2 |= 0x80; //使能访问XFR, I2C功能寄存器访问需要打开这个
I2CCFG= 0xFE; //使能I2C,主机模式,MSSPEED=2x62+4=128,I2C总线速度=40M/2/128=156.25K
I2CMSST = 0x00;
}
bit I2C_Wait(void)
{
unsigned long TimeOut = 200000L; //40*1000*5,5ms
while(TimeOut--)
{
if (I2CMSST & 0x40)
{
I2CMSST &= ~0x40;
return TRUE;
}
}
return FALSE;
}
//启动I2C总线
void I2C_Start(void)
{
I2CMSCR = 0x01;
if( !I2C_Wait() )
UART_PutString_NoISR("I2C Start Fail!\r\n");
}
//主机发送一个字节
void I2C_SendByte(unsigned char SendByte)
{
I2CTXD= SendByte;
I2CMSCR = 0x02;
I2C_Wait();
}
//主机接受从机的应答信号
bit I2C_RecvAck(void)
{
I2CMSCR = 0x03;
if( I2C_Wait() )
{
return TRUE;
}
else
{
UART_PutString_NoISR("I2C RecvAck Fail!\r\n");
return FALSE;
}
}
//主机读取一个字节
unsigned char I2C_ReceiveByte(void)
{
I2CMSCR = 0x04; //发送RECV 命令
I2C_Wait();
return I2CRXD;
}
//主机给从机发送应答信号
void I2C_SendAck( void)
{
I2CMSST = 0x00; //设置ACK 信号
I2CMSCR = 0x05; //发送ACK 命令
I2C_Wait();
}
void I2C_SendNoAck( void)
{
I2CMSST = 0x01; //设置NAK 信号
I2CMSCR = 0x05; //发送ACK 命令
I2C_Wait();
}
//停止I2C总线
void I2C_Stop(void)
{
I2CMSCR = 0x06; //发送STOP 命令
I2C_Wait();
}
void I2C_Scan_SlaveAddress(void)
{
u8 i;
for(i=0;i<=0x7F;i++) //7位SlaveAddress
{
I2C_Start();
I2C_SendByte((i<<1) | 0); //I2C从地址+写标志
if ( I2C_RecvAck() )
{
// UART_PutString("\r\nFound Device Address:");
// UART_DebugDat(&i,1);
// UART_PutString("\r\n");
UART_PutString_NoISR("\r\nFound Device Address:");
UART_PutChar_NoISR(i);
UART_PutString("\r\n");
}
else
{
I2C_Stop();
}
}
}
串口打印结果显示I2C_RecvAck()一直为 TRUE
通过这种超时的方式是无法实现你的需求的
因为无论读取到ACK还是NAK,都会产生中断
正确的做法是在中断中判断MSACKI这个位来判断读取的是ACK还是NAK
如果是ACK,则表示当前地址有效,否则如果是NAK,则地址无效
zhp 发表于 2022-11-26 20:25
通过这种超时的方式是无法实现你的需求的
因为无论读取到ACK还是NAK,都会产生中断
谢谢,提供了一个思路,我试试看 zhp 发表于 2022-11-26 20:25
通过这种超时的方式是无法实现你的需求的
因为无论读取到ACK还是NAK,都会产生中断
你的方法可以用,能扫描到正确器件地址。
就是每次会把地址00都认为是正确的,有应答
就这个0x00,不知道是什么原因
bit I2C_Wait(void)
{
bit ACK_or_NACK=0;
while (!(I2CMSST & 0x40));
if(I2CMSST & 0x02) //判断I2CMSST的bit1 MSACKI,读入的ACK信号为低即是ACK,为高为NACK.
ACK_or_NACK = FALSE; //MSACKI=1=NACK=没有正确收到ACK信号
else
ACK_or_NACK = TRUE; //MSACKI=0=ACK=正确收到ACK信号
I2CMSST &= ~0x40; //清除中断标志
return ACK_or_NACK;
}
void I2C_Scan(void)
{
u8 i;
for(i=0;i<=0x7F;i++) //7位SlaveAddress
{
I2C_Start();
I2C_SendByte((i<<1) | 0); //I2C从地址+写标志
if ( I2C_RecvAck() )
{
UART_PutString("\r\nFound Device Address:");
UART_DebugDat(&i,1);
UART_PutString("\r\n");
}
else
{
I2C_Stop();
}
}
}
liners 发表于 2022-11-28 10:02
你的方法可以用,能扫描到正确器件地址。
就是每次会把地址00都认为是正确的,有应答
不同的I2C设备对地址00有不同的处理方式
比如用我们的单片机的I2C作为从机,会匹配SLADR寄存器中的从机地址,也会匹配00H地址
也就是说当检测到从机地址等于SLADR或者00时,都会回应ACK zhp 发表于 2022-11-28 11:52
不同的I2C设备对地址00有不同的处理方式
比如用我们的单片机的I2C作为从机,会匹配SLADR寄存器中的从机地 ...
感谢
已经用了上
页:
[1]