CH340与CH341的常见问题解答

SOS!我在使用CH340G(外置晶振)时,初始化时芯片的输出电平会有相应变化(而控制系统是不希望这样的),后来厂家升级了驱动程序,这个问题解决了。可是当我采用CH340C(无外置晶振)时,这个问题又出现了,该如何解决呢?请厂家提供解决方案。谢谢了!有高手也望不吝指教!拜托了!顺祝节日快乐!


您好,请问具体所指信号变化是否为DTR和RTS变化。如果是该2个信号在USB插入时变化,则是因为驱动版本未更新至最新版本所致,请从如下链接中下载驱动:http://www.wch.cn/downloads/CH341SER_EXE.html 


谢谢TECH39的回复!确实是DTR和RTS信号的变化,CH340C插入USB时DTR和RTS没有变化,当驱动加载后这两个信号就动作了,而这时操作DTR和RTS的命令并没有下达。当芯片为CH340G时,通过升级CH341SER.EXE可以解决。而当芯片为CH340C时,这个方法不起作用了。链接下载的驱动日期为2019/1/30,版本为3.5.2019.1。也就是说:这个版本不能解决问题。症结在哪里呀?还求TECH39继续指导为盼!


您好,可以添加我微信单独确认下问题仍然存在的原因。已私信您联系方式。


您好!如何添加呀?您的微信号是啥?盼告。谢谢!


我的微信号:lichenyin2017,EMAIL:个人信息保护,已隐藏


您好,已添加微信。您可以将如上包含个人信息回帖删除,以免收到广告信息等。


官网CH341A驱动程序无法适配 ubuntu 5.11.0-37-generic 系统,驱动版本过旧,无法编译,需要如何修改驱动程序源代码!


您好,请单独mail给我,我将资料包发送过去,有问题及时沟通。我的邮箱地址:zhangj@wch.cn


1、利用CH341对I2C从站进行写操作,代码如下,结果成功完成。

            CH341OpenDevice(0);

            CH341StreamI2C(0, 18, tx_buf, 0, rx_buf);    // 写入16字节的数据到指定存储器

            CH341CloseDevice(0);

2、对从站进行读操作,代码如下:

            CH341OpenDevice(0);

            IIC_IssueStart(0);                           // start

            IIC_OutByteCheckAck(0, 0x80);    // 从站地址=0x40

            IIC_OutByteCheckAck(0, 0x04);    // 读取命令

            IIC_IssueStart(0);                           // start

            IIC_OutByteCheckAck(0, 0x81);    // 0x40<<1 + 1

            IIC_InBlockByAck(0, 15, rx_buf);   // 前15个字节由主机ACK

            IIC_InByteNoAck(0, temp);           // 最后一个字节由主机NACK

            rx_buf[15] = temp;

            IIC_IssueStop(0);

            CH341CloseDevice(0);

            从站是一个MCU,通过监视可以正常接收到IIC_OutByteCheckAck发送的数据,但返回给主机的数据只发送了2个字节(应该发送16个字节的),而通过CH341这边接收到的数据又全部是0xFF。

            以上程序是调用CH341DLL.DLL在VC#环境下编制的,以前采用其它厂家的USB/I2C转换器都完全调试通过了的,因此I2C从站设备是不会有问题的,现在就是针对IIC_InBlockByAck和IIC_InByteNoAck这两个功能块有所怀疑,请帮助分析一下,谢谢!



您好,如上提到的功能函数IIC_InBlockByAck、IIC_InByteNoAck等具体是什么实现,可以把这部分的代码发给我们确认下。排查I2C的读写问题主要有如下几个点:

1、CH341的读I2C,默认API在写完设备+寄存器地址后没有delay,要求设备准备数据足够快;(若来不及,可以先通过CH341SetStream设置为100Khz的I2C);

2、CH341默认是忽略I2C设备的ACK状态的,即设备是ACK或NACK,不影响API返回结果;

提到的返回给主机的数据只发送2个字节(应该16字节):关于这段话,主机读取的字节是主机决定,不是设备决定,读取16字节CH341StreamI2C中的读长度设置为16即可。


