不同编程语言下CH347DLL的调用方法

前言

        CH347为一款USB转JTAG/SPI/IIC/GPIO/UART接口的转换芯片,此处总结一下开发时所遇到的在C/C++、Python、C#下调用CH347DLL的方法,若有其他需要补充的也可一起交流。

        基于WCH官方Demo板做的代码验证。

1、C/C++调用

        可参考WCH官网CH347EVT/Tools下工程代码,此处则不再重复

2、Python调用

        选择Python调用时,需对应上Python和DLL是否都为32或64位,否则会出现调用失败的情况,传入API参数时则只需注意一下特殊的结构体此类参函数即可。

'''
Author: OIDCAT
Date: 2022-07-13 15:22:17
LastEditTime: 2022-08-23 19:19:23
此处需注意Python版本位数与DLL是否匹配
'''

 #! /usr/bin/env python
 #coding=utf-8
import ctypes
import os
from ctypes import *

# 
print("进入程序")
CH347 = windll.LoadLibrary("./CH347DLL.DLL")
DevIndex = 0
I2C_addr = 0xA0
class spi_config(Structure):
        _fields_ = [
            ("iMode", c_ubyte),
            ("iClock", c_ubyte),
            ("iByteOrder", c_ubyte),
            ("iSpiWriteReadInterval", c_ushort),
            ("iSpiOutDefaultData",c_ubyte),
            ("iChipSelect", c_ulong),
            ("CS1Polarity",c_ubyte),  
            ("CS2Polarity", c_ubyte), 
            ("iIsAutoDeativeCS", c_ushort), 
            ("iActiveDelay", c_ushort), 
            ("iDelayDeactive", c_ulong),
        ]

def init():
    if CH347.CH347OpenDevice(DevIndex) != -1:
        print("CH347 Open succeeded")
        CH347.CH347I2C_Set(DevIndex, 3)

        CH347_SPI = spi_config()
        CH347_SPI.iMode = 0x03
        CH347_SPI.iClock = 0x01
        CH347_SPI.iByteOrder = 0x01
        CH347_SPI.iSpiOutDefaultData = 0xff 
        CH347_SPI.iChipSelect = 0x80
        CH347.CH347SPI_Init(DevIndex, CH347_SPI)
        # CH347.CH347CloseDevice(DevIndex)
    else:
        print("Open The CH347 Failed")
            
def read(addr):
    if CH347.CH347OpenDevice(DevIndex) != -1:
        oBuf = (c_byte *2)()
        iBuf = (c_byte *1)()
        oBuf[0] = 0xA0
        oBuf[1] = addr
        CH347.CH347StreamI2C(DevIndex, 2, oBuf, 1, iBuf)
        CH347.CH347CloseDevice(DevIndex)
        print("CH347 read succeeded")
        return iBuf[0] & 0xFF
    else:
        print("CH347I2C.CH347OpenDevice")
        return 0

def spi_readId(DevIndex):
    cmd_buf = (c_byte * 4)()
    len = 4
    cmd_buf[0] = 0x9F
    cmd_buf[1] = 0xFF
    cmd_buf[2] = 0xFF
    cmd_buf[3] = 0xFF
    
    CH347.CH347SPI_WriteRead(DevIndex, 0x80, len, cmd_buf)
    print("{0:x} {1:x} {2:x} {3:x}".format(cmd_buf[0], cmd_buf[1], cmd_buf[2], cmd_buf[3]))
    return cmd_buf[0] & 0xFF

if __name__ == "__main__":
    print("CH347 Test")
    init()
    read(0x02)
    spi_readId(DevIndex)

3、C#调用

        使用C#比较麻烦的就是需要将头文件重新换格式,但实际上工作量并不是太大,其中结构体需要注意其地址对齐。

using System;

