C# WPF实现读写CAN数据
作者:鸿喵小仙女
这篇文章主要介绍了C# WPF实现读写CAN数据,文中通过代码示例给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
项目配置
复制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"); } } } }
到此这篇关于C# WPF实现读写CAN数据的文章就介绍到这了,更多相关C#读写CAN数据内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!