CH341A实现USB转I2C的问题

最近使用CH341A发现一个问题,用CH341A实现USB转I2C,当不接EEPROM进行字节写时,上位机仍然出现“I2C写数据成功”,字节读时,读取的是“FF”,这是为什么?没有EEPROM就没有应答,怎么可能进行读写呢?还有当有eeprom时,但读写地址跟eeprom不匹配也是同样问题!!!求解!!!

没有检查ack啊


我也知道没有检查ACK,是不是CH341.dll库中的函数就没有检查呢?要不然为什么用他们公司自己的软件都是一样的结果呢?!!!地址不匹配照样可写可读!!!


是的!

你可以通过下面的函数来解决检查应答的问题: /* ********************************************************************************************** */ /* 例子:兼容IIC总线的通用操作时序 */

BOOL WINAPI IIC_IssueStart( ULONG iIndex ) // 指定CH341设备序号 { UCHAR mBuffer[ mCH341_PACKET_LENGTH ]; ULONG mLength; mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令码 mBuffer[ 1 ] = mCH341A_CMD_I2C_STM_STA; // 产生起始位 mBuffer[ 2 ] = mCH341A_CMD_I2C_STM_END; // 当前包提前结束 mLength = 3; return( CH341WriteData( iIndex, mBuffer, &mLength ) ); // 写出数据块 }

BOOL WINAPI IIC_IssueStop( ULONG iIndex ) // 指定CH341设备序号 { UCHAR mBuffer[ mCH341_PACKET_LENGTH ]; ULONG mLength; mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令码 mBuffer[ 1 ] = mCH341A_CMD_I2C_STM_STO; // 产生停止位 mBuffer[ 2 ] = mCH341A_CMD_I2C_STM_END; // 当前包提前结束 mLength = 3; return( CH341WriteData( iIndex, mBuffer, &mLength ) ); // 写出数据块 }

