CH341搜索I2C从机,必须自行发送手动搭建临时I2C时序指令。而CH347搜索I2C从机,一个原生函数搞定
一、 CH341搜索I2C从机,必须自行发送手动搭建临时I2C时序指令
纯C的写法是:
c
//发送START
IIC_IssueStart(iIndex);
//通知iIndex主机发送从机地址device_addr,其bit7..bit1是7bit的从机地址且bit0=0,返回从机是否正确响应ack=0
Status = IIC_OutByteCheckAck(iIndex, device_addr);
//发送STOP
IIC_IssueStop(iIndex);
//判断Status是否等于1,=1表示找到了device_addr这个从机,=0表示没有找到
if (0==Status) {//没有找到USBHandle下I2CSlaveAddress对应的从I2C设备
return -1;
}
其中,
c
uint8_t CMD_I2C_STREAM = 0xAA; // I2C流命令包开头
uint8_t CMD_I2C_STM_STA = 0x74; // 产生起始位
uint8_t CMD_I2C_STM_STO = 0x75; // 产生停止位
uint8_t CMD_I2C_STM_OUT = 0x80; // 输出数据
uint8_t CMD_I2C_STM_END = 0x00; // 命令包提前结束
bool CH341Device::IIC_IssueStart()
{
uint8_t mBuffer[3] = {0};
mBuffer[0] = CMD_I2C_STREAM;
mBuffer[1] = CMD_I2C_STM_STA;
mBuffer[2] = CMD_I2C_STM_END;
ULONG writeLen = 3;
return CH341WriteData(m_deviceIndex, mBuffer, &writeLen);
}
bool CH341Device::IIC_IssueStop()
{
uint8_t mBuffer[3] = {0};
mBuffer[0] = CMD_I2C_STREAM;
mBuffer[1] = CMD_I2C_STM_STO;
mBuffer[2] = CMD_I2C_STM_END;
ULONG writeLen = 3;
return CH341WriteData(
static_cast<ULONG>(m_deviceIndex),
reinterpret_cast<PUCHAR>(mBuffer),
&writeLen
);
}
bool CH341Device::IIC_OutByteCheckAck1(uint8_t slaveAddr)
{
uint8_t mBuffer[4] = {0};
mBuffer[0] = CMD_I2C_STREAM;
mBuffer[1] = CMD_I2C_STM_OUT;
mBuffer[2] = slaveAddr;
mBuffer[3] = CMD_I2C_STM_END;
ULONG iWriteLength = 4;
ULONG iReadLength = 1;
ULONG readLen = 0;
uint8_t readBuffer[32] = {0};
BOOL ret = CH341WriteRead(
static_cast<ULONG>(m_deviceIndex),
iWriteLength,
reinterpret_cast<PUCHAR>(mBuffer),
32,
iReadLength,
&readLen,
reinterpret_cast<PUCHAR>(readBuffer)
);
if (ret && readLen > 0) {
return (readBuffer[readLen - 1] & 0x80) == 0;
}
return false;
}
二、 CH347搜索I2C从机,一个原生函数搞定
C原型函数头:
c
// 处理I2C数据流,速度约56K字节,返回主机端获取到的ACK数量
BOOL WINAPI CH347StreamI2C_RetACK(
ULONG iIndex, // 指定设备序号
ULONG iWriteLength, // 准备写出的数据字节数
PVOID iWriteBuffer, // 指向一个缓冲区,放置准备写出的数据,首字节通常是I2C设备地址及读写方向位
ULONG iReadLength, // 准备读取的数据字节数
PVOID oReadBuffer, // 指向一个缓冲区,返回后是读入的数据
PULONG rAckCount); // 指向读写返回的ACK值
一样的,我们可以调用该函数,通知iIndex主机发送1Byte数据即从机地址device_addr,其bit7...bit1是7bit的从机地址且bit0=0,运行完了应该有rAckCount==1,且返回值是执行完该函数(但实测无论从机是否有正确响应ack=1,这个返回值总是1)。
C#代码,先封装一个方法ConfirmSlaveAdd_CH347():
csharp
private int ConfirmSlaveAdd_CH347(uint CH347Index, byte I2CSlaveAdd)
{
byte[] wrBuf = new byte[] { I2CSlaveAdd, 0x00 };
byte[] rdBuf = new byte[1];
// iWriteLen=1,iReadLen=0;发送 Start + 从机写地址,然后Stop
uint ackCnt;
int apiOk = DLLProxy.CH347StreamI2C_RetACK(
(uint)CH347Index,
(uint)1,
wrBuf,
(uint)0,
rdBuf,
out ackCnt
);
if ((1 == apiOk) && (ackCnt == 1))//发送从机地址成功,且返回1次有效的ack=0
return 0; //已搜到目标从机地址
else
return -1; //未搜到目标从机地址
}
然后在某按键的Click事件的回调函数中调用ConfirmSlaveAdd_CH347():
csharp
int streamOk = ConfirmSlaveAdd_CH347(CH347Index, I2CSlaveAdd);
if (0 != streamOk){ //没搜到
Debug.WriteLine($"CH347StreamI2C调用失败,设备索引={CH347Index},从机地址={I2CSlaveAdd}");
return;
}
else{ //搜到了
Debug.WriteLine($"找到有效I2C地址:0x{I2CSlaveAdd:X2}");
}