From 833d4633ea5665ffc9eea848e916602c6d81b736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AD=B1=E5=82=91?= <840465812@qq.com> Date: Mon, 6 May 2019 16:39:56 +0800 Subject: [PATCH] Add CAN README.md and update CANHelper.cs --- CANHelper/README.md | 116 ++++++++++++++++++++++++++++++++++ CANHelper/USBCAN/CANHelper.cs | 30 +++++---- 2 files changed, 135 insertions(+), 11 deletions(-) create mode 100644 CANHelper/README.md diff --git a/CANHelper/README.md b/CANHelper/README.md new file mode 100644 index 0000000..f001289 --- /dev/null +++ b/CANHelper/README.md @@ -0,0 +1,116 @@ +# CANHelper + + +## 文件结构 + +| 文件 | 简介 | +| ---- | ---- | +| **CAN_API.cs** | USBCAN API声明 | +| **CANHelper.cs** | 帮助类 | +| **kerneldll.ini** | 配置文件 | +| **usbcan.dll** | USBCAN核心DLL | +| **ControlCAN.dll** | CAN控件DLL | + +> **在使用时需要注意,`ControlCAN.dll`与`kerneldlls`必须输出到应用程序目录中** + +## CANHelper说明 + +### 类成员 + +#### 公开属性 +| 名称 | 简介 | +| ---- | ---- | +| `IsOpen` | CAN是否打开 | + +#### 公开方法 + +| 名称 | 简介 | +| ---- | ---- | +| `Initialize` | 初始化并打开CAN设备 | +| `CloseDevice` | 关闭CAN设备 | +| `ReadErrorMessage` | 读取错误信息 | +| `SendData` | 向CAN发送数据帧 | + +#### 公开事件与委托 + + +| 类型 | 名称 | 简介 | +| --- | ---- | ---- | +| delegate | ConsumptionFrameEventHandler | 消费帧事件委托 | +| event | ConsumptionFrameEvent | 消费帧事件 | + +### 使用示例 + +#### 简单说明 +```C# +// 启动之前,监听消费帧事件,以处理数据 +USBCAN.CANHelper.Instance.ConsumptionFrameEvent += frame => +{ + Console.WriteLine("ID:{0:X}\tTimeStamp:{1}\tTimeFlag:{2}\tSendType:{3}\tRemoteFlag:{4}\tExternFlag:{5}\tDataLen:{6}\tData:{7}\tReserved:{8}\n", + frame.ID, frame.TimeStamp, frame.TimeFlag, frame.SendType, frame.RemoteFlag, frame.ExternFlag, frame.DataLen, str, string.Join(",", frame.Reserved); +}; + +// 初始化设备并启动 +USBCAN.CANHelper.Instance.Initialize(); + +// 发生数据到CAN设备 +USBCAN.CANHelper.Instance.SendData(0x200, new byte[8] { 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }); + +// 关闭CAN设备 +USBCAN.CANHelper.Instance.CloseDevice(); +``` + + +#### 较完整示例 +```C# +public MainWindow() +{ + InitializeComponent(); + + // 监听消费帧事件 + USBCAN.CANHelper.Instance.ConsumptionFrameEvent += Instance_ConsumptionFrameEvent; +} + +private void Instance_ConsumptionFrameEvent(USBCAN.CAN_API.VCI_CAN_OBJ frame) +{ + Dispatcher.Invoke(new Action(() => + { + //string.Join(",", frame.Data); + StringBuilder sb = new StringBuilder(32); + foreach (var item in frame.Data) + sb.AppendFormat("{0:X} ", item); + + // 输出帧数据 + txtOutput.AppendText(string.Format("ID:{0:X}\tTimeStamp:{1}\tTimeFlag:{2}\tSendType:{3}\tRemoteFlag:{4}\tExternFlag:{5}\tDataLen:{6}\tData:{7}\tReserved:{8}\n", + frame.ID, frame.TimeStamp, frame.TimeFlag, frame.SendType, frame.RemoteFlag, frame.ExternFlag, frame.DataLen, sb.ToString(), string.Join(",", frame.Reserved))); + txtOutput.ScrollToEnd(); + })); +} + +private void CekStart_Checked(object sender, RoutedEventArgs e) +{ + try + { + // 初始化设备 + USBCAN.CANHelper.Instance.Initialize(); + } + catch (Exception ex) + { + // 启动发生异常,输出异常信息与CAN错误信息 + MessageBox.Show(ex.Message + USBCAN.CANHelper.Instance.ReadErrorMessage()); + } +} + +private void CekStart_Unchecked(object sender, RoutedEventArgs e) +{ + // 关闭设备 + USBCAN.CANHelper.Instance.CloseDevice(); +} +``` + +### 注意 +* CANHelper内部使用生产者消费者模型,可以解决高速通信与缓速处理导致阻塞的问题,即读取数据与处理数据为不同线程执行 +* 初始化与关闭可以安全的反复调用,若初始化失败,抛出的异常中含有错误的详细信息 +* 可以通过`ReadErrorMessage`方法读取CAN的错误信息 +* 发生数据`SendData`时参数`data`必须是长度为`8`的`byte[]` +* 代码中有详细的注释 \ No newline at end of file diff --git a/CANHelper/USBCAN/CANHelper.cs b/CANHelper/USBCAN/CANHelper.cs index 4e0bf77..3d358ef 100644 --- a/CANHelper/USBCAN/CANHelper.cs +++ b/CANHelper/USBCAN/CANHelper.cs @@ -31,6 +31,12 @@ namespace USBCAN public bool IsOpen { private set; get; } = false; #endregion + #region 构造 + private CANHelper() + { + } + #endregion + #region 释放 /// /// Flag: 标识Disposed是否已经被调用 @@ -162,7 +168,7 @@ namespace USBCAN // 若无错误信息,则返回‘无错误信息’ return "无错误信息"; } - + // 由于可能同时出现多种错误,使用按位与的方式读取错误信息 List errMsgList = new List(); if ((errInfo.ErrCode & (uint)CAN_API.ErrorType.ERR_CAN_OVERFLOW) != 0) @@ -237,6 +243,18 @@ namespace USBCAN #endregion + #region 公开事件与委托 + /// + /// 消费帧事件委托 + /// + /// 报文帧 + public delegate void ConsumptionFrameEventHandler(CAN_API.VCI_CAN_OBJ frame); + /// + /// 消费帧事件 每读取一帧数据发生一次消费帧事件 + /// + public event ConsumptionFrameEventHandler ConsumptionFrameEvent; + #endregion + #region 生产者消费者模式 - 生产数据帧,发出事件消费数据帧 /// /// 帧缓冲区(生产者消费者队列) @@ -250,16 +268,6 @@ namespace USBCAN /// 消费者线程 /// private Thread _ConsumerThread; - /// - /// 消费帧事件委托 - /// - /// 报文帧 - public delegate void ConsumptionFrameEventHandler(CAN_API.VCI_CAN_OBJ frame); - /// - /// 消费帧事件 - /// - public event ConsumptionFrameEventHandler ConsumptionFrameEvent; - /// /// 开始工作线程 ///