BOOL WINAPI IIC_OutBlockSkipAck( // 输出数据块,不检查应答 ULONG iIndex, // 指定CH341设备序号 ULONG iOutLength, // 准备写出的数据字节数,单次必须小于29字节 PVOID iOutBuffer ) // 指向一个缓冲区,放置准备写出的数据 { UCHAR mBuffer[ mCH341_PACKET_LENGTH ]; ULONG mLength; if ( iOutLength == 0 || iOutLength > ( mCH341_PACKET_LENGTH - 1 - 1 - 1 ) ) return( FALSE ); mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令码 mBuffer[ 1 ] = (UCHAR)( mCH341A_CMD_I2C_STM_OUT | iOutLength ); // 输出数据,位5-位0为长度 memcpy( &mBuffer[2], iOutBuffer, iOutLength ); // 数据 mBuffer[ 1 + 1 + iOutLength ] = mCH341A_CMD_I2C_STM_END; // 当前包提前结束 mLength = 1 + 1 + iOutLength + 1; return( CH341WriteData( iIndex, mBuffer, &mLength ) ); // 写出数据块 }

BOOL WINAPI IIC_OutByteCheckAck( // 输出一字节数据并检查应答是否有效 ULONG iIndex, // 指定CH341设备序号 UCHAR iOutByte ) // 准备写出的数据 { UCHAR mBuffer[ mCH341_PACKET_LENGTH ]; ULONG mLength, mInLen; mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令码 mBuffer[ 1 ] = mCH341A_CMD_I2C_STM_OUT; // 输出数据,位5-位0为长度,0长度则只发送一个字节并返回应答 mBuffer[ 2 ] = iOutByte; // 数据 mBuffer[ 3 ] = mCH341A_CMD_I2C_STM_END; // 当前包提前结束 mLength = 4; mInLen = 0; if ( CH341WriteRead( iIndex, mLength, mBuffer, mCH341A_CMD_I2C_STM_MAX, 1, &mInLen, mBuffer ) ) { // 执行数据流命令,先输出再输入 if ( mInLen && ( mBuffer[ mInLen - 1 ] & 0x80 ) == 0 ) return( TRUE ); // 返回的数据的位7代表ACK应答位,ACK=0有效 } return( FALSE ); }

BOOL WINAPI IIC_InBlockByAck( // 输入数据块,每输入一个字节都产生有效应答 ULONG iIndex, // 指定CH341设备序号 ULONG iInLength, // 准备读取的数据字节数,单次必须小于32字节 PVOID oInBuffer ) // 指向一个缓冲区,返回后是读入的数据 { UCHAR mBuffer[ mCH341_PACKET_LENGTH ]; ULONG mLength, mInLen; if ( iInLength == 0 || iInLength > mCH341A_CMD_I2C_STM_MAX ) return( FALSE ); mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令码 mBuffer[ 1 ] = (UCHAR)( mCH341A_CMD_I2C_STM_IN | iInLength ); // 输入数据,位5-位0为长度 mBuffer[ 2 ] = mCH341A_CMD_I2C_STM_END; // 当前包提前结束 mLength = 3; mInLen = 0; if ( CH341WriteRead( iIndex, mLength, mBuffer, mCH341A_CMD_I2C_STM_MAX, 1, &mInLen, mBuffer ) ) { // 执行数据流命令,先输出再输入 if ( mInLen == iInLength ) { memcpy( oInBuffer, &mBuffer[0], iInLength ); // 数据 return( TRUE ); } } return( FALSE ); }

BOOL WINAPI IIC_InByteNoAck( // 输入一字节数据,但是不产生应答 ULONG iIndex, // 指定CH341设备序号 PUCHAR oInByte ) // 指向一个字节的缓冲区,返回后是读入的数据 { UCHAR mBuffer[ mCH341_PACKET_LENGTH ]; ULONG mLength, mInLen; mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令码 mBuffer[ 1 ] = mCH341A_CMD_I2C_STM_IN; // 输入数据,位5-位0为长度,0长度则只接收一个字节并发送无应答 mBuffer[ 2 ] = mCH341A_CMD_I2C_STM_END; // 当前包提前结束 mLength = 3; mInLen = 0; if ( CH341WriteRead( iIndex, mLength, mBuffer, mCH341A_CMD_I2C_STM_MAX, 1, &mInLen, mBuffer ) ) { // 执行数据流命令,先输出再输入 if ( mInLen ) { *oInByte = mBuffer[ mInLen - 1 ]; // 数据 return( TRUE ); } } return( FALSE ); }


没学过软件的知识,不知道这段代码要怎么处理,能否给个进行“单字节”读写EEPROM的例程?非常感谢!


没学过软件的知识,不知道这段代码要怎么处理,能否给个进行“单字节”读写EEPROM并进行ACK检测的例程?非常感谢!


请到我们网站下载ch341evt.zip,里面有个包ch341par.zip,里面有操作eeprom的代码


我就是用的那个读写EEPROM程序,只是贵公司提供的那个程序没有“检查应答位”,我想贵公司可否提供一个“检查应答位”的“单字节”“读写EEPROM”的程序呢?不胜感激!


一到关键时刻就没人回复了!!!BOOL WINAPI IIC_OutByteCheckAck( // 输出一字节数据并检查应答是否有效 ULONG iIndex, // 指定CH341设备序号 UCHAR iOutByte ) // 准备写出的数据 { UCHAR mBuffer[ mCH341_PACKET_LENGTH ]; ULONG mLength, mInLen; mBuffer[ 0 ] = mCH341A_CMD_I2C_STREAM; // 命令码 mBuffer[ 1 ] = mCH341A_CMD_I2C_STM_OUT; // 输出数据,位5-位0为长度,0长度则只发送一个字节并返回应答 mBuffer[ 2 ] = iOutByte; // 数据 mBuffer[ 3 ] = mCH341A_CMD_I2C_STM_END; // 当前包提前结束 mLength = 4; mInLen = 0; if ( CH341WriteRead( iIndex, mLength, mBuffer, mCH341A_CMD_I2C_STM_MAX, 1, &mInLen, mBuffer ) ) { // 执行数据流命令,先输出再输入 if ( mInLen && ( mBuffer[ mInLen - 1 ] & 0x80 ) == 0 ) return( TRUE ); // 返回的数据的位7代表ACK应答位,ACK=0有效 } return( FALSE ); }

这段代码是不是一直返回FALSE呀?能不能给详细的资料?最好直接给个“检查应答位”的“单字节”“读写EEPROM”的程序,不胜感激!


已经很详细了啊,直接调用就可以了


我连续调用了 BOOL WINAPI IIC_IssueStart BOOL WINAPI IIC_OutByteCheckAck( // 输出一字节数据并检查应答是否有效 BOOL WINAPI IIC_IssueStop( 这三个函数,结果在示波器上发现三个函数之间的距离好远啊,所以BOOL WINAPI IIC_OutByteCheckAck这个函数就不识别前面发送的起始位信号,自然就不响应应答位,请问怎么解决?谢谢


这个问题搞定,不过不是像上面说的直接调用,还要修改拼装


只有登录才能回复,可以选择微信账号登录