C# WPF 读写CAN数据
CAN 分析仪
分析仪资料下载
官方地址:https://www.zhcxgd.com/1.html
CSDN:
项目配置
复制Dll库文件
文件在上面的资料里面
设置不安全代码
CAN C#工具类
CAN_Tool.cs
using Microsoft.VisualBasic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
namespace CAN_TEST.tool
{
/*------------兼容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;
//}
//以下为简易定义与调用方式,在项目属性->生成->勾选使用不安全代码即可
unsafe 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;
public fixed byte str_Serial_Num[20];
public fixed byte str_hw_Type[40];
public fixed byte Reserved[8];
}
/
//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 class CAN_Tool
{
const int DEV_USBCAN = 3;
const int DEV_USBCAN2 = 4;
/// <summary>
///
/// </summary>
/// <param name="DeviceType"></param>
/// <param name="DeviceInd"></param>
/// <param name="Reserved"></param>
/// <returns></returns>
/*------------兼容ZLG的函数描述---------------------------------*/
/*------------兼容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_FindUsbDevice2(ref VCI_BOARD_INFO pInfo);
/*------------函数描述结束---------------------------------*/
static UInt32 m_bOpen = 0;
static UInt32 m_devind = 0;
static UInt32 m_canind = 0;
static UInt32[] m_arrdevtype = new UInt32[20];
static VCI_CAN_OBJ[] m_recobj = new VCI_CAN_OBJ[1000];
static UInt32 m_devtype = 4;//USBCAN2
//this.timer_rec = new System.Windows.Forms.Timer(this.components);
public static void init()
{
m_arrdevtype[2] = 3;
m_arrdevtype[3] = 4;
}
public static void close_CAN()
{
CAN_Tool.VCI_CloseDevice(m_devtype, m_devind);
m_bOpen = 0;
}
public static void start_CAN()
{
if (m_bOpen == 0)
return;
CAN_Tool.VCI_StartCAN(m_devtype, m_devind, m_canind);
}
unsafe public static string can_send(string can_data_idText,string can_send_data)
{
if (m_bOpen == 0)
{
MessageBox.Show("CAN断开连接", "错误");
return null;
}
VCI_CAN_OBJ sendobj = new VCI_CAN_OBJ();
//sendobj.Init();
sendobj.RemoteFlag = (byte)0;
sendobj.ExternFlag = (byte)0;
sendobj.ID = System.Convert.ToUInt32("0x" + can_data_idText, 16);
int len = (can_send_data.Length + 1) / 3;
sendobj.DataLen = System.Convert.ToByte(len);
String strdata = can_send_data;
//MessageBox.Show(strdata);
int i = -1;
if (i++ < len - 1)
sendobj.Data[0] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[1] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[2] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[3] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[4] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[5] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[6] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[7] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (CAN_Tool.VCI_Transmit(m_devtype, m_devind, m_canind, ref sendobj, 1) == 0)
{
MessageBox.Show("发送失败", "错误");
return null;
}
else
{
return "TX 帧ID:" + can_data_idText + " 数据: " + can_send_data;
}
}
public static string connect_CAN(int CAN_Type, int CAN_id,int RUN_mod)
{
//以下两行为多卡同机测试代码,用来获取序列号与对应的设备索引号,单卡可以不使用。
VCI_BOARD_INFO[] vbi2 = new VCI_BOARD_INFO[50];
uint num1 = CAN_Tool.VCI_FindUsbDevice2(ref vbi2[0]);
m_devtype = m_arrdevtype[CAN_Type + 2];
m_devind = 0;
m_canind = (UInt32)CAN_id;
if (CAN_Tool.VCI_OpenDevice(m_devtype, m_devind, 0) == 0)
{
MessageBox.Show("打开设备失败,请检查设备类型和设备索引号是否正确", "错误");
m_bOpen = 0;
return "";
}
m_bOpen = 1;
VCI_INIT_CONFIG config = new VCI_INIT_CONFIG();
config.AccCode = System.Convert.ToUInt32("0x" + "00000000", 16);
config.AccMask = System.Convert.ToUInt32("0x" + "FFFFFFFF", 16);
config.Timing0 = System.Convert.ToByte("0x" + "00", 16);
config.Timing1 = System.Convert.ToByte("0x" + "1C", 16);
config.Filter = (Byte)(0 + 1);
config.Mode = (Byte)RUN_mod;
CAN_Tool.VCI_InitCAN(m_devtype, m_devind, m_canind, ref config);
return m_bOpen == 0 ? "断开" : "连接";
}
unsafe public static string TimerRecTick()
{
UInt32 res = new UInt32();
res = CAN_Tool.VCI_Receive(m_devtype, m_devind, m_canind, ref m_recobj[0], 1000, 100);
/
//IntPtr[] ptArray = new IntPtr[1];
//ptArray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(VCI_CAN_OBJ)) * 50);
//IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * 1);
//Marshal.Copy(ptArray, 0, pt, 1);
//MessageBox.Show(res+"");
//res = VCI_Receive(m_devtype, m_devind, m_canind, pt, 50/*50*/, 100);
if (res == 0xFFFFFFFF) res = 0;//当设备未初始化时,返回0xFFFFFFFF,不进行列表显示。
String str = "";
for (UInt32 i = 0; i < res; i++)
{
//VCI_CAN_OBJ obj = (VCI_CAN_OBJ)Marshal.PtrToStructure((IntPtr)((UInt32)pt + i * Marshal.SizeOf(typeof(VCI_CAN_OBJ))), typeof(VCI_CAN_OBJ));
str = "RX: ";
str += " 帧ID:0x" + System.Convert.ToString(m_recobj[i].ID, 16);
str += " 帧格式:";
if (m_recobj[i].RemoteFlag == 0)
str += "数据帧 ";
else
str += "远程帧 ";
if (m_recobj[i].ExternFlag == 0)
str += "标准帧 ";
else
str += "扩展帧 ";
//
if (m_recobj[i].RemoteFlag == 0)
{
str += "数据: ";
byte len = (byte)(m_recobj[i].DataLen % 9);
byte j = 0;
fixed (VCI_CAN_OBJ* m_recobj1 = &m_recobj[i])
{
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[0], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[1], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[2], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[3], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[4], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[5], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[6], 16);
if (j++ < len)
str += " " + System.Convert.ToString(m_recobj1->Data[7], 16);
}
}
return str + "\n";
}
return null;
}
}
}
主界面
MainWindow.xaml
<Window x:Class="CAN_TEST.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="CAN测试" Height="600" Width="400">
<Grid>
<StackPanel>
<StackPanel Orientation="Horizontal" Height="30" Margin="0,20,0,0">
<Button Margin="10,0,0,0" Click="connect_CAN" Width="100">连接分析仪</Button>
<Button Margin="20,0,0,0" Click="close_CAN" Width="100">断开分析仪</Button>
<Button Margin="20,0,0,0" Click="start_CAN" Width="100">启动CAN</Button>
</StackPanel>
<StackPanel Orientation="Horizontal" Height="30" Margin="0,20,0,0">
<StackPanel Orientation="Horizontal" Margin="20,0,0,0">
<TextBlock>CAN类型</TextBlock>
<ComboBox HorizontalAlignment="Center" Width="100" Margin="20,0,0,0" x:Name="CAN_Type">
<ComboBoxItem>USBCAN V1</ComboBoxItem>
<ComboBoxItem>USBCAN V2</ComboBoxItem>
</ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="20,0,0,0">
<TextBlock>CAN通道</TextBlock>
<ComboBox HorizontalAlignment="Center" Width="100" Margin="20,0,0,0" x:Name="CAN_id">
<ComboBoxItem>CAN1</ComboBoxItem>
<ComboBoxItem>CAN2</ComboBoxItem>
</ComboBox>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal" Height="30" Margin="0,20,0,0">
<StackPanel Orientation="Horizontal" Margin="20,0,0,0">
<TextBlock>CAN运行模式</TextBlock>
<ComboBox HorizontalAlignment="Center" Width="100" Margin="20,0,0,0" x:Name="RUN_mod">
<ComboBoxItem>正常</ComboBoxItem>
<ComboBoxItem>只听</ComboBoxItem>
<ComboBoxItem>自测</ComboBoxItem>
</ComboBox>
</StackPanel>
<TextBlock Margin="20,0,0,0">连接状态:</TextBlock>
<TextBlock Text="断开" x:Name="CAN_statusText"></TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical" Width="300" Margin="0,10,0,0">
<TextBlock TextAlignment="Center">数据发送</TextBlock>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBlock TextAlignment="Center" Margin="20,0,0,0">帧ID:</TextBlock>
<TextBox Width="200" Margin="33,0,0,0" x:Name="can_data_id" Text="00000123"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBlock TextAlignment="Center" Margin="20,0,0,0">发送数据:</TextBlock>
<TextBox Width="200" Margin="10,0,0,0" x:Name="can_send_data" Text="00 01 02 03 04 05 06 07 "></TextBox>
</StackPanel>
<Button Width="50" Margin="0,10,0,0" Click="can_send">发送</Button>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock TextAlignment="Center">数据接收</TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBox
Width="350"
Height="200"
Margin="10,0,0,0"
VerticalScrollBarVisibility="Visible"
MaxLines="5"
x:Name="resData"
TextWrapping="Wrap">
</TextBox>
</StackPanel>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs
using CAN_TEST.tool;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Configuration;
using System.Runtime.InteropServices;
using System.Text;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using static CAN_TEST.MainWindow;
namespace HZFM_TEST
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer m_timer = new DispatcherTimer();
public MainWindow()
{
InitializeComponent();
// 初始化CAN
CAN_Tool.init();
// 启动定时器
m_timer.Interval = TimeSpan.FromSeconds(0.2);
m_timer.Tick += new System.EventHandler(timer_rec_Tick);
}
private void close_CAN(object sender, RoutedEventArgs e)
{
// 关闭CAN
CAN_Tool.close_CAN();
}
private void start_CAN(object sender, RoutedEventArgs e)
{
// 启动CAN
CAN_Tool.start_CAN();
}
private void connect_CAN(object sender, RoutedEventArgs e)
{
// 连接CAN分析仪
string outData = CAN_Tool.connect_CAN(CAN_Type.SelectedIndex, CAN_id.SelectedIndex, RUN_mod.SelectedIndex);
if(outData.Length > 0)
{
m_timer.Start();
}
CAN_statusText.Text = outData;
}
// 定时收数据任务
unsafe private void timer_rec_Tick(object sender, EventArgs e)
{
string res = CAN_Tool.TimerRecTick();
if(res != null)
{
resData.AppendText(res + "\r\n");
}
}
// 发送惨数据
unsafe private void can_send(object sender, RoutedEventArgs e)
{
string res = CAN_Tool.can_send(can_data_id.Text, can_send_data.Text);
if (res != null)
{
resData.AppendText(res + "\r\n");
}
}
// 读取数据
private void read_Data(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
int id = int.Parse(btn.CommandParameter.ToString()) + 1;
string res = CAN_Tool.can_send("01800300", can_send_data.Text);
if (res != null)
{
resData.AppendText(res + "\r\n");
}
}
}
}