使用ZLG USBCAN-E-U,通过C#实现通讯:

1、建一个CANDevice实体类,传递一些参数,并且保存一些设备的型号、ID,以及波特率等参数

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Runtime.InteropServices;namespace ZLGUSBCAN
{[Serializable]public class CardType{public string TyPeName { get; set; }public uint TypeId { get; set; }}[Serializable]public class BoudRoute{public string RateName { get; set; }public UInt32 RateValue { get; set; }}[Serializable]public class CANDevice{        //private readonly uint devType;//private readonly uint devID;//private readonly uint canID;//private readonly uint baudRate;//private readonly uint sendTimeout;public uint DevType { get; set; }public uint DevID { get; set; }public uint CANID { get; set; }public uint BoudRate { get; set; }public uint SendTimeout { get; set; }//CAN参数public uint AccCode { get; set; }public uint AccMask { get; set; }public uint Reserved { get; set; }public byte Filter { get; set; }public byte Timing0 { get; set; }public byte Timing1 { get; set; }public byte Mode { get; set; }public List<CardType> CardTypeList { get; set; }public List<BoudRoute> BoudRateList { get; set; }public CANDevice(uint devType, uint devID, uint boudRate, uint sendTimeout, uint canID = 0){this.DevType = devType;this.DevID = devID;this.CANID = canID;this.BoudRate = boudRate;this.SendTimeout = sendTimeout;}public CANDevice(){this.CardTypeList = new List<CardType>();           this.CardTypeList.Add(new CardType { TyPeName = "VCI_USBCAN_E_U", TypeId = 20 });this.CardTypeList.Add(new CardType { TyPeName = "VCI_USBCAN_2E_U", TypeId = 21 });this.BoudRateList = new List<BoudRoute>();this.BoudRateList.Add(new BoudRoute { RateName = "1000Kbps", RateValue = 0x060003 });this.BoudRateList.Add(new BoudRoute { RateName = "800Kbps", RateValue = 0x060004 });this.BoudRateList.Add(new BoudRoute { RateName = "500Kbps", RateValue = 0x060007 });this.BoudRateList.Add(new BoudRoute { RateName = "250Kbps", RateValue = 0x1C0008 });this.BoudRateList.Add(new BoudRoute { RateName = "125Kbps", RateValue = 0x1C0011 });this.BoudRateList.Add(new BoudRoute { RateName = "100Kbps", RateValue = 0x160023 });this.BoudRateList.Add(new BoudRoute { RateName = "50Kbps", RateValue = 0x1C002C });this.BoudRateList.Add(new BoudRoute { RateName = "20Kbps", RateValue = 0x1600B3 });this.BoudRateList.Add(new BoudRoute { RateName = "10Kbps", RateValue = 0x1C00E0 });this.BoudRateList.Add(new BoudRoute { RateName = "5Kbps", RateValue = 0x1C01C1 });           }   }
}

2、建一个ControlCAN,对周立功提供的接口函数进行二次开发

首先需要引入设备供应商提供的接口函数库,在C#中属于非托管,因此需要通过[DllImport("路径.dll")]这样的方式来引入。特别注意:该接口函数如果是32位,注意你的解决方案平台需要时X86;还有,你要将所有引用的文件都复制到路径下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Microsoft.Win32.SafeHandles;namespace ZLGUSBCAN
{public class _VCI_CAN_OBJ{public uint ID { get; set; }public uint TimeStamp { get; set; }public byte TimeFlag { get; set; }/// <summary>/// 发送格式:0:正常发送 1:单次正常发送 2:自发自收 3.单次自发自收/// </summary>public byte SendType { get; set; }/// <summary>/// 帧格式:0:数据帧 1:远程帧/// </summary>public byte RemoteFlag { get; set; }/// <summary>/// 帧类型:0:标准帧 1为扩展帧,29位ID/// </summary>public byte ExternFlag { get; set; }public byte DataLen { get; set; }public byte[] Data { get; set; }public byte[] Reserved { get; set; }}public class _VCI_INIT_CONFIG{public uint AccCode { get; set; }public uint AccMask { get; set; }public byte Reserved { get; set; }public byte Filter { get; set; }public byte Timing0 { get; set; }public byte Timing1 { get; set; }public byte Mode { get; set; }}public class ControlCAN{#region 接口函数定义[StructLayoutAttribute(LayoutKind.Sequential)]struct VCI_CAN_OBJ{public uint ID;public uint TimeStamp;public byte TimeFlag;public byte SendType;//发送格式:0:正常发送 1:单次正常发送 2:自发自收 3.单次自发自收public byte RemoteFlag;//帧格式:0:数据帧 1:远程帧public byte ExternFlag;//帧类型:0:标准帧 1为扩展帧,29位IDpublic byte DataLen;[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 8)]public byte[] Data;[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3)]public byte[] Reserved;}[StructLayoutAttribute(LayoutKind.Sequential)]struct VCI_INIT_CONFIG{public uint AccCode;public uint AccMask;public uint Reserved;public byte Filter;public byte Timing0;public byte Timing1;public byte Mode;}[StructLayoutAttribute(LayoutKind.Sequential)]struct VCI_FILTER_RECORD{public uint ExtFrame;public uint Start;public uint End;}[DllImport("kernel32.dll")]static extern uint GetLastError();[DllImport("ControlCAN.dll")]static extern uint VCI_OpenDevice(uint DevType, uint DevIndex, uint Reserved);//Reserved系统保留字段[DllImport("ControlCAN.dll")]static extern uint VCI_CloseDevice(uint DevType, uint DevIndex);[DllImport("ControlCAN.dll")]static extern uint VCI_StartCAN(uint DevType, uint DevIndex, uint CANIndex);[DllImport("ControlCAN.dll")]static extern uint VCI_ResetCAN(uint DevType, uint DevIndex, uint CANIndex);[DllImport("ControlCAN.dll")]static extern uint VCI_SetReference(uint DevType, uint DevIndex, uint CANIndex, uint RefType, IntPtr pData);//[DllImport("ControlCAN.dll")]//unsafe static extern UInt32 VCI_SetReference(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, UInt32 RefType, byte* pData);[DllImport("ControlCAN.dll")]static extern uint VCI_Receive(uint DevType, uint DevIndex, uint CANIndex, [Out] VCI_CAN_OBJ[] pReceive, uint Len, int WaitTime);//参照官方[DllImport("ControlCAN.dll", CharSet = CharSet.Ansi)]static extern UInt32 VCI_Receive(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, IntPtr pReceive, UInt32 Len, Int32 WaitTime);[DllImport("ControlCAN.dll")]static extern uint VCI_Transmit(uint DevType, uint DevIndex, uint CANIndex, [In] VCI_CAN_OBJ[] pSend, uint Len);[DllImport("ControlCAN.dll")]static extern uint VCI_InitCAN(uint DevType, uint DevIndex, uint CANIndex, ref VCI_INIT_CONFIG pInitConfig);[DllImport("ControlCAN.dll")]static extern uint VCI_GetReceiveNum(uint DevType, uint DevIndex, uint CANIndex);[DllImport("ControlCAN.dll")]static extern uint VCI_ClearBuffer(uint DevType, uint DevIndex, uint CANIndex);[DllImport("RC500USB.dll")]static extern byte RC500USB_init();[DllImport("RC500USB.dll")]static extern void RC500USB_exit();[DllImport("RC500USB.dll")]static extern byte RC500USB_request(byte mode, ref ushort tagtype);[DllImport("RC500USB.dll")]static extern byte RC500USB_anticoll(byte bcnt, ref uint snr);[DllImport("RC500USB.dll")]static extern byte RC500USB_select(uint snr, ref byte size);[DllImport("RC500USB.dll")]internal static extern byte RC500USB_authkey(byte mode, [In] byte[] key, byte secnr);[DllImport("RC500USB.dll")]internal static extern byte RC500USB_read(byte addr, [Out] byte[] data);[DllImport("RC500USB.dll")]internal static extern byte RC500USB_buzzer(byte contrl, byte opentm, byte closetm, byte repcnt);// serialport//Win32 io errorspublic const int ERROR_BROKEN_PIPE = 109;public const int ERROR_NO_DATA = 232;public const int ERROR_HANDLE_EOF = 38;public const int ERROR_IO_INCOMPLETE = 996;public const int ERROR_IO_PENDING = 997;public const int ERROR_FILE_EXISTS = 0x50;public const int ERROR_FILENAME_EXCED_RANGE = 0xCE;  // filename too long.public const int ERROR_MORE_DATA = 234;public const int ERROR_CANCELLED = 1223;public const int ERROR_FILE_NOT_FOUND = 2;public const int ERROR_PATH_NOT_FOUND = 3;public const int ERROR_ACCESS_DENIED = 5;public const int ERROR_INVALID_HANDLE = 6;public const int ERROR_NOT_ENOUGH_MEMORY = 8;public const int ERROR_BAD_COMMAND = 22;public const int ERROR_SHARING_VIOLATION = 32;public const int ERROR_OPERATION_ABORTED = 995;public const int ERROR_NO_ASSOCIATION = 1155;public const int ERROR_DLL_NOT_FOUND = 1157;public const int ERROR_DDE_FAIL = 1156;public const int ERROR_INVALID_PARAMETER = 87;public const int ERROR_PARTIAL_COPY = 299;// Since C# does not provide access to bitfields and the native DCB structure contains// a very necessary one, these are the positional offsets (from the right) of areas// of the 32-bit integer used in SerialStream's SetDcbFlag() and GetDcbFlag() methods.internal const int FBINARY = 0;internal const int FPARITY = 1;internal const int FOUTXCTSFLOW = 2;internal const int FOUTXDSRFLOW = 3;internal const int FDTRCONTROL = 4;internal const int FDSRSENSITIVITY = 6;internal const int FTXCONTINUEONXOFF = 7;internal const int FOUTX = 8;internal const int FINX = 9;internal const int FERRORCHAR = 10;internal const int FNULL = 11;internal const int FRTSCONTROL = 12;internal const int FABORTONOERROR = 14;internal const int FDUMMY2 = 15;// The following are unique to the SerialPort/SerialStream classesinternal const byte ONESTOPBIT = 0;internal const byte ONE5STOPBITS = 1;internal const byte TWOSTOPBITS = 2;public const int FILE_READ_DATA = (0x0001),FILE_LIST_DIRECTORY = (0x0001),FILE_WRITE_DATA = (0x0002),FILE_ADD_FILE = (0x0002),FILE_APPEND_DATA = (0x0004),FILE_ADD_SUBDIRECTORY = (0x0004),FILE_CREATE_PIPE_INSTANCE = (0x0004),FILE_READ_EA = (0x0008),FILE_WRITE_EA = (0x0010),FILE_EXECUTE = (0x0020),FILE_TRAVERSE = (0x0020),FILE_DELETE_CHILD = (0x0040),FILE_READ_ATTRIBUTES = (0x0080),FILE_WRITE_ATTRIBUTES = (0x0100),FILE_SHARE_READ = 0x00000001,FILE_SHARE_WRITE = 0x00000002,FILE_SHARE_DELETE = 0x00000004,FILE_ATTRIBUTE_READONLY = 0x00000001,FILE_ATTRIBUTE_HIDDEN = 0x00000002,FILE_ATTRIBUTE_SYSTEM = 0x00000004,FILE_ATTRIBUTE_DIRECTORY = 0x00000010,FILE_ATTRIBUTE_ARCHIVE = 0x00000020,FILE_ATTRIBUTE_NORMAL = 0x00000080,FILE_ATTRIBUTE_TEMPORARY = 0x00000100,FILE_ATTRIBUTE_COMPRESSED = 0x00000800,FILE_ATTRIBUTE_OFFLINE = 0x00001000,FILE_NOTIFY_CHANGE_FILE_NAME = 0x00000001,FILE_NOTIFY_CHANGE_DIR_NAME = 0x00000002,FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x00000004,FILE_NOTIFY_CHANGE_SIZE = 0x00000008,FILE_NOTIFY_CHANGE_LAST_WRITE = 0x00000010,FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020,FILE_NOTIFY_CHANGE_CREATION = 0x00000040,FILE_NOTIFY_CHANGE_SECURITY = 0x00000100,FILE_ACTION_ADDED = 0x00000001,FILE_ACTION_REMOVED = 0x00000002,FILE_ACTION_MODIFIED = 0x00000003,FILE_ACTION_RENAMED_OLD_NAME = 0x00000004,FILE_ACTION_RENAMED_NEW_NAME = 0x00000005,FILE_CASE_SENSITIVE_SEARCH = 0x00000001,FILE_CASE_PRESERVED_NAMES = 0x00000002,FILE_UNICODE_ON_DISK = 0x00000004,FILE_PERSISTENT_ACLS = 0x00000008,FILE_FILE_COMPRESSION = 0x00000010,OPEN_EXISTING = 3,OPEN_ALWAYS = 4,FILE_FLAG_WRITE_THROUGH = unchecked((int)0x80000000),FILE_FLAG_OVERLAPPED = 0x40000000,FILE_FLAG_NO_BUFFERING = 0x20000000,FILE_FLAG_RANDOM_ACCESS = 0x10000000,FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000,FILE_FLAG_DELETE_ON_CLOSE = 0x04000000,FILE_FLAG_BACKUP_SEMANTICS = 0x02000000,FILE_FLAG_POSIX_SEMANTICS = 0x01000000,FILE_TYPE_UNKNOWN = 0x0000,FILE_TYPE_DISK = 0x0001,FILE_TYPE_CHAR = 0x0002,FILE_TYPE_PIPE = 0x0003,FILE_TYPE_REMOTE = unchecked((int)0x8000),FILE_VOLUME_IS_COMPRESSED = 0x00008000;// The following are unique to the SerialPort/SerialStream classesinternal const int DTR_CONTROL_DISABLE = 0x00;internal const int DTR_CONTROL_ENABLE = 0x01;internal const int DTR_CONTROL_HANDSHAKE = 0x02;internal const int RTS_CONTROL_DISABLE = 0x00;internal const int RTS_CONTROL_ENABLE = 0x01;internal const int RTS_CONTROL_HANDSHAKE = 0x02;internal const int RTS_CONTROL_TOGGLE = 0x03;internal const int MS_CTS_ON = 0x10;internal const int MS_DSR_ON = 0x20;internal const byte DEFAULTXONCHAR = (byte)17;internal const byte DEFAULTXOFFCHAR = (byte)19;internal const byte EOFCHAR = (byte)26;[StructLayoutAttribute(LayoutKind.Sequential)]public struct COMMTIMEOUTS{public int ReadIntervalTimeout;public int ReadTotalTimeoutMultiplier;public int ReadTotalTimeoutConstant;public int WriteTotalTimeoutMultiplier;public int WriteTotalTimeoutConstant;}[StructLayout(LayoutKind.Sequential)]internal struct DCB{public uint DCBlength;public uint BaudRate;public uint Flags;public ushort wReserved;public ushort XonLim;public ushort XoffLim;public byte ByteSize;public byte Parity;public byte StopBits;public byte XonChar;public byte XoffChar;public byte ErrorChar;public byte EofChar;public byte EvtChar;public ushort wReserved1;}public const int GENERIC_READ = unchecked(((int)0x80000000));public const int GENERIC_WRITE = (0x40000000);internal const int PURGE_TXABORT = 0x0001;  // Kill the pending/current writes to the comm port.internal const int PURGE_RXABORT = 0x0002;  // Kill the pending/current reads to the comm port.internal const int PURGE_TXCLEAR = 0x0004;  // Kill the transmit queue if there.internal const int PURGE_RXCLEAR = 0x0008;  // Kill the typeahead buffer if there.#endregionprivate static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);public uint MaxFrames { get; set; } = 16;public int ReceiveTimeout { get; set; } = 2000;private int disposed = 0;private CANDevice objCANDevice;protected virtual void Dispose(bool disposing){if (Interlocked.Exchange(ref disposed, 1) == 0){if (Interlocked.Exchange(ref disposed, 1) == 0){//释放非托管资源if (ControlCAN.VCI_CloseDevice(objCANDevice.DevType, objCANDevice.DevID) == 0){log.Error("Failed to close CAN device");}}}}public void Dispose(){///<summary>/// 实现IDisposable中的Dispose方法///</summary>Dispose(true);//必须为true//通知垃圾回收机制不再调用终结器(析构器)GC.SuppressFinalize(this);//禁止终结操作}/// <summary>/// /// </summary>/// <param name="devType"></param>/// <param name="devID"></param>/// <param name="baudRate"></param>/// <param name="sendTimeout"></param>/// <param name="canID">默认为0</param>public ControlCAN(CANDevice canDevice){objCANDevice = canDevice;}/// <summary>/// 打开CAN设备/// </summary>/// <returns></returns>public bool OpenCAN(){if (VCI_OpenDevice(objCANDevice.DevType, objCANDevice.DevID, 0) == 0){//log.Error("Failed to open CAN device");//uint error = GetLastError();return false;}return true;}/// <summary>/// 启动某一路CAN/// </summary>public bool StartCan(uint canId = 0){if (Thread.VolatileRead(ref disposed) != 0){throw new ObjectDisposedException("CanDevice already disposed");}if (canId != 0){objCANDevice.CANID = canId;}if (!SetBaudRate(objCANDevice.BoudRate)){throw new Exception("波特率设置失败!");}if (!SetWorkingMode()){throw new Exception("工作模式设置失败!");}if (VCI_StartCAN(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID) == 0){//log.Error("Failed to start CAN device");return false;}if (!SetSendTimeout()){throw new Exception("发送超时设置失败!");}ClearBuffer();return true;}/// <summary>/// 设置波特率/// </summary>/// <param name="baudRate">uint类型</param>/// <returns></returns>public bool SetBaudRate(uint baudRate){if (Thread.VolatileRead(ref disposed) != 0){throw new ObjectDisposedException("CanDevice already disposed");}IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(baudRate));try{Marshal.WriteInt32(ptr, (int)baudRate);if (VCI_SetReference(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID, 0, ptr) == 0){log.Error("Failed to set CAN baud rate");return false;}}finally{Marshal.FreeHGlobal(ptr);}return true;}/// <summary>/// 设置工作模式,需提供工作模式Id/// 必须先设置波特率再设置工模式/// </summary>/// <param name="modeId"> =0 表示正常模式(相当于正常节点), =1 表示只听模式(只接收,不影响总线)</param>/// <returns></returns>public bool SetWorkingMode(byte modeId = 0){if (Thread.VolatileRead(ref disposed) != 0){throw new ObjectDisposedException("CanDevice already disposed");}VCI_INIT_CONFIG initConfig = new VCI_INIT_CONFIG();initConfig.Mode = modeId;//正常模式if (VCI_InitCAN(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID, ref initConfig) == 0){log.Error("Failed to set CAN working mode");return false;}return true;}/// <summary>///设置发送超时时间/// </summary>public bool SetSendTimeout(uint timeout = 2000){if (Thread.VolatileRead(ref disposed) != 0){throw new ObjectDisposedException("CanDevice already disposed");}IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(timeout));try{Marshal.WriteInt32(ptr, (int)timeout);if (VCI_SetReference(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID, 4, ptr) == 0){log.Error("Failed to set CAN send timeout");return false;}}finally{Marshal.FreeHGlobal(ptr);}return true;}/// <summary>/// 发送数据/// </summary>/// <param name="frames">帧结构体数组</param>/// 举例:VCI_CAN_OBJ[] frames=new VCI_CAN_OBJ[2];//将发送两帧数据/// frames[0].ID=0x00000001;//第一帧ID/// frames[0].SendType=0;//正常发送/// frames[0].RemoteFlag=0;//数据帧/// frames[0].ExternFlag=0;//标准帧/// frames[0].DataLen=1;//数据长度/// frames[0].Data[0]=0x56;//数据/// frames[1]~/// <returns></returns>public bool Transmit(_VCI_CAN_OBJ[] frames){if (Thread.VolatileRead(ref disposed) != 0){throw new ObjectDisposedException("CanDevice already disposed");}int length = frames.Length;VCI_CAN_OBJ[] obj = new VCI_CAN_OBJ[length];for (int i = 0; i < length; i++){obj[i] = new VCI_CAN_OBJ{ID = frames[i].ID,TimeFlag = frames[i].TimeFlag,TimeStamp = frames[i].TimeStamp,SendType = frames[i].SendType,RemoteFlag = frames[i].RemoteFlag,ExternFlag = frames[i].ExternFlag,Data = frames[i].Data,DataLen = frames[i].DataLen,Reserved = frames[i].Reserved};}return VCI_Transmit(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID, obj, (uint)length) != 0;}public bool Transmit(_VCI_CAN_OBJ frame){if (Thread.VolatileRead(ref disposed) != 0){throw new ObjectDisposedException("CanDevice already disposed");}VCI_CAN_OBJ[] frames = new VCI_CAN_OBJ[1];frames[0] = new VCI_CAN_OBJ{ID = frame.ID,TimeFlag = frame.TimeFlag,TimeStamp = frame.TimeStamp,SendType = frame.SendType,RemoteFlag = frame.RemoteFlag,ExternFlag = frame.ExternFlag,Data = frame.Data,DataLen = frame.DataLen,Reserved = frame.Reserved};return VCI_Transmit(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID, frames, (uint)frames.Length) != 0;}/// <summary>/// 设置CAN相关参数/// </summary>/// <param name="config"></param>/// <returns></returns>public bool InitCAN(_VCI_INIT_CONFIG config){if (Thread.VolatileRead(ref disposed) != 0){throw new ObjectDisposedException("CanDevice already disposed");}VCI_INIT_CONFIG obj = new VCI_INIT_CONFIG{AccCode = config.AccCode,AccMask = config.AccMask,Mode = config.Mode,Filter = config.Filter,Timing0 = config.Timing0,Timing1 = config.Timing1,Reserved = config.Reserved};if (VCI_InitCAN(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID, ref obj) == 0){return false;}return true;}#region 参考ZLG官方示例/// <summary>/// 接收数据/// </summary>/// <returns></returns>public List<_VCI_CAN_OBJ> Receive(){//获取CAN通道缓冲区中已接收但未读取的帧数量uint receiveNum = VCI_GetReceiveNum(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID);if (receiveNum == 0) return null;//如果缓冲区未读取的帧数量大于规定的最大读取量,只能读取规定的最大量的帧数据,其它数据丢失uint needReceiveNum = receiveNum > MaxFrames ? MaxFrames : receiveNum;IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(VCI_CAN_OBJ)) * (Int32)receiveNum);//返回值为实际读取的帧数量,数据填充至bufreceiveNum = VCI_Receive(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID, pt, receiveNum, 100);List<_VCI_CAN_OBJ> result = new List<_VCI_CAN_OBJ>();//string str = "";for (int i = 0; i < receiveNum; i++){VCI_CAN_OBJ obj = (VCI_CAN_OBJ)Marshal.PtrToStructure((IntPtr)((UInt32)pt + i * Marshal.SizeOf(typeof(VCI_CAN_OBJ))), typeof(VCI_CAN_OBJ));//foreach (var item in obj.Data)//{//    str += " " + System.Convert.ToString(item, 16);//}result.Add(new _VCI_CAN_OBJ{ID = obj.ID,TimeFlag = obj.TimeFlag,TimeStamp = obj.TimeStamp,SendType = obj.SendType,RemoteFlag = obj.RemoteFlag,ExternFlag = obj.ExternFlag,Data = obj.Data,DataLen = obj.DataLen,Reserved = obj.Reserved});}return result;}/// <summary>/// 直接获取接收数据的string形式/// </summary>/// <returns></returns>public string OnlyReceiveData(){//获取CAN通道缓冲区中已接收但未读取的帧数量uint receiveNum = VCI_GetReceiveNum(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID);if (receiveNum == 0) return null;//如果缓冲区未读取的帧数量大于规定的最大读取量,只能读取规定的最大量的帧数据,其它数据丢失uint needReceiveNum = receiveNum > MaxFrames ? MaxFrames : receiveNum;IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(VCI_CAN_OBJ)) * (Int32)receiveNum);//返回值为实际读取的帧数量,数据填充至bufreceiveNum = VCI_Receive(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID, pt, receiveNum, 100);string str = "";for (int i = 0; i < receiveNum; i++){VCI_CAN_OBJ obj = (VCI_CAN_OBJ)Marshal.PtrToStructure((IntPtr)((UInt32)pt + i * Marshal.SizeOf(typeof(VCI_CAN_OBJ))), typeof(VCI_CAN_OBJ));foreach (var item in obj.Data){str += " " + System.Convert.ToString(item, 16);}}return str;}#endregion#region 修改接收方法:调用的VCI_Receive参数不同/// <summary>/// /// </summary>/// <returns></returns>public List<_VCI_CAN_OBJ> _Receive(){if (Thread.VolatileRead(ref disposed) != 0){throw new ObjectDisposedException("CanDevice already disposed");}VCI_CAN_OBJ[] buf = new VCI_CAN_OBJ[MaxFrames];//MaxFrames为规定的最大接收数uint num = VCI_Receive(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID, buf, (uint)buf.Length,2000);VCI_CAN_OBJ[] frames = new VCI_CAN_OBJ[num];Array.Copy(buf, frames, num);List<_VCI_CAN_OBJ> result = new List<_VCI_CAN_OBJ>();foreach (var obj in frames){result.Add(new _VCI_CAN_OBJ{ID = obj.ID,TimeFlag = obj.TimeFlag,TimeStamp = obj.TimeStamp,SendType = obj.SendType,RemoteFlag = obj.RemoteFlag,ExternFlag = obj.ExternFlag,Data = obj.Data,DataLen = obj.DataLen,Reserved = obj.Reserved});}return result;}#endregion/// <summary>/// 查看缓存区是否存在未读取数据/// </summary>/// <returns></returns>public bool HasReceive(){return VCI_GetReceiveNum(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID) != 0;}/// <summary>/// 清除接收缓冲区数据/// </summary>/// <returns></returns>public bool ClearBuffer(){if (Thread.VolatileRead(ref disposed) != 0){throw new ObjectDisposedException("CanDevice already disposed");}if (ControlCAN.VCI_ClearBuffer(objCANDevice.DevType, objCANDevice.DevID, objCANDevice.CANID) == 0){log.Error("Failed to clear can.");return false;}return true;}/// <summary>/// 关闭CAN/// </summary>/// <returns></returns>public bool CloseCAN(){if (VCI_CloseDevice(objCANDevice.DevType, objCANDevice.DevID) == 0){//log.Error("Failed to close CAN device");return false;}return true;}}
}

基于提供的接口函数,对连接、打开、发送、接收等方法进行再次封装。

3、这样就可以实现通讯了

我做了一个简单的winform界面,可以进行简单的参数设置,并且能发送、接收数据。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace ZLGUSBCAN
{public partial class Form1 : Form{private CANDevice objCANDevice = null;private ControlCAN objControlCAN = null;private bool isOpen = false;public Form1(){InitializeComponent();this.cboDevType.DataSource = new CANDevice().CardTypeList;this.cboDevType.ValueMember = "TypeId";this.cboDevType.DisplayMember = "TypeName";this.cboBaudRate.DataSource = new CANDevice().BoudRateList;this.cboBaudRate.ValueMember = "RateValue";this.cboBaudRate.DisplayMember = "RateName";this.cboDevType.SelectedIndex = 0;this.cboDevIndex.SelectedIndex = 0;this.cboCANIndex.SelectedIndex = 0;this.cboBaudRate.SelectedIndex = 0;this.cboFilter.SelectedIndex = 1;this.cboFilterMode.SelectedIndex = 0;this.cboFrameFormat.SelectedIndex = 0;this.cboFrameType.SelectedIndex = 0;this.cboSendType.SelectedIndex = 2;//自发自收this.cboMode.SelectedIndex = 0;receiverTimer.Start();}private void btnConnect_Click(object sender, EventArgs e){try{if (isOpen)//CAN设备已打开{if (objCANDevice != null && objControlCAN != null){objControlCAN.CloseCAN();btnConnect.Text = "连接";btnStartCAN.Text = "启动CAN";isOpen = false;}}else//CAN设备未打开{objCANDevice = new CANDevice(Convert.ToUInt32(this.cboDevType.SelectedValue), Convert.ToUInt32(this.cboDevIndex.Text), Convert.ToUInt32(this.cboBaudRate.SelectedValue), 2000, Convert.ToUInt32(this.cboCANIndex.Text));objControlCAN = new ControlCAN(objCANDevice);if (objControlCAN.OpenCAN()){btnConnect.Text = "关闭连接";isOpen = true;}elseMessageBox.Show("设备打开失败!");}}catch (Exception ex){MessageBox.Show(ex.Message);}}private void btnStartCAN_Click(object sender, EventArgs e){try{if (isOpen){if (objControlCAN.StartCan()){//初始化CAN参数,可以没有,有默认值_VCI_INIT_CONFIG config = new _VCI_INIT_CONFIG(){AccCode = Convert.ToUInt32("0x" + this.txtAccCode.Text, 16),AccMask = Convert.ToUInt32("0x" + this.txtAccMask.Text, 16),Filter = (Byte)this.cboFilter.SelectedIndex,Mode = (Byte)this.cboFilterMode.SelectedIndex,Timing0 = System.Convert.ToByte("0x" + this.txtTime0.Text, 16),Timing1 = System.Convert.ToByte("0x" + this.txtTime1.Text, 16)};objControlCAN.InitCAN(config);this.btnStartCAN.Text = "打开成功";}else{MessageBox.Show("打开失败!");return;}}elseMessageBox.Show("请先连接CAN设备!");}catch (Exception ex){MessageBox.Show(ex.Message);}}private void btnSend_Click(object sender, EventArgs e){_VCI_CAN_OBJ frame = new _VCI_CAN_OBJ();//ControlCAN.VCI_CAN_OBJ frame = new ControlCAN.VCI_CAN_OBJ();try{frame.SendType = (byte)this.cboSendType.SelectedIndex;frame.RemoteFlag = (byte)this.cboFrameFormat.SelectedIndex;frame.ExternFlag = (byte)this.cboFrameType.SelectedIndex;frame.ID = Convert.ToUInt32("0x" + txtID.Text, 16);string[] dataStr = this.txtData.Text.Trim().Split(' ');frame.Data = new byte[dataStr.Length];frame.DataLen = (byte)dataStr.Length;for (int i = 0; i < dataStr.Length; i++){frame.Data[i] = Convert.ToByte("0x" + dataStr[i], 16);}if (objControlCAN.Transmit(frame)){lbInfo.Items.Add($"发送 {DateTime.Now.ToShortTimeString()} 帧ID:{txtID.Text} 数据:{this.txtData.Text}");}else{MessageBox.Show("发送失败!");return;}}catch (Exception ex){MessageBox.Show(ex.Message);}}private void receiverTimer_Tick(object sender, EventArgs e){if (objControlCAN != null && objControlCAN.HasReceive()){List<_VCI_CAN_OBJ> objOBJ = objControlCAN._Receive();foreach (var obj in objOBJ){string str = "接收 ";str += "  帧ID:0x" + System.Convert.ToString((Int32)obj.ID, 16);str += "  帧格式:";if (obj.RemoteFlag == 0){str += "数据: ";foreach (var item in obj.Data){str += " " + System.Convert.ToString(item, 16);}}lbInfo.Items.Add(str);lbInfo.SelectedIndex = lbInfo.Items.Count - 1;}}}}
}

使用USBCAN通讯(转载)相关推荐

  1. Centos 6.5 64位双网卡绑定

    1.环境描述       我的Vmware workstation 10 安装Centos 6.5 64位加上双口的Intel千兆网卡,通过ifconfig -a|grep eth命令看到eth2和e ...

  2. centos09-nodejs与vue搭建

    https://nodejs.org/dist/v8.9.4/node-v8.9.4-linux-x64.tar.xz 注意,后缀名是tar.xz 不是tar.gz 下面的任务: 把node.js 的 ...

  3. 进程间通信 (IPC) 方法总结(三)

    进程间通信 (IPC) 方法总结(三) 信号量(SEMAPHORE) 信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步. 为了获得共享资源,进程需要执行下列操作: 创建一个信 ...

  4. Java修炼之道--I/O

    原作地址:https://github.com/frank-lam/2019_campus_apply Java IO Java 的 I/O 大概可以分成以下几类: 磁盘操作:File 字节操作:In ...

  5. Windows下socket编程(console非MFC)

    console控制台:使用<winsock2.h> 和 ws2_32.lib  参考:孙鑫C++课程14 TCP:面对连接的.安全的通信 // TcpSrv.cpp /#define _C ...

  6. preparedStatement和Statement 有什么不一样

    1. PreparedStatement接口继承Statement, PreparedStatement 实例包含已编译的 SQL 语句,所以其执行速度要快于 Statement 对象. 2.作为 S ...

  7. 路由器下接路由器设置方法(路由器级联)

    这个属于路由器的级联.不同的路由器有不同的方法. 路由器级联 在单位兼职网管,现在遇到了复杂的问题.又开始重新学习网络知识,下面是今天所学.量变引起质变.多多积累. 路由器的接口不够,可级联交换机来扩 ...

  8. 【工大SCIR】AAAI20 基于Goal(话题)的开放域多轮对话规划

    论文名称:Knowledge Graph Grounded Goal Planning for Open-Domain Conversation Generation 论文作者:徐俊,王海峰,牛正雨, ...

  9. 西门子Wincc/Step7/pcs7

    pcs7:它集成了上位机和下位机的编程,step7只有下位机编程,上位机需要其他的软件开发人机界面,比如wincc.组态王.力控等! STEP7是针对西门子S7-300/400的组态和编程软件.它只能 ...

  10. Python 网络编程之网络协议(未完待续)

    一:网络编程从两大架构开始 1.网络开发的两大架构 c/s 架构 : client  server B/S 架构 : Brower  server (1)bs 和 cs 架构之间的关系? (2)哪一种 ...

最新文章

  1. 一个bug隐藏了另外一个bug,reloaddata,
  2. 利用大数据技术探索“数字公民”创新
  3. 温度单闭环实验计算机控制,过程控制系统实践指导简介,目录书摘
  4. oracle的管理工具
  5. Project Management Library项目管理甘特图控件
  6. 解锁bios学习总结
  7. 8086的两种工作模式_Lora自组网网关的两种工作模式
  8. oracle12版本无scott解决,Oracle12C中scott账户与表问题
  9. 寻找连通域算法_FPGA实现的连通域识别算法升级
  10. python实现词云图
  11. weblogic-wslt初探
  12. python入口文件详解_Python基础系列讲解——那些py文件中容易忽略的细节
  13. JAVA王思聪吃热狗程序_易语言制作王校长吃热狗游戏的源码
  14. 中英文电子书下载:https://sobooks.cc/
  15. MongoDB 主从复制(Master-Slaver)实验
  16. Unable to open JDBC Connection for DDL execution
  17. 你若安好便是晴天nbsp;---------…
  18. UltraGrid本地Oracle数据库增删改查
  19. 无法卸载vue2.x提示up to date
  20. ExpandableListView 去掉默认箭头,设置成别的图片

热门文章

  1. 中国大学mooc c语言答案,中国大学mooc程序设计与算法(一)C语言程序设计章节答案...
  2. 操作系统基础(八)快表和多级页表
  3. 计算机位置不可用d 桌面,win7系统D: 文档desktop引用了一个不可用的位置怎么办...
  4. 计算机学院院徽设计,信息工程学院院徽设计
  5. mysql数据库增左右连接_Nodejs连接MySQL数据库 增、删、改、查等操作
  6. minecraft崩溃java,je1.7.10,进入世界就崩溃,解决一下
  7. 联想电脑管家图文介绍:联想电脑管家怎么下载?
  8. 苹果公司是如何“驻厂“管理供应商的
  9. [HNOI2004]宠物收养所(简单理解,用set写的)
  10. 路由器回执路由配置_路由器接路由器设置详细图文教程