拒绝造轮子(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 获取
结束
积跬步以至千里:) (:一阵没来由的风