博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C# 控制CH341进行SPI,I2C读写

Posted on 2019-02-27 11:36  Alvis_Lv  阅读(9695)  评论(6编辑  收藏  举报

之前看了别人是C++ MFC开发的CH341 I2C,SPI读写flash的软件代码,看上去有点头晕,感觉还是使用C# winform开发更人性化些

C#控制需要调用CH341提供的DLL库,网上多数是ch341.dll,我这里使用的是USBIOX.DLL(内容基本上是相同的),有需要的可以到下面网盘地址下载

链接: https://pan.baidu.com/s/1-PafH2pX1A9DvEprGciXRw 提取码: uqdh 

调用类函数:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 using System.Runtime.InteropServices;
  5 
  6 
  7 namespace Burner
  8 {
  9     /* mUSB_SETUP_PKT结构体C++定义如下
 10         typedef    struct    _USB_SETUP_PKT {                // USB控制传输的建立阶段的数据请求包结构
 11         UCHAR            mUspReqType;                // 00H 请求类型
 12         UCHAR            mUspRequest;                // 01H 请求代码
 13         union    {
 14             struct    {
 15                 UCHAR    mUspValueLow;                // 02H 值参数低字节
 16                 UCHAR    mUspValueHigh;                // 03H 值参数高字节
 17             };
 18             USHORT        mUspValue;                    // 02H-03H 值参数
 19         };
 20         union    {
 21             struct    {
 22                 UCHAR    mUspIndexLow;                // 04H 索引参数低字节
 23                 UCHAR    mUspIndexHigh;                // 05H 索引参数高字节
 24             };
 25             USHORT        mUspIndex;                    // 04H-05H 索引参数
 26         };
 27         USHORT            mLength;                    // 06H-07H 数据阶段的数据长度
 28     } mUSB_SETUP_PKT, *mPUSB_SETUP_PKT;
 29     */
 30 
 31     [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Size = 8)]
 32     public struct mUSB_SETUP_PKT
 33     {               // USB控制传输的建立阶段的数据请求包结构
 34         [FieldOffset(0)]
 35         public byte mUspReqType;                // 00H 请求类型
 36         [FieldOffset(1)]
 37         public byte mUspRequest;                // 01H 请求代码
 38 
 39         [FieldOffset(2)]
 40         public byte mUspValueLow;               // 02H 值参数低字节
 41         [FieldOffset(3)]
 42         public byte mUspValueHigh;              // 03H 值参数高字节
 43         [FieldOffset(2)]
 44         public UInt16 mUspValue;                    // 02H-03H 值参数
 45 
 46         [FieldOffset(4)]
 47         public byte mUspIndexLow;               // 04H 索引参数低字节
 48         [FieldOffset(5)]
 49         public byte mUspIndexHigh;              // 05H 索引参数高字节
 50         [FieldOffset(4)]
 51         public UInt16 mUspIndex;                    // 04H-05H 索引参数
 52         [FieldOffset(6)]
 53         public UInt16 mLength;                  // 06H-07H 数据阶段的数据长度
 54     }
 55 
 56 
 57     /*
 58     mWIN32_COMMAND结构体C++定义如下
 59 
 60     typedef    struct    _WIN32_COMMAND {                // 定义WIN32命令接口结构
 61         union    {
 62             ULONG        mFunction;                    // 输入时指定功能代码或者管道号
 63             NTSTATUS    mStatus;                    // 输出时返回操作状态
 64         };
 65         ULONG            mLength;                    // 存取长度,返回后续数据的长度
 66         union    {
 67             mUSB_SETUP_PKT    mSetupPkt;                // USB控制传输的建立阶段的数据请求
 68             UCHAR            mBuffer[ mCH341_PACKET_LENGTH ];    // 数据缓冲区,长度为0至255B
 69         };
 70     } mWIN32_COMMAND, *mPWIN32_COMMAND;
 71 
 72    C#中union功能由FieldOffset()代替
 73 
 74    由于上述结构体中最后一个union可能引起错误“对象字段由一个非对象字段不正确地对齐或重叠”
 75    因此将上述结构体拆分成2个结构体mWIN32_COMMAND_USB_SETUP_PKT与mWIN32_COMMAND_mBuffer,选其一即可。
 76    CH341DriverCommand函数将重载
 77    */
 78 
 79     [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
 80     public struct mWIN32_COMMAND_USB_SETUP_PKT
 81     {               // 定义WIN32命令接口结构
 82         [FieldOffset(0)]
 83         public UInt32 mFunction;                    // 输入时指定功能代码或者管道号
 84         [FieldOffset(0)]
 85         public Int32 mStatus;                   // 输出时返回操作状态
 86         [FieldOffset(4)]
 87         public UInt32 mLength;                  // 存取长度,返回后续数据的长度
 88         [FieldOffset(8)]
 89         public mUSB_SETUP_PKT mSetupPkt;                // USB控制传输的建立阶段的数据请求
 90     }
 91 
 92     [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
 93     public struct mWIN32_COMMAND_mBuffer
 94     {               // 定义WIN32命令接口结构
 95         [FieldOffset(0)]
 96         public UInt32 mFunction;                    // 输入时指定功能代码或者管道号
 97         [FieldOffset(0)]
 98         public Int32 mStatus;                   // 输出时返回操作状态
 99         [FieldOffset(4)]
100         public UInt32 mLength;                  // 存取长度,返回后续数据的长度
101 
102         [MarshalAs(UnmanagedType.ByValArray, SizeConst = USBIOXdll.mCH341_PACKET_LENGTH), FieldOffset(8)]
103         public byte[] mBuffer;  // 数据缓冲区,长度为0至255B
104 
105     }
106 
107 
108     class USBIOXdll
109     {
110         public const int mCH341_PACKET_LENGTH = 32;// CH341支持的数据包的长度
111         public const int mCH341_PKT_LEN_SHORT = 8;//CH341支持的短数据包的长度
112 
113         // WIN32应用层接口命令
114         //public  const int        IOCTL_CH341_COMMAND    =    ( FILE_DEVICE_UNKNOWN << 16 | FILE_ANY_ACCESS << 14 | 0x0f34 << 2 | METHOD_BUFFERED )    // 专用接口
115 
116         // public  const int        mWIN32_COMMAND_HEAD    =    mOFFSET( mWIN32_COMMAND, mBuffer );    // WIN32命令接口的头长度
117 
118         public const int mCH341_MAX_NUMBER = 16;            // 最多同时连接的CH341数
119 
120         public const int mMAX_BUFFER_LENGTH = 0x1000;       // 数据缓冲区最大长度4096
121 
122         //  public  const int        mMAX_COMMAND_LENGTH    =    ( mWIN32_COMMAND_HEAD + mMAX_BUFFER_LENGTH );    // 最大数据长度加上命令结构头的长度
123 
124         public const int mDEFAULT_BUFFER_LEN = 0x0400;      // 数据缓冲区默认长度1024
125 
126         //   public  const int        mDEFAULT_COMMAND_LEN=    ( mWIN32_COMMAND_HEAD + mDEFAULT_BUFFER_LEN );    // 默认数据长度加上命令结构头的长度
127 
128         // CH341端点地址
129         public const int mCH341_ENDP_INTER_UP = 0x81;        // CH341的中断数据上传端点的地址
130         public const int mCH341_ENDP_INTER_DOWN = 0x01;        // CH341的中断数据下传端点的地址
131         public const int mCH341_ENDP_DATA_UP = 0x82;        // CH341的数据块上传端点的地址
132         public const int mCH341_ENDP_DATA_DOWN = 0x02;        // CH341的数据块下传端点的地址
133 
134 
135         // 设备层接口提供的管道操作命令
136         public const int mPipeDeviceCtrl = 0x00000004;    // CH341的综合控制管道
137         public const int mPipeInterUp = 0x00000005;    // CH341的中断数据上传管道
138         public const int mPipeDataUp = 0x00000006;    // CH341的数据块上传管道
139         public const int mPipeDataDown = 0x00000007;    // CH341的数据块下传管道
140 
141         // 应用层接口的功能代码
142         public const int mFuncNoOperation = 0x00000000;    // 无操作
143         public const int mFuncGetVersion = 0x00000001;    // 获取驱动程序版本号
144         public const int mFuncGetConfig = 0x00000002;    // 获取USB设备配置描述符
145         public const int mFuncSetTimeout = 0x00000009;    // 设置USB通讯超时
146         public const int mFuncSetExclusive = 0x0000000b;    // 设置独占使用
147         public const int mFuncResetDevice = 0x0000000c;    // 复位USB设备
148         public const int mFuncResetPipe = 0x0000000d;    // 复位USB管道
149         public const int mFuncAbortPipe = 0x0000000e;    // 取消USB管道的数据请求
150 
151         // CH341并口专用的功能代码
152         public const int mFuncSetParaMode = 0x0000000f;    // 设置并口模式
153         public const int mFuncReadData0 = 0x00000010;    // 从并口读取数据块0
154         public const int mFuncReadData1 = 0x00000011;    // 从并口读取数据块1
155         public const int mFuncWriteData0 = 0x00000012;    // 向并口写入数据块0
156         public const int mFuncWriteData1 = 0x00000013;    // 向并口写入数据块1
157         public const int mFuncWriteRead = 0x00000014;    // 先输出再输入
158         public const int mFuncBufferMode = 0x00000020;    // 设定缓冲上传模式及查询缓冲区中的数据长度
159         public const int FuncBufferModeDn = 0x00000021;    // 设定缓冲下传模式及查询缓冲区中的数据长度
160 
161 
162         // USB设备标准请求代码
163         public const int mUSB_CLR_FEATURE = 0x01;
164         public const int mUSB_SET_FEATURE = 0x03;
165         public const int mUSB_GET_STATUS = 0x00;
166         public const int mUSB_SET_ADDRESS = 0x05;
167         public const int mUSB_GET_DESCR = 0x06;
168         public const int mUSB_SET_DESCR = 0x07;
169         public const int mUSB_GET_CONFIG = 0x08;
170         public const int mUSB_SET_CONFIG = 0x09;
171         public const int mUSB_GET_INTERF = 0x0a;
172         public const int mUSB_SET_INTERF = 0x0b;
173         public const int mUSB_SYNC_FRAME = 0x0c;
174 
175         // CH341控制传输的厂商专用请求类型
176         public const int mCH341_VENDOR_READ = 0xC0;        // 通过控制传输实现的CH341厂商专用读操作
177         public const int mCH341_VENDOR_WRITE = 0x40;        // 通过控制传输实现的CH341厂商专用写操作
178 
179         // CH341控制传输的厂商专用请求代码
180         public const int mCH341_PARA_INIT = 0xB1;    // 初始化并口
181         public const int mCH341_I2C_STATUS = 0x52;        // 获取I2C接口的状态
182         public const int mCH341_I2C_COMMAND = 0x53;        // 发出I2C接口的命令
183 
184         // CH341并口操作命令代码
185         public const int mCH341_PARA_CMD_R0 = 0xAC;        // 从并口读数据0,次字节为长度
186         public const int mCH341_PARA_CMD_R1 = 0xAD;        // 从并口读数据1,次字节为长度
187         public const int mCH341_PARA_CMD_W0 = 0xA6;        // 向并口写数据0,从次字节开始为数据流
188         public const int mCH341_PARA_CMD_W1 = 0xA7;        // 向并口写数据1,从次字节开始为数据流
189         public const int mCH341_PARA_CMD_STS = 0xA0;        // 获取并口状态
190 
191         // CH341A并口操作命令代码
192         public const int mCH341A_CMD_SET_OUTPUT = 0xA1;        // 设置并口输出
193         public const int mCH341A_CMD_IO_ADDR = 0xA2;    // MEM带地址读写/输入输出,从次字节开始为命令流
194         public const int mCH341A_CMD_PRINT_OUT = 0xA3;        // PRINT兼容打印方式输出,从次字节开始为数据流
195         public const int mCH341A_CMD_PWM_OUT = 0xA4;        // PWM数据输出的命令包,从次字节开始为数据流
196         public const int mCH341A_CMD_SHORT_PKT = 0xA5;        // 短包,次字节是该命令包的真正长度,再次字节及之后的字节是原命令包
197         public const int mCH341A_CMD_SPI_STREAM = 0xA8;        // SPI接口的命令包,从次字节开始为数据流
198         //public  const int        mCH341A_CMD_SIO_STREAM    0xA9        // SIO接口的命令包,从次字节开始为数据流
199         public const int mCH341A_CMD_I2C_STREAM = 0xAA;        // I2C接口的命令包,从次字节开始为I2C命令流
200         public const int mCH341A_CMD_UIO_STREAM = 0xAB;        // UIO接口的命令包,从次字节开始为命令流
201         public const int mCH341A_CMD_PIO_STREAM = 0xAE;        // PIO接口的命令包,从次字节开始为数据流
202 
203         // CH341A控制传输的厂商专用请求代码
204         public const int mCH341A_BUF_CLEAR = 0xB2;        // 清除未完成的数据
205         public const int mCH341A_I2C_CMD_X = 0x54;        // 发出I2C接口的命令,立即执行
206         public const int mCH341A_DELAY_MS = 0x5E;        // 以亳秒为单位延时指定时间
207         public const int mCH341A_GET_VER = 0x5F;        // 获取芯片版本
208 
209         public const int mCH341_EPP_IO_MAX = (mCH341_PACKET_LENGTH - 1);    // CH341在EPP/MEM方式下单次读写数据块的最大长度
210         public const int mCH341A_EPP_IO_MAX = 0xFF;        // CH341A在EPP/MEM方式下单次读写数据块的最大长度
211 
212         public const int mCH341A_CMD_IO_ADDR_W = 0x00;        // MEM带地址读写/输入输出的命令流:写数据,位6-位0为地址,下一个字节为待写数据
213         public const int mCH341A_CMD_IO_ADDR_R = 0x80;        // MEM带地址读写/输入输出的命令流:读数据,位6-位0为地址,读出数据一起返回
214 
215         public const int mCH341A_CMD_I2C_STM_STA = 0x74;        // I2C接口的命令流:产生起始位
216         public const int mCH341A_CMD_I2C_STM_STO = 0x75;        // I2C接口的命令流:产生停止位
217         public const int mCH341A_CMD_I2C_STM_OUT = 0x80;        // I2C接口的命令流:输出数据,位5-位0为长度,后续字节为数据,0长度则只发送一个字节并返回应答
218         public const int mCH341A_CMD_I2C_STM_IN = 0xC0;        // I2C接口的命令流:输入数据,位5-位0为长度,0长度则只接收一个字节并发送无应答
219         public const int mCH341A_CMD_I2C_STM_MAX = ((0x3F < mCH341_PACKET_LENGTH) ? 0x3F : mCH341_PACKET_LENGTH);    // I2C接口的命令流单个命令输入输出数据的最大长度
220         public const int mCH341A_CMD_I2C_STM_SET = 0x60;        // I2C接口的命令流:设置参数,位2=SPI的I/O数(0=单入单出,1=双入双出),位1位0=I2C速度(00=低速,01=标准,10=快速,11=高速)
221         public const int mCH341A_CMD_I2C_STM_US = 0x40;        // I2C接口的命令流:以微秒为单位延时,位3-位0为延时值
222         public const int mCH341A_CMD_I2C_STM_MS = 0x50;        // I2C接口的命令流:以亳秒为单位延时,位3-位0为延时值
223         public const int mCH341A_CMD_I2C_STM_DLY = 0x0F;        // I2C接口的命令流单个命令延时的最大值
224         public const int mCH341A_CMD_I2C_STM_END = 0x00;        // I2C接口的命令流:命令包提前结束
225 
226         public const int mCH341A_CMD_UIO_STM_IN = 0x00;        // UIO接口的命令流:输入数据D7-D0
227         public const int mCH341A_CMD_UIO_STM_DIR = 0x40;        // UIO接口的命令流:设定I/O方向D5-D0,位5-位0为方向数据
228         public const int mCH341A_CMD_UIO_STM_OUT = 0x80;    // UIO接口的命令流:输出数据D5-D0,位5-位0为数据
229         public const int mCH341A_CMD_UIO_STM_US = 0xC0;        // UIO接口的命令流:以微秒为单位延时,位5-位0为延时值
230         public const int mCH341A_CMD_UIO_STM_END = 0x20;        // UIO接口的命令流:命令包提前结束
231 
232 
233         // CH341并口工作模式
234         public const int mCH341_PARA_MODE_EPP = 0x00;        // CH341并口工作模式为EPP方式
235         public const int mCH341_PARA_MODE_EPP17 = 0x00;        // CH341A并口工作模式为EPP方式V1.7
236         public const int mCH341_PARA_MODE_EPP19 = 0x01;        // CH341A并口工作模式为EPP方式V1.9
237         public const int mCH341_PARA_MODE_MEM = 0x02;        // CH341并口工作模式为MEM方式
238         public const int mCH341_PARA_MODE_ECP = 0x03;        // CH341A并口工作模式为ECP方式
239 
240 
241         // I/O方向设置位定义,直接输入的状态信号的位定义,直接输出的位数据定义
242         public const int mStateBitERR = 0x00000100;    // 只读可写,ERR#引脚输入状态,1:高电平,0:低电平
243         public const int mStateBitPEMP = 0x00000200;    // 只读可写,PEMP引脚输入状态,1:高电平,0:低电平
244         public const int mStateBitINT = 0x00000400;    // 只读可写,INT#引脚输入状态,1:高电平,0:低电平
245         public const int mStateBitSLCT = 0x00000800;    // 只读可写,SLCT引脚输入状态,1:高电平,0:低电平
246         public const int mStateBitWAIT = 0x00002000;    // 只读可写,WAIT#引脚输入状态,1:高电平,0:低电平
247         public const int mStateBitDATAS = 0x00004000;    // 只写可读,DATAS#/READ#引脚输入状态,1:高电平,0:低电平
248         public const int mStateBitADDRS = 0x00008000;    // 只写可读,ADDRS#/ADDR/ALE引脚输入状态,1:高电平,0:低电平
249         public const int mStateBitRESET = 0x00010000;    // 只写,RESET#引脚输入状态,1:高电平,0:低电平
250         public const int mStateBitWRITE = 0x00020000;    // 只写,WRITE#引脚输入状态,1:高电平,0:低电平
251         public const int mStateBitSCL = 0x00400000;    // 只读,SCL引脚输入状态,1:高电平,0:低电平
252         public const int mStateBitSDA = 0x00800000;    // 只读,SDA引脚输入状态,1:高电平,0:低电平
253 
254 
255         public const int MAX_DEVICE_PATH_SIZE = 128;            // 设备名称的最大字符数
256         public const int MAX_DEVICE_ID_SIZE = 64;            // 设备ID的最大字符数
257 
258         /*
259          typedef        VOID    ( CALLBACK    * mPCH341_INT_ROUTINE ) (  // 中断服务程序
260          ULONG            iStatus );  // 中断状态数据,参考下面的位说明
261         // 位7-位0对应CH341的D7-D0引脚
262         // 位8对应CH341的ERR#引脚, 位9对应CH341的PEMP引脚, 位10对应CH341的INT#引脚, 位11对应CH341的SLCT引脚
263         */
264         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
265         public delegate void mPCH341_INT_ROUTINE(// 中断服务程序
266                                                 UInt32 iStatus);// 中断状态数据,参考下面的位说明
267         // 位7-位0对应CH341的D7-D0引脚
268         // 位8对应CH341的ERR#引脚, 位9对应CH341的PEMP引脚, 位10对应CH341的INT#引脚, 位11对应CH341的SLCT引脚
269 
270         public const int USBIO_DEVICE_ARRIVAL = 3;  // 设备插入事件,已经插入
271         public const int USBIO_DEVICE_REMOVE_PEND = 1;      // 设备将要拔出
272         public const int USBIO_DEVICE_REMOVE = 0;   // 设备拔出事件,已经拔出
273 
274         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_OpenDevice")]
275         public static extern IntPtr USBIO_OpenDevice(  // 打开CH341设备,返回句柄,出错则无效
276                                      UInt32 iIndex);  // 指定CH341设备序号,0对应第一个设备
277 
278         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_CloseDevice")]
279         public static extern void USBIO_CloseDevice(  // 关闭CH341设备
280                                       UInt32 iIndex);  // 指定CH341设备序号
281 
282         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_GetVersion")]
283         public static extern UInt32 USBIO_GetVersion();  // 获得DLL版本号,返回版本号
284 
285         //函数重载
286         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_DriverCommand")]
287         public static extern UInt32 USBIO_DriverCommand(  // 直接传递命令给驱动程序,出错则返回0,否则返回数据长度
288                                 UInt32 iIndex,  // 指定CH341设备序号,V1.6以上DLL也可以是设备打开后的句柄
289                                  ref mWIN32_COMMAND_mBuffer ioCommand);  // 命令结构的指针
290 
291 
292 
293         [DllImport("USBIOX.DLL", EntryPoint= "USBIO_DriverCommand")]
294         public static extern UInt32 USBIO_DriverCommand(  // 直接传递命令给驱动程序,出错则返回0,否则返回数据长度
295                                 UInt32 iIndex,  // 指定CH341设备序号,V1.6以上DLL也可以是设备打开后的句柄
296                                  ref mWIN32_COMMAND_USB_SETUP_PKT ioCommand);  // 命令结构的指针
297         // 该程序在调用后返回数据长度,并且仍然返回命令结构,如果是读操作,则数据返回在命令结构中,
298         // 返回的数据长度在操作失败时为0,操作成功时为整个命令结构的长度,例如读一个字节,则返回mWIN32_COMMAND_HEAD+1,
299         // 命令结构在调用前,分别提供:管道号或者命令功能代码,存取数据的长度(可选),数据(可选)
300         // 命令结构在调用后,分别返回:操作状态代码,后续数据的长度(可选),
301         //   操作状态代码是由WINDOWS定义的代码,可以参考NTSTATUS.H,
302         //   后续数据的长度是指读操作返回的数据长度,数据存放在随后的缓冲区中,对于写操作一般为0
303 
304         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_GetDrvVersion")]
305         public static extern UInt32 USBIO_GetDrvVersion();  // 获得驱动程序版本号,返回版本号,出错则返回0
306 
307         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_ResetDevice")]
308         public static extern bool USBIO_ResetDevice(  // 复位USB设备
309                              UInt32 iIndex);  // 指定CH341设备序号
310 
311         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_GetDeviceDescr")]
312         public static extern bool USBIO_GetDeviceDescr(  // 读取设备描述符
313             UInt32 iIndex,  // 指定CH341设备序号
314             byte[] oBuffer,  // 指向一个足够大的缓冲区,用于保存描述符
315             ref UInt32 ioLength);  // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度
316 
317         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_GetConfigDescr")]
318         public static extern bool USBIO_GetConfigDescr(  // 读取配置描述符
319             UInt32 iIndex,  // 指定CH341设备序号
320             byte[] oBuffer,  // 指向一个足够大的缓冲区,用于保存描述符
321             ref UInt32 ioLength);  // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度
322 
323         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_SetIntRoutine")]
324         public static extern bool USBIO_SetIntRoutine(  // 设定中断服务程序
325             UInt32 iIndex,  // 指定CH341设备序号
326             mPCH341_INT_ROUTINE iIntRoutine);  // 指定中断服务程序,为NULL则取消中断服务,否则在中断时调用该程序
327 
328         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_ReadInter")]
329         public static extern bool USBIO_ReadInter(  // 读取中断数据
330             UInt32 iIndex,  // 指定CH341设备序号
331             ref UInt32 iStatus);  // 指向一个双字单元,用于保存读取的中断状态数据,见下行
332         // 位7-位0对应CH341的D7-D0引脚
333         // 位8对应CH341的ERR#引脚, 位9对应CH341的PEMP引脚, 位10对应CH341的INT#引脚, 位11对应CH341的SLCT引脚
334 
335 
336         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_AbortInter")]
337         public static extern bool USBIO_AbortInter(  // 放弃中断数据读操作
338             UInt32 iIndex);  // 指定CH341设备序号
339 
340         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_SetParaMode")]
341         public static extern bool USBIO_SetParaMode(  // 设置并口模式
342             UInt32 iIndex,  // 指定CH341设备序号
343             UInt32 iMode);  // 指定并口模式: 0为EPP模式/EPP模式V1.7, 1为EPP模式V1.9, 2为MEM模式
344 
345         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_InitParallel")]
346         public static extern bool USBIO_InitParallel(  // 复位并初始化并口,RST#输出低电平脉冲
347             UInt32 iIndex,  // 指定CH341设备序号
348             UInt32 iMode);  // 指定并口模式: 0为EPP模式/EPP模式V1.7, 1为EPP模式V1.9, 2为MEM模式, >= 0x00000100 保持当前模式
349 
350         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_ReadData0")]
351         public static extern bool USBIO_ReadData0(  // 从0#端口读取数据块
352             UInt32 iIndex,  // 指定CH341设备序号
353             byte[] oBuffer,  // 指向一个足够大的缓冲区,用于保存读取的数据
354             ref UInt32 ioLength);  // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度
355 
356         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_ReadData1")]
357         public static extern bool USBIO_ReadData1(  // 从1#端口读取数据块
358             UInt32 iIndex,  // 指定CH341设备序号
359             byte[] oBuffer,  // 指向一个足够大的缓冲区,用于保存读取的数据
360             ref UInt32 ioLength);  // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度
361 
362         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_AbortRead")]
363         public static extern bool USBIO_AbortRead(  // 放弃数据块读操作
364             UInt32 iIndex);  // 指定CH341设备序号
365 
366         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_WriteData0")]
367         public static extern bool USBIO_WriteData0(  // 向0#端口写出数据块
368             UInt32 iIndex,  // 指定CH341设备序号
369             byte[] iBuffer,  // 指向一个缓冲区,放置准备写出的数据
370             ref UInt32 ioLength);  // 指向长度单元,输入时为准备写出的长度,返回后为实际写出的长度
371 
372         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_WriteData1")]
373         public static extern bool USBIO_WriteData1(  // 向1#端口写出数据块
374             UInt32 iIndex,  // 指定CH341设备序号
375             byte[] iBuffer,  // 指向一个缓冲区,放置准备写出的数据
376             ref UInt32 ioLength);  // 指向长度单元,输入时为准备写出的长度,返回后为实际写出的长度
377 
378         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_AbortWrite")]
379         public static extern bool USBIO_AbortWrite(  // 放弃数据块写操作
380             UInt32 iIndex);  // 指定CH341设备序号
381 
382         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_GetStatus")]
383         public static extern bool USBIO_GetStatus(  // 通过CH341直接输入数据和状态
384             UInt32 iIndex,  // 指定CH341设备序号
385             ref UInt32 iStatus);  // 指向一个双字单元,用于保存状态数据,参考下面的位说明
386         // 位7-位0对应CH341的D7-D0引脚
387         // 位8对应CH341的ERR#引脚, 位9对应CH341的PEMP引脚, 位10对应CH341的INT#引脚, 位11对应CH341的SLCT引脚, 位23对应CH341的SDA引脚
388         // 位13对应CH341的BUSY/WAIT#引脚, 位14对应CH341的AUTOFD#/DATAS#引脚,位15对应CH341的SLCTIN#/ADDRS#引脚
389 
390         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_ReadI2C")]
391         public static extern bool USBIO_ReadI2C(  // 从I2C接口读取一个字节数据
392             UInt32 iIndex,  // 指定CH341设备序号
393             byte iDevice,  // 低7位指定I2C设备地址
394             byte iAddr,  // 指定数据单元的地址
395             ref byte oByte);  // 指向一个字节单元,用于保存读取的字节数据
396 
397         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_WriteI2C")]
398         public static extern bool USBIO_WriteI2C(  // 向I2C接口写入一个字节数据
399             UInt32 iIndex,  // 指定CH341设备序号
400             byte iDevice,  // 低7位指定I2C设备地址
401             byte iAddr,  // 指定数据单元的地址
402             byte iByte);  // 待写入的字节数据
403 
404         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_EppReadData")]
405         public static extern bool USBIO_EppReadData(  // EPP方式读数据: WR#=1, DS#=0, AS#=1, D0-D7=input
406             UInt32 iIndex,  // 指定CH341设备序号
407             byte[] oBuffer,  // 指向一个足够大的缓冲区,用于保存读取的数据
408             ref UInt32 ioLength);  // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度
409 
410         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_EppReadAddr")]
411         public static extern bool USBIO_EppReadAddr(  // EPP方式读地址: WR#=1, DS#=1, AS#=0, D0-D7=input
412             UInt32 iIndex,  // 指定CH341设备序号
413             byte[] oBuffer,  // 指向一个足够大的缓冲区,用于保存读取的地址数据
414             ref UInt32 ioLength);  // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度
415 
416         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_EppWriteData")]
417         public static extern bool USBIO_EppWriteData(  // EPP方式写数据: WR#=0, DS#=0, AS#=1, D0-D7=output
418             UInt32 iIndex,  // 指定CH341设备序号
419             byte[] iBuffer,  // 指向一个缓冲区,放置准备写出的数据
420             ref UInt32 ioLength);  // 指向长度单元,输入时为准备写出的长度,返回后为实际写出的长度
421 
422         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_EppWriteAddr")]
423         public static extern bool USBIO_EppWriteAddr(  // EPP方式写地址: WR#=0, DS#=1, AS#=0, D0-D7=output
424             UInt32 iIndex,  // 指定CH341设备序号
425             byte[] iBuffer,  // 指向一个缓冲区,放置准备写出的地址数据
426             ref UInt32 ioLength);  // 指向长度单元,输入时为准备写出的长度,返回后为实际写出的长度
427 
428         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_EppSetAddr")]
429         public static extern bool USBIO_EppSetAddr(  // EPP方式设置地址: WR#=0, DS#=1, AS#=0, D0-D7=output
430             UInt32 iIndex,  // 指定CH341设备序号
431             byte iAddr);  // 指定EPP地址
432 
433         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_MemReadAddr0")]
434         public static extern bool USBIO_MemReadAddr0(  // MEM方式读地址0: WR#=1, DS#/RD#=0, AS#/ADDR=0, D0-D7=input
435             UInt32 iIndex,  // 指定CH341设备序号
436             byte[] oBuffer,  // 指向一个足够大的缓冲区,用于保存从地址0读取的数据
437             ref UInt32 ioLength);  // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度
438 
439         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_MemReadAddr1")]
440         public static extern bool USBIO_MemReadAddr1(  // MEM方式读地址1: WR#=1, DS#/RD#=0, AS#/ADDR=1, D0-D7=input
441             UInt32 iIndex,  // 指定CH341设备序号
442             byte[] oBuffer,  // 指向一个足够大的缓冲区,用于保存从地址1读取的数据
443             ref UInt32 ioLength);  // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度
444 
445         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_MemWriteAddr0")]
446         public static extern bool USBIO_MemWriteAddr0(  // MEM方式写地址0: WR#=0, DS#/RD#=1, AS#/ADDR=0, D0-D7=output
447             UInt32 iIndex,  // 指定CH341设备序号
448             byte[] iBuffer,  // 指向一个缓冲区,放置准备向地址0写出的数据
449             ref UInt32 ioLength);  // 指向长度单元,输入时为准备写出的长度,返回后为实际写出的长度
450 
451         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_MemWriteAddr1")]
452         public static extern bool USBIO_MemWriteAddr1(  // MEM方式写地址1: WR#=0, DS#/RD#=1, AS#/ADDR=1, D0-D7=output
453             UInt32 iIndex,  // 指定CH341设备序号
454             byte[] iBuffer,  // 指向一个缓冲区,放置准备向地址1写出的数据
455             ref UInt32 ioLength);  // 指向长度单元,输入时为准备写出的长度,返回后为实际写出的长度
456 
457         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_SetExclusive")]
458         public static extern bool USBIO_SetExclusive(  // 设置独占使用当前CH341设备
459             UInt32 iIndex,  // 指定CH341设备序号
460             UInt32 iExclusive);  // 为0则设备可以共享使用,非0则独占使用
461 
462         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_SetTimeout")]
463         public static extern bool USBIO_SetTimeout(  // 设置USB数据读写的超时
464             UInt32 iIndex,  // 指定CH341设备序号
465             UInt32 iWriteTimeout,  // 指定USB写出数据块的超时时间,以毫秒mS为单位,0xFFFFFFFF指定不超时(默认值)
466             UInt32 iReadTimeout);  // 指定USB读取数据块的超时时间,以毫秒mS为单位,0xFFFFFFFF指定不超时(默认值)
467 
468         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_ReadData")]
469         public static extern bool USBIO_ReadData(  // 读取数据块
470             UInt32 iIndex,  // 指定CH341设备序号
471             byte[] oBuffer,  // 指向一个足够大的缓冲区,用于保存读取的数据
472             ref UInt32 ioLength);  // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度
473 
474         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_WriteData")]
475         public static extern bool USBIO_WriteData(  // 写出数据块
476             UInt32 iIndex,  // 指定CH341设备序号
477             byte[] iBuffer,  // 指向一个缓冲区,放置准备写出的数据
478             ref UInt32 ioLength);  // 指向长度单元,输入时为准备写出的长度,返回后为实际写出的长度
479 
480         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_GetDeviceName")]
481         public static extern IntPtr USBIO_GetDeviceName(  // 返回指向CH341设备名称的缓冲区,出错则返回NULL
482             UInt32 iIndex);  // 指定CH341设备序号,0对应第一个设备
483 
484         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_GetVerIC")]
485         public static extern UInt32 USBIO_GetVerIC(  // 获取CH341芯片的版本,返回:0=设备无效,0x10=CH341,0x20=CH341A
486             UInt32 iIndex);  // 指定CH341设备序号
487 
488         public const int IC_VER_CH341A = 0x20;
489         public const int IC_VER_CH341A3 = 0x30;
490 
491         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_FlushBuffer")]
492         public static extern bool USBIO_FlushBuffer(  // 清空CH341的缓冲区
493             UInt32 iIndex);  // 指定CH341设备序号
494 
495         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_WriteRead")]
496         public static extern bool USBIO_WriteRead(  // 执行数据流命令,先输出再输入
497             UInt32 iIndex,  // 指定CH341设备序号
498             UInt32 iWriteLength,  // 写长度,准备写出的长度
499             byte[] iWriteBuffer,  // 指向一个缓冲区,放置准备写出的数据
500             UInt32 iReadStep,  // 准备读取的单个块的长度, 准备读取的总长度为(iReadStep*iReadTimes)
501             UInt32 iReadTimes,  // 准备读取的次数
502             ref UInt32 oReadLength,  // 指向长度单元,返回后为实际读取的长度
503             byte[] oReadBuffer);  // 指向一个足够大的缓冲区,用于保存读取的数据
504 
505         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_SetStream")]
506         public static extern bool USBIO_SetStream(  // 设置串口流模式
507             UInt32 iIndex,  // 指定CH341设备序号
508             UInt32 iMode);  // 指定模式,见下行
509         // 位1-位0: I2C接口速度/SCL频率, 00=低速/20KHz,01=标准/100KHz(默认值),10=快速/400KHz,11=高速/750KHz
510         // 位2:     SPI的I/O数/IO引脚, 0=单入单出(D3时钟/D5出/D7入)(默认值),1=双入双出(D3时钟/D5出D4出/D7入D6入)
511         // 位7:     SPI字节中的位顺序, 0=低位在前, 1=高位在前
512         // 其它保留,必须为0
513 
514         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_SetDelaymS")]
515         public static extern bool USBIO_SetDelaymS(  // 设置硬件异步延时,调用后很快返回,而在下一个流操作之前延时指定毫秒数
516             UInt32 iIndex,  // 指定CH341设备序号
517             UInt32 iDelay);  // 指定延时的毫秒数
518 
519         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_StreamI2C")]
520         public static extern bool USBIO_StreamI2C(  // 处理I2C数据流,2线接口,时钟线为SCL引脚,数据线为SDA引脚(准双向I/O),速度约56K字节
521             UInt32 iIndex,  // 指定CH341设备序号
522             UInt32 iWriteLength,  // 准备写出的数据字节数
523             byte[] iWriteBuffer,  // 指向一个缓冲区,放置准备写出的数据,首字节通常是I2C设备地址及读写方向位
524             UInt32 iReadLength,  // 准备读取的数据字节数
525             byte[] oReadBuffer);  // 指向一个缓冲区,返回后是读入的数据
526 
527         public enum EEPROM_TYPE         // EEPROM型号
528         {
529             ID_24C01,
530             ID_24C02,
531             ID_24C04,
532             ID_24C08,
533             ID_24C16,
534             ID_24C32,
535             ID_24C64,
536             ID_24C128,
537             ID_24C256,
538             ID_24C512,
539             ID_24C1024,
540             ID_24C2048,
541             ID_24C4096
542 
543         };
544 
545         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_ReadEEPROM")]
546         public static extern bool USBIO_ReadEEPROM(  // 从EEPROM中读取数据块,速度约56K字节
547             UInt32 iIndex,  // 指定CH341设备序号
548             EEPROM_TYPE iEepromID,  // 指定EEPROM型号
549             UInt32 iAddr,  // 指定数据单元的地址
550             UInt32 iLength,  // 准备读取的数据字节数
551             byte[] oBuffer);  // 指向一个缓冲区,返回后是读入的数据
552 
553         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_WriteEEPROM")]
554         public static extern bool USBIO_WriteEEPROM(  // 向EEPROM中写入数据块
555             UInt32 iIndex,  // 指定CH341设备序号
556             EEPROM_TYPE iEepromID,  // 指定EEPROM型号
557             UInt32 iAddr,  // 指定数据单元的地址
558             UInt32 iLength,  // 准备写出的数据字节数
559             byte[] iBuffer);  // 指向一个缓冲区,放置准备写出的数据
560 
561         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_GetInput")]
562         public static extern bool USBIO_GetInput(  // 通过CH341直接输入数据和状态,效率比CH341GetStatus更高
563             UInt32 iIndex,  // 指定CH341设备序号
564             ref UInt32 iStatus);  // 指向一个双字单元,用于保存状态数据,参考下面的位说明
565         // 位7-位0对应CH341的D7-D0引脚
566         // 位8对应CH341的ERR#引脚, 位9对应CH341的PEMP引脚, 位10对应CH341的INT#引脚, 位11对应CH341的SLCT引脚, 位23对应CH341的SDA引脚
567         // 位13对应CH341的BUSY/WAIT#引脚, 位14对应CH341的AUTOFD#/DATAS#引脚,位15对应CH341的SLCTIN#/ADDRS#引脚
568 
569         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_SetOutput")]
570         public static extern bool USBIO_SetOutput(  // 设置CH341的I/O方向,并通过CH341直接输出数据
571                                                    /* ***** 谨慎使用该API, 防止修改I/O方向使输入引脚变为输出引脚导致与其它输出引脚之间短路而损坏芯片 ***** */
572             UInt32 iIndex,  // 指定CH341设备序号
573             UInt32 iEnable,  // 数据有效标志,参考下面的位说明
574                              // 位0为1说明iSetDataOut的位15-位8有效,否则忽略
575                              // 位1为1说明iSetDirOut的位15-位8有效,否则忽略
576                              // 位2为1说明iSetDataOut的7-位0有效,否则忽略
577                              // 位3为1说明iSetDirOut的位7-位0有效,否则忽略
578                              // 位4为1说明iSetDataOut的位23-位16有效,否则忽略
579             UInt32 iSetDirOut,  // 设置I/O方向,某位清0则对应引脚为输入,某位置1则对应引脚为输出,并口方式下默认值为0x000FC000,参考下面的位说明
580             UInt32 iSetDataOut);  // 输出数据,如果I/O方向为输出,那么某位清0时对应引脚输出低电平,某位置1时对应引脚输出高电平,参考下面的位说明
581         // 位7-位0对应CH341的D7-D0引脚
582         // 位8对应CH341的ERR#引脚, 位9对应CH341的PEMP引脚, 位10对应CH341的INT#引脚, 位11对应CH341的SLCT引脚
583         // 位13对应CH341的WAIT#引脚, 位14对应CH341的DATAS#/READ#引脚,位15对应CH341的ADDRS#/ADDR/ALE引脚
584         // 以下引脚只能输出,不考虑I/O方向: 位16对应CH341的RESET#引脚, 位17对应CH341的WRITE#引脚, 位18对应CH341的SCL引脚, 位29对应CH341的SDA引脚
585 
586         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_Set_D5_D0")]
587         public static extern bool USBIO_Set_D5_D0(  // 设置CH341的D5-D0引脚的I/O方向,并通过CH341的D5-D0引脚直接输出数据,效率比CH341SetOutput更高
588                                                    /* ***** 谨慎使用该API, 防止修改I/O方向使输入引脚变为输出引脚导致与其它输出引脚之间短路而损坏芯片 ***** */
589             UInt32 iIndex,  // 指定CH341设备序号
590             UInt32 iSetDirOut,  // 设置D5-D0各引脚的I/O方向,某位清0则对应引脚为输入,某位置1则对应引脚为输出,并口方式下默认值为0x00全部输入
591             UInt32 iSetDataOut);  // 设置D5-D0各引脚的输出数据,如果I/O方向为输出,那么某位清0时对应引脚输出低电平,某位置1时对应引脚输出高电平
592         // 以上数据的位5-位0分别对应CH341的D5-D0引脚
593 
594         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_StreamSPI3")]
595         public static extern bool USBIO_StreamSPI3(  // 该API已失效,请勿使用
596             UInt32 iIndex,
597             UInt32 iChipSelect,
598             UInt32 iLength,
599             byte[] ioBuffer);
600 
601         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_StreamSPI4")]
602         public static extern bool USBIO_StreamSPI4(  // 处理SPI数据流,4线接口,时钟线为DCK/D3引脚,输出数据线为DOUT/D5引脚,输入数据线为DIN/D7引脚,片选线为D0/D1/D2,速度约68K字节
603                                                     /* SPI时序: DCK/D3引脚为时钟输出, 默认为低电平, DOUT/D5引脚在时钟上升沿之前的低电平期间输出, DIN/D7引脚在时钟下降沿之前的高电平期间输入 */
604             UInt32 iIndex,  // 指定CH341设备序号
605             UInt32 iChipSelect,  // 片选控制, 位7为0则忽略片选控制, 位7为1则参数有效: 位1位0为00/01/10分别选择D0/D1/D2引脚作为低电平有效片选
606             UInt32 iLength,  // 准备传输的数据字节数
607             byte[] ioBuffer);  // 指向一个缓冲区,放置准备从DOUT写出的数据,返回后是从DIN读入的数据
608 
609         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_StreamSPI5")]
610         public static extern bool USBIO_StreamSPI5(  // 处理SPI数据流,5线接口,时钟线为DCK/D3引脚,输出数据线为DOUT/D5和DOUT2/D4引脚,输入数据线为DIN/D7和DIN2/D6引脚,片选线为D0/D1/D2,速度约30K字节*2
611                                                     /* SPI时序: DCK/D3引脚为时钟输出, 默认为低电平, DOUT/D5和DOUT2/D4引脚在时钟上升沿之前的低电平期间输出, DIN/D7和DIN2/D6引脚在时钟下降沿之前的高电平期间输入 */
612             UInt32 iIndex,  // 指定CH341设备序号
613             UInt32 iChipSelect,  // 片选控制, 位7为0则忽略片选控制, 位7为1则参数有效: 位1位0为00/01/10分别选择D0/D1/D2引脚作为低电平有效片选
614             UInt32 iLength,  // 准备传输的数据字节数
615             byte[] ioBuffer,  // 指向一个缓冲区,放置准备从DOUT写出的数据,返回后是从DIN读入的数据
616             byte[] ioBuffer2);  // 指向第二个缓冲区,放置准备从DOUT2写出的数据,返回后是从DIN2读入的数据
617 
618         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_BitStreamSPI")]
619         public static extern bool USBIO_BitStreamSPI(  // 处理SPI位数据流,4线/5线接口,时钟线为DCK/D3引脚,输出数据线为DOUT/DOUT2引脚,输入数据线为DIN/DIN2引脚,片选线为D0/D1/D2,速度约8K位*2
620             UInt32 iIndex,  // 指定CH341设备序号
621             UInt32 iLength,  // 准备传输的数据位数,一次最多896,建议不超过256
622             byte[] ioBuffer);  // 指向一个缓冲区,放置准备从DOUT/DOUT2/D2-D0写出的数据,返回后是从DIN/DIN2读入的数据
623         /* SPI时序: DCK/D3引脚为时钟输出, 默认为低电平, DOUT/D5和DOUT2/D4引脚在时钟上升沿之前的低电平期间输出, DIN/D7和DIN2/D6引脚在时钟下降沿之前的高电平期间输入 */
624         /* ioBuffer中的一个字节共8位分别对应D7-D0引脚, 位5输出到DOUT, 位4输出到DOUT2, 位2-位0输出到D2-D0, 位7从DIN输入, 位6从DIN2输入, 位3数据忽略 */
625         /* 在调用该API之前,应该先调用CH341Set_D5_D0设置CH341的D5-D0引脚的I/O方向,并设置引脚的默认电平 */
626 
627         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_SetBufUpload")]
628         public static extern bool USBIO_SetBufUpload(  // 设定内部缓冲上传模式
629             UInt32 iIndex,  // 指定CH341设备序号,0对应第一个设备
630             UInt32 iEnableOrClear);  // 为0则禁止内部缓冲上传模式,使用直接上传,非0则启用内部缓冲上传模式并清除缓冲区中的已有数据
631         // 如果启用内部缓冲上传模式,那么CH341驱动程序创建线程自动接收USB上传数据到内部缓冲区,同时清除缓冲区中的已有数据,当应用程序调用CH341ReadData后将立即返回缓冲区中的已有数据
632 
633         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_QueryBufUpload")]
634         public static extern Int32 USBIO_QueryBufUpload(  // 查询内部上传缓冲区中的已有数据包个数,成功返回数据包个数,出错返回-1
635             UInt32 iIndex);  // 指定CH341设备序号,0对应第一个设备
636 
637         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_SetBufDownload")]
638         public static extern bool USBIO_SetBufDownload(  // 设定内部缓冲下传模式
639             UInt32 iIndex,  // 指定CH341设备序号,0对应第一个设备
640             UInt32 iEnableOrClear);  // 为0则禁止内部缓冲下传模式,使用直接下传,非0则启用内部缓冲下传模式并清除缓冲区中的已有数据
641         // 如果启用内部缓冲下传模式,那么当应用程序调用CH341WriteData后将仅仅是将USB下传数据放到内部缓冲区并立即返回,而由CH341驱动程序创建的线程自动发送直到完毕
642 
643         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_QueryBufDownload")]
644         public static extern Int32 USBIO_QueryBufDownload(  // 查询内部下传缓冲区中的剩余数据包个数(尚未发送),成功返回数据包个数,出错返回-1
645             UInt32 iIndex);  // 指定CH341设备序号,0对应第一个设备
646 
647         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_ResetInter")]
648         public static extern bool USBIO_ResetInter(  // 复位中断数据读操作
649             UInt32 iIndex);  // 指定CH341设备序号
650 
651         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_ResetRead")]
652         public static extern bool USBIO_ResetRead(  // 复位数据块读操作
653             UInt32 iIndex);  // 指定CH341设备序号
654 
655         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_ResetWrite")]
656         public static extern bool USBIO_ResetWrite(  // 复位数据块写操作
657             UInt32 iIndex);  // 指定CH341设备序号
658 
659         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
660 
661         public delegate void mPCH341_NOTIFY_ROUTINE(  // 设备事件通知回调程序
662                     UInt32 iEventStatus);  // 设备事件和当前状态(在下行定义): 0=设备拔出事件, 3=设备插入事件
663 
664 
665         public const int CH341_DEVICE_ARRIVA = 3;    // 设备插入事件,已经插入
666         public const int CH341_DEVICE_REMOVE_PEND = 1;        // 设备将要拔出
667         public const int CH341_DEVICE_REMOVE = 0;        // 设备拔出事件,已经拔出
668 
669         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_SetDeviceNotify")]
670         public static extern bool USBIO_SetDeviceNotify(  // 设定设备事件通知程序
671             UInt32 iIndex,  // 指定CH341设备序号,0对应第一个设备
672             string iDeviceID,  // 可选参数,指向字符串,指定被监控的设备的ID,字符串以\0终止
673             mPCH341_NOTIFY_ROUTINE iNotifyRoutine);  // 指定设备事件回调程序,为NULL则取消事件通知,否则在检测到事件时调用该程序
674 
675         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_SetupSerial")]
676         public static extern bool USBIO_SetupSerial(  // 设定CH341的串口特性,该API只能用于工作于串口方式的CH341芯片
677             UInt32 iIndex,  // 指定CH341设备序号,0对应第一个设备
678             UInt32 iParityMode,  // 指定CH341串口的数据校验模式: NOPARITY/ODDPARITY/EVENPARITY/MARKPARITY/SPACEPARITY
679             UInt32 iBaudRate);  // 指定CH341串口的通讯波特率值,可以是50至3000000之间的任意值
680 
681         /*  以下API可以用于工作于串口方式的CH341芯片,除此之外的API一般只能用于并口方式的CH341芯片
682             CH341OpenDevice
683             CH341CloseDevice
684             CH341SetupSerial
685             CH341ReadData
686             CH341WriteData
687             CH341SetBufUpload
688             CH341QueryBufUpload
689             CH341SetBufDownload
690             CH341QueryBufDownload
691             CH341SetDeviceNotify
692             CH341GetStatus
693         //  以上是主要API,以下是次要API
694             CH341GetVersion
695             CH341DriverCommand
696             CH341GetDrvVersion
697             CH341ResetDevice
698             CH341GetDeviceDescr
699             CH341GetConfigDescr
700             CH341SetIntRoutine
701             CH341ReadInter
702             CH341AbortInter
703             CH341AbortRead
704             CH341AbortWrite
705             CH341ReadI2C
706             CH341WriteI2C
707             CH341SetExclusive
708             CH341SetTimeout
709             CH341GetDeviceName
710             CH341GetVerIC
711             CH341FlushBuffer
712             CH341WriteRead
713             CH341ResetInter
714             CH341ResetRead
715             CH341ResetWrite
716         */
717         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_OpenDeviceEx")]
718         public static extern IntPtr USBIO_OpenDeviceEx(   // 打开CH341设备,返回句柄,出错则无效
719             UInt32 iIndex);        // 指定CH341设备序号,0对应插入的第一个设备,1对应插入的第二个设备,为节约设备设备序号资源,用完后要关闭设备
720 
721         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_CloseDeviceEx")]
722         public static extern void USBIO_CloseDeviceEx(  // 关闭CH341设备
723             UInt32 iIndex);        // 指定CH341设备序号
724 
725         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_GetDeviceNameEx")]
726         public static extern IntPtr USBIO_GetDeviceNameEx(   // 返回指向CH341设备名称的缓冲区,出错则返回NULL
727             UInt32 iIndex);           // 指定CH341设备序号,0对应第一个设备
728 
729         [DllImport("USBIOX.DLL", EntryPoint = "USBIO_SetDeviceNotifyEx")]
730         public static extern bool USBIO_SetDeviceNotifyEx(       // 设定设备事件通知程序
731             UInt32 iIndex,           // 指定CH341设备序号,0对应第一个设备
732             string iDeviceID,        // 可选参数,指向字符串,指定被监控的设备的ID,字符串以\0终止
733             mPCH341_NOTIFY_ROUTINE iNotifyRoutine); // 指定设备事件回调程序,为NULL则取消事件通知,否则在检测到事件时调用该程序
734 
735     }
736 }
USBIOXdll.cs

主要I2C和SPI 操作代码:

  1 //FLASH 配置状态寄存器地址
  2         public static byte WRITE_ENABLE = 0X06; //写使能
  3         public static byte WRITE_DISABLE = 0X04;    //写禁止
  4         public static byte READ_STATUS_REG1 = 0X05; //读状态寄存器
  5         public static byte READ_STATUS_REG2 = 0X35; //读状态寄存器
  6         public static byte READ_DATA = 0X03;    //读字节
  7         public static byte EWSR = 0X50;    //使能写状态寄存器
  8         public static byte FAST_READ = 0X0B;    //快读指令
  9         public static byte PAGE_PROGRAM = 0X02; //Byte Prog Mode
 10         public static byte SECTOR_ERASE_4K = 0X20;  //Erase 4 KByte of memory array
 11         public static byte BLOCK_ERASE_32K = 0X52; //Erase 32 KByte block of memory array
 12         public static byte BLOCK_ERASE_64K = 0XD8;  //Erase 64 KByte block of memory array
 13         public static byte CHIP_ERASE = 0XC7;   //擦除整个FLASH芯片
 14 
 15 public static void memset(byte[] buf, byte val, int size)
 16         {
 17             int i;
 18             for (i = 0; i < size; i++)
 19                 buf[i] = val;
 20         }
 21 
 22         public static void memcpy(byte[] dst, int dst_offst, byte[] src, int src_offst, uint len)
 23         {
 24             for (int i = 0; i < len; i++)
 25             {
 26                 dst[dst_offst++] = src[src_offst++];
 27             }
 28 
 29         }
 30 
 31         public static bool ReadI2C(uint mIndex, byte SlaveAddr, byte DataAddr, byte readData)    //连读模式
 32         {
 33             UInt32 writeLen = 0, readLen = 1;
 34             byte[] writeData = new byte[4], rData = new byte[1];
 35             memset(writeData, 0xFF, 4);
 36             writeData[0] = SlaveAddr;
 37             writeData[1] = DataAddr;
 38             writeLen = 2;
 39             bool bRet = USBIOXdll.USBIO_StreamI2C(mIndex, writeLen, writeData, readLen, rData);
 40             readData = rData[0];
 41             return bRet;
 42         }
 43         public static bool ReadI2C(uint mIndex, byte SlaveAddr, byte DataAddr, byte[] readData, UInt32 readLen)    //连读模式
 44         {
 45             UInt32 writeLen = 0;
 46             byte[] writeData = new byte[4];
 47             memset(writeData, 0xFF, 4);
 48             writeData[0] = SlaveAddr;
 49             writeData[1] = DataAddr;
 50             writeLen = 2;
 51             bool bRet = USBIOXdll.USBIO_StreamI2C(mIndex, writeLen, writeData, readLen, readData);
 52             return bRet;
 53         }
 54 
 55         public static bool WriteI2C(uint mIndex, byte SlaveAddr, byte DataAddr, byte data)     //单写模式
 56         {
 57             UInt32 writeLen = 3;
 58             UInt32 readLen = 0;
 59             byte[] writeData = new byte[4];
 60             byte[] readData = new byte[256];
 61             memset(writeData, 0xFF, 4);
 62             memset(readData, 0x00, 256);
 63             writeData[0] = SlaveAddr;
 64             writeData[1] = DataAddr;
 65             writeData[2] = data;
 66             bool bRet = USBIOXdll.USBIO_StreamI2C(mIndex, writeLen, writeData, readLen, readData);
 67             return bRet;
 68         }
 69 
 70         public static bool WriteI2C(uint mIndex, byte SlaveAddr, byte DataAddr, byte[] data, UInt32 len)     //多写模式
 71         {
 72             UInt32 writeLen = len + 2;
 73             UInt32 readLen = 0;
 74             byte[] writeData = new byte[writeLen];
 75             byte[] readData = new byte[256];
 76             //memset(writeData, 0xFF, 4);
 77             memset(readData, 0x00, 256);
 78 
 79             writeData[0] = SlaveAddr;
 80             writeData[1] = DataAddr;
 81             memcpy(writeData, 2, data, 0, len);
 82             bool bRet = USBIOXdll.USBIO_StreamI2C(mIndex, writeLen, writeData, readLen, readData);
 83             return bRet;
 84         }
 85         /// <summary>
 86         /// SPI擦除flash操作
 87         /// </summary>
 88         /// <param name="mIndex">指定CH341设备序号</param>
 89         /// <param name="m_iChipSelect">片选控制, 位7为0则忽略片选控制, 位7为1则参数有效: 位1位0为00/01/10分别选择D0/D1/D2引脚作为低电平有效片选</param>
 90         /// <param name="Erase_Select">擦除类型</param>
 91         /// <param name="sAdd">地址</param>
 92         public static void SPIErase(uint mIndex,uint m_iChipSelect,byte Erase_Select,uint sAdd)
 93         {
 94             byte[] data = new byte[4];
 95             USBIOXdll.USBIO_SetStream(mIndex, 0x80);
 96             memset(data, 0xFF, 4);
 97             data[0] = WRITE_ENABLE;
 98             USBIOXdll.USBIO_StreamSPI4(mIndex, m_iChipSelect, 1, data);
 99 
100             data[0] = Erase_Select;
101             data[1] = (byte)((sAdd & 0xFF0000) >> 16);
102             data[2] = (byte)((sAdd & 0x00FF00) >> 8);
103             data[3] = (byte)(sAdd & 0x0000FF);
104             USBIOXdll.USBIO_StreamSPI4(mIndex, m_iChipSelect, 4, data);
105 
106             data[0] = WRITE_DISABLE;
107             USBIOXdll.USBIO_StreamSPI4(mIndex, m_iChipSelect, 1, data);
108 
109         }
110         /// <summary>
111         /// SPI写入flash数据
112         /// </summary>
113         /// <param name="mIndex">设备号</param>
114         /// <param name="m_iChipSelect">片选</param>
115         /// <param name="sAdd">起始地址</param>
116         /// <param name="WriteData">数据</param>
117         public static void WriteSPI(uint mIndex, uint m_iChipSelect,uint sAdd,byte[] WriteData)
118         {
119             byte[] status = new byte[1];
120             byte[] data = new byte[260];
121             int len = WriteData.Length;
122             int nPage = 0;
123             USBIOXdll.USBIO_SetStream(mIndex, 0x80);
124             while (len >256)
125             {
126                 
127                 status[0] = WRITE_ENABLE;
128                 USBIOXdll.USBIO_StreamSPI4(mIndex, m_iChipSelect, 1, status);
129                 data[0] = PAGE_PROGRAM;
130                 data[1] = (byte)((sAdd & 0xFF0000) >> 16);
131                 data[2] = (byte)((sAdd & 0x00FF00) >> 8);
132                 data[3] = (byte)(sAdd & 0x0000FF);
133                 memcpy(data, 4, WriteData, nPage * 256, 256);
134                 USBIOXdll.USBIO_StreamSPI4(mIndex, m_iChipSelect, 260, data);
135                 status[0] = WRITE_DISABLE;
136                 USBIOXdll.USBIO_StreamSPI4(mIndex, m_iChipSelect, 1, status);
137                 USBIOXdll.USBIO_SetDelaymS(mIndex, 2);
138                 len -= 256;
139                 nPage++;
140                 sAdd += 256;
141             }
142 
143             status[0] = WRITE_ENABLE;
144             USBIOXdll.USBIO_StreamSPI4(mIndex, m_iChipSelect, 1, status);
145             data[0] = PAGE_PROGRAM;
146             data[1] = (byte)((sAdd & 0xFF0000) >> 16);
147             data[2] = (byte)((sAdd & 0x00FF00) >> 8);
148             data[3] = (byte)(sAdd & 0x0000FF);
149             memcpy(data, 4, WriteData, nPage * 256, (uint)len);
150             USBIOXdll.USBIO_StreamSPI4(mIndex, m_iChipSelect, (uint)(len+4), data);
151             status[0] = WRITE_DISABLE;
152             USBIOXdll.USBIO_StreamSPI4(mIndex, m_iChipSelect, 1, status);
153         }
154         /// <summary>
155         /// SPI读取flash数据
156         /// </summary>
157         /// <param name="mIndex">设备号</param>
158         /// <param name="m_iChipSelect">片选</param>
159         /// <param name="sAdd">起始地址</param>
160         /// <param name="ReadData">读取数据返回数组</param>
161         /// <param name="ReadLen">读取长度</param>
162         public static void ReadSPI(uint mIndex, uint m_iChipSelect, uint sAdd, byte[] ReadData,uint ReadLen)
163         {
164             byte[] status = new byte[2564];
165             int i = 0;
166             
167             USBIOXdll.USBIO_SetStream(mIndex, 0x80);
168             //USBIOXdll.USBIO_StreamSPI4(mIndex, m_iChipSelect, 4, status);
169             while(ReadLen>2560)
170             {
171                 status[0] = READ_DATA;
172                 status[1] = (byte)((sAdd & 0xFF0000) >> 16);
173                 status[2] = (byte)((sAdd & 0x00FF00) >> 8);
174                 status[3] = (byte)(sAdd & 0x0000FF);
175                 USBIOXdll.USBIO_StreamSPI4(mIndex, m_iChipSelect, 2564, status);
176                 memcpy(ReadData, i * 2560, status, 4, 2560);
177                 ReadLen -= 2560;
178                 i++;
179                 sAdd += 2560;
180             }
181             status[0] = READ_DATA;
182             status[1] = (byte)((sAdd & 0xFF0000) >> 16);
183             status[2] = (byte)((sAdd & 0x00FF00) >> 8);
184             status[3] = (byte)(sAdd & 0x0000FF);
185             USBIOXdll.USBIO_StreamSPI4(mIndex, m_iChipSelect, ReadLen+4, status);
186             memcpy(ReadData, i * 2560, status, 4, ReadLen);
187         }
View Code

 

 

 

链接:C# SPI 读写SD卡