1、已被验证可正确执行的3个子程序:

        public bool IIC_IssueStart(UInt32 iIndex)

        {

            byte[] mBuffer = new byte[3];

            UInt32 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, ref mLength));

        }

        public bool IIC_IssueStop(UInt32 iIndex)

        {

            byte[] mBuffer = new byte[3];

            UInt32 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, ref mLength));

        }

        public bool IIC_OutByteCheckAck(UInt32 iIndex, byte iOutByte)

        {

            byte[] mBuffer = new byte[10];

            UInt32 mLength, mInLen;

            mBuffer[0] = mCH341A_CMD_I2C_STREAM;

            mBuffer[1] = mCH341A_CMD_I2C_STM_OUT;

            mBuffer[2] = iOutByte;

            mBuffer[3] = mCH341A_CMD_I2C_STM_END;

            mLength = 4;

            mInLen = 0;

            if (CH341WriteRead(iIndex, mLength, mBuffer, 32, 1, ref mInLen, mBuffer) == true)

            {

                if ((mInLen > 0) && ((mBuffer[mInLen-1] & 0x80) == 0))

                    return (true);

            }

            return (false);

        }

  

2、执行结果不正确的2个子程序: 

        public bool IIC_InBlockByAck(UInt32 iIndex, UInt32 iInLength, byte[] oInBuffer)

        {

            byte[] mBuffer = new byte[40];

            UInt32 mLength, mInLen;

            if ((iInLength == 0) || (iInLength > 32))

                return (false);

            mBuffer[0] = mCH341A_CMD_I2C_STREAM;

            mBuffer[1] = (byte)(mCH341A_CMD_I2C_STM_IN |iInLength);

            mBuffer[2] = mCH341A_CMD_I2C_STM_END;

            mLength = 3;

            mInLen = 0;

            if(CH341WriteRead(iIndex, mLength, mBuffer, 32, 1, ref mInLen, mBuffer)==true)

            {

                if (mInLen == iInLength)

                {

                    for (int i = 0; i < iInLength; i++)

                        oInBuffer[i] = mBuffer[i];

                    return (true);

                }

            }

            return(false);

        }

        public bool IIC_InByteNoAck(UInt32 iIndex, ref byte oInByte)

        {

            byte[] mBuffer = new byte[4];

            byte[] nBuffer = new byte[40];

            UInt32 mLength, mInLen;

            mBuffer[0] = mCH341A_CMD_I2C_STREAM;

            mBuffer[1] = mCH341A_CMD_I2C_STM_IN;

            mBuffer[2] = mCH341A_CMD_I2C_STM_END;

            mLength = 3;

            mInLen = 0;

            if(CH341WriteRead(iIndex,mLength,mBuffer,32,1,ref mInLen,nBuffer)==true)

            {

                if(mInLen > 0 )

                {

                    oInByte = nBuffer[mInLen-1];

                    return(true);

                }

            }

            return(false);

        }



从机只发送了2个字节是这样的:从机MCU是通过中断来发送数据的,每中断一次增加一次发送计数器,目前这个指令(0x04)执行后已经把要发送的数据放到了发送缓冲区(0x3F,0x9D,0x70,0xA4,.....)共16个字节,但响应完指令后发送计数器=2,上位机接收到的数据为:0x1F,0xFF,0xFF,0xFF,.....共16个字节。

当发送缓冲区数据=0x40,....共16个字节时,已发送的字节还是=2,但上位机收的数据为:0x20,0xFF,0xFF,...16个字节,感觉像数据错位或时钟过快。




           IIC_IssueStart(0);                           // start

            IIC_OutByteCheckAck(0, 0x80);    // 从站地址=0x40

            IIC_OutByteCheckAck(0, 0x04);    // 读取命令

CH341的读I2C,因为写完设备+寄存器地址后没有delay,要求设备准备数据足够快;

           那我在这里加入一条延时语句,是否有用?)


            IIC_IssueStart(0);                           // start

            IIC_OutByteCheckAck(0, 0x81);    // 0x40<<1 + 1

            IIC_InBlockByAck(0, 15, rx_buf);   // 前15个字节由主机ACK

            IIC_InByteNoAck(0, temp);           // 最后一个字节由主机NACK

            rx_buf[15] = temp;

            IIC_IssueStop(0);



您好,因为I2C的读操作需要Repeat Start,进行读操作的时候需要先Write设备地址(有寄存器地址),如果是采用单独的 IIC_OutByteCheckAck函数再读,则会没有Repeat Start信号。您可以发邮件给我,我整理下Code发您。此外,有逻辑分析仪的话可以同步抓下I2C时序,定位问题会更便捷些。


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