拒絕造輪子(C#篇)ZLG CAN卡驅動封裝應用
今天給大家介紹一個封裝完善的CAN卡類。
背景
在面對常規開發場景,開發者對復雜SDK進行封裝和測試。閱讀相關開發資料和理解SDK的DEMO程序。
開篇
如果你也有同樣的煩惱,那就來看看今天跟大家分享的庫。
Gycylm.Tools.Devices.Cans.Zlg (獲取方法放在文末尾)
該庫文件提供一個非常好用的類CanCommService,提供了我們想要訪問設備的所有操作,精巧的封裝到3個事件、和4個方法中。如下所示:
? ? ? ?/// <summary>/// 當通道斷開了,通知外部/// </summary>event Action<ChannelConfig> ChannelDisconned;/// <summary>/// 當數據收到了,通知外部/// </summary>event Action<ICanChannelService, List<UniversalCanMessage>> CanDataComed;/// <summary>/// 當有數據發送出去時,通知外部/// </summary>event Action<ICanChannelService, List<UniversalCanMessage>> CanDataSent;/// <summary>/// 發生數據/// </summary>/// <param name="ccc"></param>/// <param name="protocolId"></param>/// <param name="data"></param>/// <returns></returns>Boolean Send(ChannelConfig ccc, UInt32 protocolId, Byte[] data);/// <summary>/// 打開指定通道/// </summary>/// <param name="ccc">通道配置信息</param>/// <returns></returns>Boolean Open(ChannelConfig ccc);/// <summary>/// 關閉指定 <see cref="ChannelConfig.Id"/> 的通道/// </summary>/// <param name="id">通道配置信息的<see cref="ChannelConfig.Id"/></param>/// <returns></returns>Boolean Close(UInt32 id);/// <summary>/// 關閉所有通道/// </summary>void CloseAll();
該方法是針對所有的基礎CAN卡通信的封裝,可以通過使用上面的方法實現對CAN設備的基本操作
-
配置
-
打開
-
關閉
-
數據發送
-
數據接收
同時支持CAN/CANFD,通道分離,支持ZLG的USB CAN卡設備。
CAN卡配置信息如下
? /// <summary>/// CAN 設備通道配置信息/// </summary>public class ChannelConfig{/// <summary>/// CAN 設備通道唯一 ID/// </summary>public UInt32 Id { get; set; } ?/// <summary>/// CAN 設備類型,具體見 CanCategory 枚舉/// </summary>public CanCategory CCategroy { get; set; } = CanCategory.ZLG_USBCAN_2; ?/// <summary>/// CAN 設備索引 0 1 2 3 4 .../// </summary>public Byte CanIndex { get; set; } ?/// <summary>/// 通道索引 0 1 2 3 .../// </summary>public Byte ChannelIndex { get; set; } ?/// <summary>/// 數據協議/// </summary>public DataProtocol DataProto { get; set; } = DataProtocol.CAN; ?/// <summary>/// 通道波特率/// </summary>public ChannelBaudRate BaudRate { get; set; } = ChannelBaudRate._1000Kbps; ?/// <summary>/// 數據波特率/// </summary>public ChannelDataBaudRate DataBaudRate { get; set; } = ChannelDataBaudRate.None;/// <summary>/// 啟用終端電阻/// </summary>public ChannelInternalResistance InternalResistance { get; set; } = ChannelInternalResistance.Disable; ?public override string ToString(){return $"Id = {Id};\n" +$"CCategroy = {CCategroy};\n" +$"CanIndex = {CanIndex};\n" +$"ChannelIndex = {ChannelIndex};\n" +$"DataProto = {DataProto};\n" +$"BaudRate = {BaudRate};\n" +$"DataBaudRate = {DataBaudRate};\n" +$"InternalResistance = {InternalResistance}";}} ?
CAN 消息定義如下:
[StructLayout(LayoutKind.Sequential, Pack = 1)]public struct UniversalCanMessage{/// <summary>/// 報文 ID/// </summary>public UInt32 ID;/// <summary>/// 報文數據內容長度/// 不是DataLengthCode/// 如果需要獲得真實的DLC,需要自己再換算<see cref="DataConverter.DataLen2DLC(int)"/>/// </summary>public Byte DLC;/// <summary>/// CAN 通道接收時間戳,相對于 CAN 打開時間,單位微秒/// </summary>public UInt64 TIMESTAMP;/// <summary>/// 報文數據內容,根據 DLC 來判斷真實有效數據內容/// </summary>[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]public Byte[] DATA; ?public override string ToString(){var sb = new System.Text.StringBuilder();sb.AppendLine($"ID = 0x{ID:X8}");sb.AppendLine($"DLC = {DLC}");sb.AppendLine($"TIMESTAMP = {TIMESTAMP} us"); ?sb.Append("DATA = ");if (DATA != null){for (int i = 0; i < DLC && i < DATA.Length; i++){sb.Append($"{DATA[i]:X2} ");}}else{sb.Append("null");} ?return sb.ToString().TrimEnd();}} ?
Gycylm.Tools.Devices.Cans.Zlg 該庫只針對ZLG USBCAN進行了封裝,其中還有其他庫實現了Vector、PCAN、GCAN...等常見CAN的封裝適配。
筆者對CAN通信上位機開發略有經驗,歡迎交流。
整理不易,如有需要,聯系 mefdeamon@qq.com 獲取
結束
積跬步以至千里:) (:一陣沒來由的風