1.API
class API
{
/*------------兼容ZLG的函数描述---------------------------------*/
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_OpenDevice(UInt32 DeviceType, UInt32 DeviceInd, UInt32 Reserved);
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_CloseDevice(UInt32 DeviceType, UInt32 DeviceInd);
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_InitCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_INIT_CONFIG pInitConfig);
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_ReadBoardInfo(UInt32 DeviceType, UInt32 DeviceInd, ref VCI_BOARD_INFO pInfo);
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_GetReceiveNum(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_ClearBuffer(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_StartCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_ResetCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_Transmit(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pSend, UInt32 Len);
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_Receive(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pReceive, UInt32 Len, Int32 WaitTime);
/*------------其他函数描述---------------------------------*/
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_ConnectDevice(UInt32 DevType, UInt32 DevIndex);
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_UsbDeviceReset(UInt32 DevType, UInt32 DevIndex, UInt32 Reserved);
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_FindUsbDevice(ref VCI_BOARD_INFO1 pInfo);
[DllImport("controlcan.dll")]
public static extern UInt32 VCI_FindUsbDevice2(ref VCI_BOARD_INFO pInfo);
/*------------函数描述结束---------------------------------*/
}
2.C# 与C++对应的数据模型
/*------------兼容ZLG的数据类型---------------------------------*/
//1.ZLGCAN系列接口卡信息的数据类型。
public struct VCI_BOARD_INFO
{
public UInt16 hw_Version;
public UInt16 fw_Version;
public UInt16 dr_Version;
public UInt16 in_Version;
public UInt16 irq_Num;
public byte can_Num;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public byte[] str_Serial_Num;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
public byte[] str_hw_Type;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] Reserved;
}
/
//2.定义CAN信息帧的数据类型。
unsafe public struct VCI_CAN_OBJ //使用不安全代码
{
public uint ID;
public uint TimeStamp; //时间标识
public byte TimeFlag; //是否使用时间标识
public byte SendType; //发送标志。保留,未用
public byte RemoteFlag; //是否是远程帧
public byte ExternFlag; //是否是扩展帧
public byte DataLen; //数据长度
public fixed byte Data[8]; //数据
public fixed byte Reserved[3];//保留位
}
//3.定义初始化CAN的数据类型
public struct VCI_INIT_CONFIG
{
public UInt32 AccCode;
public UInt32 AccMask;
public UInt32 Reserved;
public byte Filter; //0或1接收所有帧。2标准帧滤波,3是扩展帧滤波。
public byte Timing0; //波特率参数,具体配置,请查看二次开发库函数说明书。
public byte Timing1;
public byte Mode; //模式,0表示正常模式,1表示只听模式,2自测模式
}
/*------------其他数据结构描述---------------------------------*/
//4.USB-CAN总线适配器板卡信息的数据类型1,该类型为VCI_FindUsbDevice函数的返回参数。
public struct VCI_BOARD_INFO1
{
public UInt16 hw_Version;
public UInt16 fw_Version;
public UInt16 dr_Version;
public UInt16 in_Version;
public UInt16 irq_Num;
public byte can_Num;
public byte Reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] str_Serial_Num;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] str_hw_Type;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] str_Usb_Serial;
}
/*------------数据结构描述完成---------------------------------*/
public struct CHGDESIPANDPORT
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public byte[] szpwd;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public byte[] szdesip;
public Int32 desport;
public void Init()
{
szpwd = new byte[10];
szdesip = new byte[20];
}
}
public enum DevType
{
DEV_USBCAN = 3,
DEV_USBCAN2 = 4
}
public class Data
{
public static Dictionary<int, byte[]> Bitrate = new Dictionary<int, byte[]>()
{
{10000, new byte[]{0x31,0x1C}},
{20000, new byte[]{0x18,0x1C}},
{40000, new byte[]{0x87,0xFF}},
{50000, new byte[]{0x09,0x1C}},
{80000, new byte[]{0x83,0xFF}},
{100000, new byte[]{0x04,0x1C}},
{125000, new byte[]{0x03,0x1C}},
{200000, new byte[]{0x81,0xFA}},
{250000, new byte[]{0x01,0x1C}},
{400000, new byte[]{0x80,0xFA}},
{500000, new byte[]{0x00,0x1C}},
{666000, new byte[]{0x80,0xB6}},
{800000, new byte[]{0x00,0x16}},
{1000000, new byte[]{0x00,0x14}},
{33330, new byte[]{0x09,0x6F}},
{66660, new byte[]{0x04,0x6F}},
{83330, new byte[]{0x03,0x6F}},
};
}
3. C#动态库实现
/// <summary>
/// 珠海创芯科技CAN总线分析仪
/// </summary>
public class CAN_zhcxgd : InterfaceCAN
{
private readonly object lock_send = new object();
private VCI_CAN_OBJ[] _vCI_CAN_OBJs = new VCI_CAN_OBJ[2500];
private DevType _devType = DevType.DEV_USBCAN2;
private uint _devIndex = 0;
private int _bitrate;
public byte[] Bitrate { get => Data.Bitrate[_bitrate]; }
public uint int_DevType { get => (uint)_devType; }
public uint ChannelCount { get => _devType == DevType.DEV_USBCAN ? (uint)1 : (uint)2; }
public void SetParameters(int devIndex, int bitrate, params object[] parms)
{
_devIndex = (uint)devIndex;
_bitrate = bitrate;
}
public bool Close()
{
var result = API.VCI_CloseDevice(int_DevType, _devIndex);
return result == 1;
}
public bool Open()
{
var result = API.VCI_OpenDevice(int_DevType, _devIndex, 0) == 1;
if (!result)
return false;
result = Start(Bitrate);
if (!result)
return false;
return true;
}
public bool Send(FrameData frameData)
{
lock (lock_send)
{
VCI_CAN_OBJ vCI_CAN_OBJ = new VCI_CAN_OBJ();
vCI_CAN_OBJ.RemoteFlag = frameData.RemoteFlag;
vCI_CAN_OBJ.ExternFlag = frameData.ExternFlag;
vCI_CAN_OBJ.ID = (uint)frameData.Id;
vCI_CAN_OBJ.DataLen = frameData.DataLen;
WriteUnsafeData(ref vCI_CAN_OBJ, frameData.Data);
var result = API.VCI_Transmit(int_DevType, _devIndex, (uint)frameData.ChannelId, ref vCI_CAN_OBJ, 1);
return result == 1;
}
}
public List<FrameData> Receive()
{
List<FrameData> frameDatas = new List<FrameData>();
for (int i = 0; i < ChannelCount; i++)
{
frameDatas.AddRange(Receive((uint)i));
}
return frameDatas;
}
private List<FrameData> Receive(uint channelId)
{
var result = API.VCI_Receive(int_DevType, _devIndex, channelId, ref _vCI_CAN_OBJs[0], 2500, 100);
if (result < 0)
return null;
List<FrameData> receiveDatas = new List<FrameData>();
for (int i = 0; i < result; i++)
{
FrameData receiveData = new FrameData();
receiveData.ChannelId = (int)channelId;
receiveData.Id = (int)_vCI_CAN_OBJs[i].ID;
receiveData.DataLen = _vCI_CAN_OBJs[i].DataLen;
receiveData.Data = ReadUnsafeData(ref _vCI_CAN_OBJs[i]);
receiveData.TimeStamp = (long)_vCI_CAN_OBJs[i].TimeStamp;
receiveData.RemoteFlag = _vCI_CAN_OBJs[i].RemoteFlag;
receiveData.ExternFlag = _vCI_CAN_OBJs[i].ExternFlag;
receiveData.SendType = _vCI_CAN_OBJs[i].SendType;
receiveData.TimeFlag = _vCI_CAN_OBJs[i].TimeFlag;
unsafe
{
receiveData.Reserved = new byte[3];
receiveData.Reserved[0] = _vCI_CAN_OBJs[i].Reserved[0];
receiveData.Reserved[1] = _vCI_CAN_OBJs[i].Reserved[1];
receiveData.Reserved[2] = _vCI_CAN_OBJs[i].Reserved[2];
}
receiveDatas.Add(receiveData);
}
return receiveDatas;
}
unsafe private void WriteUnsafeData(ref VCI_CAN_OBJ data, byte[] buffer)
{
fixed (byte* ptr = data.Data)
for (int i = 0; i < buffer.Length; i++)
{
ptr[i] = buffer[i];
}
}
unsafe private byte[] ReadUnsafeData(ref VCI_CAN_OBJ data)
{
var buffer = new byte[data.DataLen];
fixed (byte* ptr = data.Data)
for (int index = 0; index < data.DataLen; index++)
{
buffer[index] = ptr[index];
}
return buffer;
}
/// <summary>
/// 启动CAN
/// </summary>
/// <param name="bitrate"></param>
/// <returns></returns>
private bool Start(byte[] bitrate)
{
for (uint i = 0; i < ChannelCount; i++)
{
if (!Init(i, bitrate))
return false;
if (!Start(i))
return false;
}
return true;
}
private bool Init(uint channelNum, byte[] bitrate)
{
VCI_INIT_CONFIG config = new VCI_INIT_CONFIG();
config.AccCode = Convert.ToUInt32("0x00000000", 16);
config.AccMask = Convert.ToUInt32("0xFFFFFFFF", 16);
config.Timing0 = bitrate[0];
config.Timing1 = bitrate[1];
config.Filter = 1;
config.Mode = 0;
var result = API.VCI_InitCAN(int_DevType, _devIndex, channelNum, ref config);
return result == 1;
}
private bool Start(uint channelNum)
{
var result = API.VCI_StartCAN(int_DevType, _devIndex, channelNum);
return result == 1;
}
}
4.使用
static void Main(string[] args)
{
CAN_zhcxgd cAN_Zhcxgd = new CAN_zhcxgd();
cAN_Zhcxgd.SetParameters(0, 100000);
cAN_Zhcxgd.Open();
cAN_Zhcxgd.Send(new FrameData() { ChannelId = 0, Id = 1, Data = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }, DataLen = 8 });
List<FrameData> frameDatas = cAN_Zhcxgd.Receive();
foreach (FrameData frameData in frameDatas)
{
//做点什么
}
}
5.源码以及CANPlus.cs(自用dll)
源码