namespace CH347T_Develop
{
    using System.Runtime.InteropServices;
    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Size = 8)]
    public struct mUSB_SETUP_PKT
    {// USB控制传输的建立阶段的数据请求包结构
        [FieldOffset(0)]
        public byte mUspReqType;                // 00H 请求类型
        [FieldOffset(1)]
        public byte mUspRequest;                // 01H 请求代码

        [FieldOffset(2)]
        public byte mUspValueLow;// 02H 值参数低字节
        [FieldOffset(3)]
        public byte mUspValueHigh;              // 03H 值参数高字节
        [FieldOffset(2)]
        public UInt16 mUspValue;                // 02H-03H 值参数

        [FieldOffset(4)]
        public byte mUspIndexLow;// 04H 索引参数低字节
        [FieldOffset(5)]
        public byte mUspIndexHigh;              // 05H 索引参数高字节
        [FieldOffset(4)]
        public UInt16 mUspIndex;                    // 04H-05H 索引参数
        [FieldOffset(6)]
        public UInt16 mLength;// 06H-07H 数据阶段的数据长度
    }

    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
    public struct mWIN32_COMMAND_USB_SETUP_PKT
    {               // 定义WIN32命令接口结构
        [FieldOffset(0)]
        public UInt32 mFunction; // 输入时指定功能代码或者管道号
        [FieldOffset(0)]
        public Int32 mStatus;                    // 输出时返回操作状态
        [FieldOffset(4)]
        public UInt32 mLength;                   // 存取长度,返回后续数据的长度
        [FieldOffset(8)]
        public mUSB_SETUP_PKT mSetupPkt;         // USB控制传输的建立阶段的数据请求
    }

    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
    public struct mWIN32_COMMAND_mBuffer
    {// 定义WIN32命令接口结构
        [FieldOffset(0)]
        public UInt32 mFunction;// 输入时指定功能代码或者管道号
        [FieldOffset(0)]
        public Int32 mStatus;// 输出时返回操作状态
        [FieldOffset(4)]
        public UInt32 mLength;// 存取长度,返回后续数据的长度

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = CH347DLL.mCH341_PACKET_LENGTH), FieldOffset(8)]
        public byte[] mBuffer;                // 数据缓冲区,长度为0至255B
    }
    // 此处可能存在问题,待修改

    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
    public struct DEV_INFOR
    {
        [FieldOffset(0)]
        public byte iIndex;                 // 当前打开序号

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64), FieldOffset(16)]
        public byte[] DevicePath;           // 设备链接名,用于CreateFile

        [FieldOffset(18)]
        public byte UsbClass;               // 0:CH347_USB_CH341, 2:CH347_USB_HID,3:CH347_USB_VCP

        [FieldOffset(19)]
        public byte FuncType;               // 0:CH347_FUNC_UART,1:CH347_FUNC_SPI_I2C,2:CH347_FUNC_JTAG_I2C

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64), FieldOffset(35)]
        public byte[] DeviceID;             // USB\VID_xxxx&PID_xxxx

        [FieldOffset(36)]
        public byte ChipMode;               // 芯片模式,0:Mode0(UART0/1); 1:Mode1(Uart1+SPI+I2C); 2:Mode2(HID Uart1+SPI+I2C) 3:Mode3(Uart1+Jtag+IIC)

        [FieldOffset(0)]
        IntPtr DevHandle;                   // 设备句柄

        [FieldOffset(0)]
        public UInt16 BulkOutEndpMaxSize;     // 上传端点大小

        [FieldOffset(2)]
        public UInt16 BulkInEndpMaxSize;      // 下传端点大小

        [FieldOffset(37)]
        public byte UsbSpeedType;           // USB速度类型,0:FS,1:HS,2:SS

        [FieldOffset(38)]
        public byte CH347IfNum;             // 设备接口号: 0:UART,1:SPI/IIC/JTAG/GPIO

        [FieldOffset(39)]
        public byte DataUpEndp;             // 端点地址

        [FieldOffset(40)]
        public byte DataDnEndp;             // 端点地址

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64), FieldOffset(56)]
        public byte[] ProductString;      // USB产品字符串

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64), FieldOffset(72)]
        public byte[] ManufacturerString; // USB厂商字符串

        [FieldOffset(0)]
        public UInt32 WriteTimeout;           // USB写超时

        [FieldOffset(4)]
        public UInt32 ReadTimeout;            // USB读超时

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64), FieldOffset(88)]
        public byte[] FuncDescStr;        // 接口功能描述符

        [FieldOffset(89)]
        public byte FirewareVer;            // 固件版本
    }

    class CH347DLL
    {
        public const int mCH341_PACKET_LENGTH = 64;

        public byte Index;

        // CH341端点地址
        public const int mCH347_ENDP_DATA_UP = 0x86;// CH347的数据块上传端点的地址
        public const int mCH347_ENDP_DATA_DOWN = 0x06;      // CH347的数据块下传端点的地址

        // 设备层接口提供的管道操作命令
        public const int mPipeDeviceCtrl = 0x00000004;      // CH347的综合控制管道
        public const int mPipeDataUp = 0x00000006;          // CH347的数据块上传管道
        public const int mPipeDataDown = 0x00000007;        // CH347的数据块下传管道

        // 应用层接口的功能代码
        public const int mFuncNoOperation = 0x00000000;     // 无操作
        public const int mFuncGetVersion = 0x00000001;      // 获取驱动程序版本号
        public const int mFuncGetConfig = 0x00000002;       // 获取USB设备配置描述符
        public const int mFuncSetTimeout = 0x00000009;      // 设置USB通讯超时
        public const int mFuncSetExclusive = 0x0000000b;    // 设置独占使用
        public const int mFuncResetDevice = 0x0000000c;     // 复位USB设备
        public const int mFuncResetPipe = 0x0000000d;       // 复位USB管道
        public const int mFuncAbortPipe = 0x0000000e;       // 取消USB管道的数据请求
        public const int mFuncBufferMode = 0x00000020;      // 设定缓冲上传模式及查询缓冲区中的数据长度
        public const int mFuncBufferModeDn = 0x00000021;    // 设定缓冲下传模式及查询缓冲区中的数据长度
        public const int mFuncGetVersionEx = 0x00000022;    // 获取驱动程序版本号及芯片型号
                                                            // USB设备标准请求代码
        public const int mUSB_CLR_FEATURE = 0x01;
        public const int mUSB_SET_FEATURE = 0x03;
        public const int mUSB_GET_STATUS = 0x00;
        public const int mUSB_SET_ADDRESS = 0x05;
        public const int mUSB_GET_DESCR = 0x06;
        public const int mUSB_SET_DESCR = 0x07;
        public const int mUSB_GET_CONFIG = 0x08;
        public const int mUSB_SET_CONFIG = 0x09;
        public const int mUSB_GET_INTERF = 0x0a;
        public const int mUSB_SET_INTERF = 0x0b;
        public const int mUSB_SYNC_FRAME = 0x0c;

        // CH341控制传输的厂商专用请求类型
        public const int mCH341_VENDOR_READ = 0xC0;         // 通过控制传输实现的CH341厂商专用读操作
        public const int mCH341_VENDOR_WRITE = 0x40;        // 通过控制传输实现的CH341厂商专用写操作
        public const int mCH341A_CMD_I2C_STREAM = 0xAA;     // I2C接口的命令包,从次字节开始为I2C命令流
        public const int mCH341A_CMD_UIO_STREAM = 0xAB;     // UIO接口的命令包,从次字节开始为命令流
        public const int mCH341A_CMD_PIO_STREAM = 0xAE;     // PIO接口的命令包,从次字节开始为数据流
                                                            // CH341A控制传输的厂商专用请求代码
        public const int mCH341A_BUF_CLEAR = 0xB2;          // 清除未完成的数据
        public const int mCH341A_I2C_CMD_X = 0x54;          // 发出I2C接口的命令,立即执行
        public const int mCH341A_DELAY_MS = 0x5E;           // 以亳秒为单位延时指定时间
        public const int mCH341A_GET_VER = 0x5F;            // 获取芯片版本

        public const int mCH341A_CMD_I2C_STM_STA = 0x74;    // I2C接口的命令流:产生起始位
        public const int mCH341A_CMD_I2C_STM_STO = 0x75;    // I2C接口的命令流:产生停止位
        public const int mCH341A_CMD_I2C_STM_OUT = 0x80;    // I2C接口的命令流:输出数据,位5-位0为长度,后续字节为数据,0长度则只发送一个字节并返回应答
        public const int mCH341A_CMD_I2C_STM_IN = 0xC0;     // I2C接口的命令流:输入数据,位5-位0为长度,0长度则只接收一个字节并发送无应答
        public const int mCH341A_CMD_I2C_STM_MAX = ((0x3F < mCH341_PACKET_LENGTH) ? 0x3F : mCH341_PACKET_LENGTH);// I2C接口的命令流单个命令输入输出数据的最大长度
        public const int mCH341A_CMD_I2C_STM_SET = 0x60;    // I2C接口的命令流:设置参数,位2=SPI的I/O数(0=单入单出,1=双入双出),位1位0=I2C速度(00=低速,01=标准,10=快速,11=高速)
        public const int mCH341A_CMD_I2C_STM_US = 0x40;     // I2C接口的命令流:以微秒为单位延时,位3-位0为延时值
        public const int mCH341A_CMD_I2C_STM_MS = 0x50;     // I2C接口的命令流:以亳秒为单位延时,位3-位0为延时值
        public const int mCH341A_CMD_I2C_STM_DLY = 0x0F;    // I2C接口的命令流单个命令延时的最大值
        public const int mCH341A_CMD_I2C_STM_END = 0x00;    // I2C接口的命令流:命令包提前结束

        public const int mCH341A_CMD_UIO_STM_IN = 0x00;     // UIO接口的命令流:输入数据D7-D0
        public const int mCH341A_CMD_UIO_STM_DIR = 0x40;    // UIO接口的命令流:设定I/O方向D5-D0,位5-位0为方向数据
        public const int mCH341A_CMD_UIO_STM_OUT = 0x80;    // UIO接口的命令流:输出数据D5-D0,位5-位0为数据
        public const int mCH341A_CMD_UIO_STM_US = 0xC0;     // UIO接口的命令流:以微秒为单位延时,位5-位0为延时值
        public const int mCH341A_CMD_UIO_STM_END = 0x20;    // UIO接口的命令流:命令包提前结束

        public const int MAX_DEVICE_PATH_SIZE = 128;        // 设备名称的最大字符数
        public const int MAX_DEVICE_ID_SIZE = 64;           // 设备ID的最大字符数

        //驱动接口
        public const int CH347_USB_VENDOR = 0;
        public const int CH347_USB_HID = 2;
        public const int CH347_USB_VCP = 3;

        //CH347_USB_VENDOR支持CH341/7
        public const int CHIP_TYPE_CH341 = 0;
        public const int CHIP_TYPE_CH347 = 1;

        //芯片功能接口号
        public const int CH347_FUNC_UART = 0;
        public const int CH347_FUNC_SPI_IIC = 1;
        public const int CH347_FUNC_JTAG_IIC = 2;

        public const int DEFAULT_READ_TIMEOUT = 500;        //默认读超时毫秒数
        public const int DEFAULT_WRITE_TIMEOUT = 500;       //默认写超时毫秒数

        public const int mCH347_PACKET_LENGTH = 512;    // CH347支持的数据包的长度

        private const string CH347_DLL = "CH347DLL.DLL";
        /// <summary>
        /// HANDLE WINAPI CH347OpenDevice(ULONG DevI);
        /// </summary>
        /// <param name="Index"></param>
        /// <returns></returns>
        [DllImport("CH347DLL.DLL", EntryPoint = "CH347OpenDevice")]
        public static extern IntPtr CH347OpenDevice(UInt32 Index);

        [DllImport("CH347DLL.DLL", EntryPoint = "CH347CloseDevice")]
        public static extern IntPtr CH347CloseDevice(UInt32 Index);

        [DllImport("CH347DLL.DLL", EntryPoint = "CH347Uart_Open")]
        public static extern IntPtr CH347Uart_Open(UInt32 Index);

        [DllImport("CH347DLL.DLL", EntryPoint = "CH347Uart_Close")]
        public static extern IntPtr CH347Uart_Close(UInt32 Index);

        [DllImport("CH347DLL.DLL", EntryPoint = "CH347GetDeviceInfor")]
        public static extern IntPtr CH347GetDeviceInfor(UInt32 Index,
            ref DEV_INFOR info);

        [DllImport("CH347DLL.DLL", EntryPoint = "CH347GPIO_Get")]
        public static extern IntPtr CH347GPIO_Get(UInt32 Index,
            ref UInt16 iDir,
            ref UInt16 iData);

        [DllImport("CH347DLL.DLL", EntryPoint = "CH347GPIO_Set")]
        public static extern IntPtr CH347GPIO_Set(UInt32 Index,
            UInt32 iEnable,
            UInt32 iSetDirOut,
            UInt32 iSetDataOut);
    }
}

  • 9
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
Python在Windows下操作CH341DLL I2C通信需要经过以下步骤: 1. 首先,确保已经安装了Python并将其添加到系统环境变量中。 2. 确定已经下载与CH341芯片对应的DLL文件,并将其保存在Python脚本所在的目录。 3. 在Python脚本中,导入ctypes库来调用DLL函数。 ```python import ctypes # 加载CH341DLLch341 = ctypes.WinDLL('CH341DLL.dll') # 定义所需的DLL函数原型 ch341.i2c_init.argtypes = [ctypes.c_ulong] ch341.i2c_init.restype = ctypes.c_int ch341.i2c_start.argtypes = [] ch341.i2c_start.restype = ctypes.c_int ch341.i2c_read.argtypes = [ctypes.c_ubyte, ctypes.POINTER(ctypes.c_ubyte)] ch341.i2c_read.restype = ctypes.c_int ch341.i2c_write.argtypes = [ctypes.c_ubyte, ctypes.POINTER(ctypes.c_ubyte)] ch341.i2c_write.restype = ctypes.c_int ch341.i2c_stop.argtypes = [] ch341.i2c_stop.restype = ctypes.c_int # 初始化I2C通信 ch341.i2c_init(0) # 发送启动信号 ch341.i2c_start() # 读取数据 data = ctypes.c_ubyte() ch341.i2c_read(0x50, ctypes.byref(data)) print("读取到的数据为:", data.value) # 发送数据 send_data = ctypes.c_ubyte(0xFF) ch341.i2c_write(0x50, ctypes.byref(send_data)) # 发送停止信号 ch341.i2c_stop() ``` 此代码片段用于初始化CH341芯片的I2C通信,并实现了读取和写入数据的功能。注意,代码中的`CH341DLL.dll`需要根据实际情况更改为正确的DLL文件名。 这是使用Python在Windows下操作CH341DLL进行I2C通信的基本步骤,根据具体的需求和芯片规格,可能需要进一步的配置和调试。
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值