前言
? ? ? ? CH347為一款USB轉(zhuǎn)JTAG/SPI/IIC/GPIO/UART接口的轉(zhuǎn)換芯片,此處總結(jié)一下開發(fā)時所遇到的在C/C++、Python、C#下調(diào)用CH347DLL的方法,若有其他需要補充的也可一起交流。
? ? ? ? 基于WCH官方Demo板做的代碼驗證。
1、C/C++調(diào)用
? ? ? ? 可參考WCH官網(wǎng)CH347EVT/Tools下工程代碼,此處則不再重復
2、Python調(diào)用
? ? ? ? 選擇Python調(diào)用時,需對應上Python和DLL是否都為32或64位,否則會出現(xiàn)調(diào)用失敗的情況,傳入API參數(shù)時則只需注意一下特殊的結(jié)構(gòu)體此類參函數(shù)即可。文章來源:http://www.zghlxwxcb.cn/news/detail-595054.html
'''
Author: OIDCAT
Date: 2022-07-13 15:22:17
LastEditTime: 2022-08-23 19:19:23
此處需注意Python版本位數(shù)與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#調(diào)用
? ? ? ? 使用C#比較麻煩的就是需要將頭文件重新?lián)Q格式,但實際上工作量并不是太大,其中結(jié)構(gòu)體需要注意其地址對齊。文章來源地址http://www.zghlxwxcb.cn/news/detail-595054.html
using System;
namespace CH347T_Develop
{
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Size = 8)]
public struct mUSB_SETUP_PKT
{// USB控制傳輸?shù)慕㈦A段的數(shù)據(jù)請求包結(jié)構(gòu)
[FieldOffset(0)]
public byte mUspReqType; // 00H 請求類型
[FieldOffset(1)]
public byte mUspRequest; // 01H 請求代碼
[FieldOffset(2)]
public byte mUspValueLow;// 02H 值參數(shù)低字節(jié)
[FieldOffset(3)]
public byte mUspValueHigh; // 03H 值參數(shù)高字節(jié)
[FieldOffset(2)]
public UInt16 mUspValue; // 02H-03H 值參數(shù)
[FieldOffset(4)]
public byte mUspIndexLow;// 04H 索引參數(shù)低字節(jié)
[FieldOffset(5)]
public byte mUspIndexHigh; // 05H 索引參數(shù)高字節(jié)
[FieldOffset(4)]
public UInt16 mUspIndex; // 04H-05H 索引參數(shù)
[FieldOffset(6)]
public UInt16 mLength;// 06H-07H 數(shù)據(jù)階段的數(shù)據(jù)長度
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct mWIN32_COMMAND_USB_SETUP_PKT
{ // 定義WIN32命令接口結(jié)構(gòu)
[FieldOffset(0)]
public UInt32 mFunction; // 輸入時指定功能代碼或者管道號
[FieldOffset(0)]
public Int32 mStatus; // 輸出時返回操作狀態(tài)
[FieldOffset(4)]
public UInt32 mLength; // 存取長度,返回后續(xù)數(shù)據(jù)的長度
[FieldOffset(8)]
public mUSB_SETUP_PKT mSetupPkt; // USB控制傳輸?shù)慕㈦A段的數(shù)據(jù)請求
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct mWIN32_COMMAND_mBuffer
{// 定義WIN32命令接口結(jié)構(gòu)
[FieldOffset(0)]
public UInt32 mFunction;// 輸入時指定功能代碼或者管道號
[FieldOffset(0)]
public Int32 mStatus;// 輸出時返回操作狀態(tài)
[FieldOffset(4)]
public UInt32 mLength;// 存取長度,返回后續(xù)數(shù)據(jù)的長度
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CH347DLL.mCH341_PACKET_LENGTH), FieldOffset(8)]
public byte[] mBuffer; // 數(shù)據(jù)緩沖區(qū),長度為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產(chǎn)品字符串
[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的數(shù)據(jù)塊上傳端點的地址
public const int mCH347_ENDP_DATA_DOWN = 0x06; // CH347的數(shù)據(jù)塊下傳端點的地址
// 設備層接口提供的管道操作命令
public const int mPipeDeviceCtrl = 0x00000004; // CH347的綜合控制管道
public const int mPipeDataUp = 0x00000006; // CH347的數(shù)據(jù)塊上傳管道
public const int mPipeDataDown = 0x00000007; // CH347的數(shù)據(jù)塊下傳管道
// 應用層接口的功能代碼
public const int mFuncNoOperation = 0x00000000; // 無操作
public const int mFuncGetVersion = 0x00000001; // 獲取驅(qū)動程序版本號
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管道的數(shù)據(jù)請求
public const int mFuncBufferMode = 0x00000020; // 設定緩沖上傳模式及查詢緩沖區(qū)中的數(shù)據(jù)長度
public const int mFuncBufferModeDn = 0x00000021; // 設定緩沖下傳模式及查詢緩沖區(qū)中的數(shù)據(jù)長度
public const int mFuncGetVersionEx = 0x00000022; // 獲取驅(qū)動程序版本號及芯片型號
// 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控制傳輸?shù)膹S商專用請求類型
public const int mCH341_VENDOR_READ = 0xC0; // 通過控制傳輸實現(xiàn)的CH341廠商專用讀操作
public const int mCH341_VENDOR_WRITE = 0x40; // 通過控制傳輸實現(xiàn)的CH341廠商專用寫操作
public const int mCH341A_CMD_I2C_STREAM = 0xAA; // I2C接口的命令包,從次字節(jié)開始為I2C命令流
public const int mCH341A_CMD_UIO_STREAM = 0xAB; // UIO接口的命令包,從次字節(jié)開始為命令流
public const int mCH341A_CMD_PIO_STREAM = 0xAE; // PIO接口的命令包,從次字節(jié)開始為數(shù)據(jù)流
// CH341A控制傳輸?shù)膹S商專用請求代碼
public const int mCH341A_BUF_CLEAR = 0xB2; // 清除未完成的數(shù)據(jù)
public const int mCH341A_I2C_CMD_X = 0x54; // 發(fā)出I2C接口的命令,立即執(zhí)行
public const int mCH341A_DELAY_MS = 0x5E; // 以亳秒為單位延時指定時間
public const int mCH341A_GET_VER = 0x5F; // 獲取芯片版本
public const int mCH341A_CMD_I2C_STM_STA = 0x74; // I2C接口的命令流:產(chǎn)生起始位
public const int mCH341A_CMD_I2C_STM_STO = 0x75; // I2C接口的命令流:產(chǎn)生停止位
public const int mCH341A_CMD_I2C_STM_OUT = 0x80; // I2C接口的命令流:輸出數(shù)據(jù),位5-位0為長度,后續(xù)字節(jié)為數(shù)據(jù),0長度則只發(fā)送一個字節(jié)并返回應答
public const int mCH341A_CMD_I2C_STM_IN = 0xC0; // I2C接口的命令流:輸入數(shù)據(jù),位5-位0為長度,0長度則只接收一個字節(jié)并發(fā)送無應答
public const int mCH341A_CMD_I2C_STM_MAX = ((0x3F < mCH341_PACKET_LENGTH) ? 0x3F : mCH341_PACKET_LENGTH);// I2C接口的命令流單個命令輸入輸出數(shù)據(jù)的最大長度
public const int mCH341A_CMD_I2C_STM_SET = 0x60; // I2C接口的命令流:設置參數(shù),位2=SPI的I/O數(shù)(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接口的命令流:命令包提前結(jié)束
public const int mCH341A_CMD_UIO_STM_IN = 0x00; // UIO接口的命令流:輸入數(shù)據(jù)D7-D0
public const int mCH341A_CMD_UIO_STM_DIR = 0x40; // UIO接口的命令流:設定I/O方向D5-D0,位5-位0為方向數(shù)據(jù)
public const int mCH341A_CMD_UIO_STM_OUT = 0x80; // UIO接口的命令流:輸出數(shù)據(jù)D5-D0,位5-位0為數(shù)據(jù)
public const int mCH341A_CMD_UIO_STM_US = 0xC0; // UIO接口的命令流:以微秒為單位延時,位5-位0為延時值
public const int mCH341A_CMD_UIO_STM_END = 0x20; // UIO接口的命令流:命令包提前結(jié)束
public const int MAX_DEVICE_PATH_SIZE = 128; // 設備名稱的最大字符數(shù)
public const int MAX_DEVICE_ID_SIZE = 64; // 設備ID的最大字符數(shù)
//驅(qū)動接口
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; //默認讀超時毫秒數(shù)
public const int DEFAULT_WRITE_TIMEOUT = 500; //默認寫超時毫秒數(shù)
public const int mCH347_PACKET_LENGTH = 512; // CH347支持的數(shù)據(jù)包的長度
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);
}
}
到了這里,關于不同編程語言下CH347DLL的調(diào)用方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!