基于CAN总线的汽车诊断协议UDS(上位机开发驱动篇)

本文介绍了如何为不同品牌的CAN分析仪开发UDS上位机驱动,包括广成、周立功及Kvaser品牌。通过创建ECANDLL类并调用各品牌提供的DLL文件实现CAN通信的基本操作。

本篇作为UDS上位机的驱动开发篇,从市面上多见的CAN分析仪着手介绍UDS上位机驱动开发和移植的一般过程,目的是使UDS上位机软件能适应多家CAN分析仪,降低使用者的硬件成本。

一:广成CAN分析仪的驱动开发

首先创建ECANDLL类,从广成提供的二次开发包中获取ECANVCI.dll文件,将DLL文件放置与生成程序的目录中,如下类中创建了CAN常用的控制函数。

    public static class ECANDLL

    {

 

        [DllImport("ECANVCI.dll", EntryPoint = "OpenDevice")]

        public static extern ECANStatus OpenDevice(

            UInt32 DeviceType,

            UInt32 DeviceInd,

            UInt32 Reserved);

 

        [DllImport("ECANVCI.dll", EntryPoint = "CloseDevice")]

        public static extern ECANStatus CloseDevice(

            UInt32 DeviceType,

            UInt32 DeviceInd);

 

 

        [DllImport("ECANVCI.dll", EntryPoint = "InitCAN")]

        public static extern ECANStatus InitCAN(

            UInt32 DeviceType,

            UInt32 DeviceInd,

            UInt32 CANInd,

            ref INIT_CONFIG InitConfig);

 

 

        [DllImport("ECANVCI.dll", EntryPoint = "StartCAN")]

        public static extern ECANStatus StartCAN(

            UInt32 DeviceType,

            UInt32 DeviceInd,

            UInt32 CANInd);

 

 

        [DllImport("ECANVCI.dll", EntryPoint = "ResetCAN")]

        public static extern ECANStatus ResetCAN(

            UInt32 DeviceType,

            UInt32 DeviceInd,

            UInt32 CANInd);

 

 

        [DllImport("ECANVCI.dll", EntryPoint = "Transmit")]

        public static extern ECANStatus Transmit(

            UInt32 DeviceType,

            UInt32 DeviceInd,

            UInt32 CANInd,

            ref CAN_OBJ Send,

            UInt16 length);

 

 

        [DllImport("ECANVCI.dll", EntryPoint = "Receive")]

        public static extern ECANStatus Receive(

            UInt32 DeviceType,

            UInt32 DeviceInd,

            UInt32 CANInd,

            out CAN_OBJ Receive,

            UInt32 length,

            UInt32 WaitTime);

 

        [DllImport("ECANVCI.dll", EntryPoint = "ReadErrInfo")]

        public static extern ECANStatus ReadErrInfo(

            UInt32 DeviceType,

            UInt32 DeviceInd,

            UInt32 CANInd,

            out CAN_ERR_INFO ReadErrInfo);

 

    }

在MainForm中,针对不同的控件调用不同的控制函数

如初始化:

INIT_CONFIG init_config = new INIT_CONFIG();

 

                    init_config.AccCode = 0;

                    init_config.AccMask = 0xffffff;

                    init_config.Filter = 0;

 

                    switch (m_Baudrate)

                    {

                        case 0: //1000

 

                            init_config.Timing0 = 0;

                            init_config.Timing1 = 0x14;

                            break;

                        case 1: //800

 

                            init_config.Timing0 = 0;

                            init_config.Timing1 = 0x16;

                            break;

                        case 2: //666

 

                            init_config.Timing0 = 0x80;

                            init_config.Timing1 = 0xb6;

                            break;

                        case 3: //500

 

                            init_config.Timing0 = 0;

                            init_config.Timing1 = 0x1c;

                            break;

                        case 4://400

 

                            init_config.Timing0 = 0x80;

                            init_config.Timing1 = 0xfa;

                            break;

                        case 5://250

 

                            init_config.Timing0 = 0x01;

                            init_config.Timing1 = 0x1c;

                            break;

                        case 6://200

 

                            init_config.Timing0 = 0x81;

                            init_config.Timing1 = 0xfa;

                            break;

                        case 7://125

 

                            init_config.Timing0 = 0x03;

                            init_config.Timing1 = 0x1c;

                            break;

                        case 8://100

 

                            init_config.Timing0 = 0x04;

                            init_config.Timing1 = 0x1c;

                            break;

                        case 9://80

 

                            init_config.Timing0 = 0x83;

                            init_config.Timing1 = 0xff;

                            break;

                        case 10://50

 

                            init_config.Timing0 = 0x09;

                            init_config.Timing1 = 0x1c;

                            break;

 

                    }

 

                    init_config.Mode = 0;

                   

                    if (ECANDLL.OpenDevice(m_devtype, m_devind, 0) != ECAN.ECANStatus.STATUS_OK)

                    {

                        MessageBox.Show("Open device fault!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);

                        return;

                    }

                    //Set can1 baud

                    if (ECANDLL.InitCAN(m_devtype, m_devind, 0, ref init_config) != ECAN.ECANStatus.STATUS_OK)

                    {

 

                        MessageBox.Show("Init can fault!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);

 

                        ECANDLL.CloseDevice(1, 0);

                        return;

                    }

 

二:周立功CAN分析仪驱动开发

                周立功的CAN分析仪与广成基本相同,将DLL文件替换为周立功的DLL文件。在初始化和其他调用函数中注意m_devtype和m_devind与广成的不同,这两个变量的取值可通过不同厂家的测试软件中获取。

一般的广成m_devtype =1,m_devind=0,周立功USBCAN II m_devtype =4,m_devind=0.

ECANDLL.OpenDevice(m_devtype, m_devind, 0)

 

三:Kvaser CAN分析仪驱动开发

Kvaser CAN驱动开发与上述两者差别较大。

首先引入驱动DLL文件

 

 

以下是初始化过程

               int hnd = Canlib.canOpenChannel(channel, Canlib.canOPEN_ACCEPT_VIRTUAL);

 

                CheckStatus("Open channel", (Canlib.canStatus)hnd);

                if (hnd >= 0)

                {

                    handle = hnd;

                }

 

                int[] bitrates = new int[] {

                Canlib.BAUD_1M,

                Canlib.BAUD_500K,

                Canlib.BAUD_250K,

                Canlib.BAUD_125K,

                Canlib.BAUD_100K,

                Canlib.BAUD_83K,

                Canlib.BAUD_62K,

                Canlib.BAUD_50K,

                };

                int bitrate = bitrates[comboBoxBaud.SelectedIndex];

                Canlib.canStatus status = Canlib.canSetBusParams(handle, bitrate, 0, 0, 0, 0, 0);

                CheckStatus("Setting bitrate to " + comboBoxBaud.SelectedItem, status);

 

 

                Canlib.canBusOn(handle);

 

                CheckStatus("Bus on", status);

                    if (status == Canlib.canStatus.canOK)

                    {

                        onBus = true;

                        /*

                        if (!dumper.IsBusy)

                        {

                            dumper.RunWorkerAsync();

                        }*/

                    }

写CAN报文函数

Canlib.canStatus status = Canlib.canWrite(handle, id, dat, dlc, flags);

读CAN报文函数

status = Canlib.canReadWait(handle, out id, dat, out dlc, out flags, out time, 50);

转载于:https://www.cnblogs.com/qq2020809663/p/8998191.html

<think>嗯,用户的问题是关于PCAN UDS上位机开发的,涉及通信协议、设备驱动和软件开发三个方面。从用户提到的引用内容来看,用户可能正在搭建一个基于PCAN硬件的UDS诊断系统,需要从底层硬件驱动到上层协议实现的完整解决方案。 用户可能是个汽车电子工程师或嵌入式开发者,正在尝试开发诊断设备。引用[1]提到PCAN设备操作和Visual Studio开发环境,引用[2]描述了CAN硬件设计,引用[3]则涉及OSI模型——这些正好对应开发UDS上位机的三个关键层:物理层(PCAN硬件)、数据链路层(CAN驱动)、应用层(UDS协议)。 注意到用户特别强调"通信协议"部分,说明对UDS协议栈的实现细节有强烈需求。用户可能遇到的具体难点包括:如何将PCAN的底层API与UDS服务对接,如何处理多帧传输,以及如何管理诊断会话状态机。 在硬件驱动层面,需要提醒用户注意PCAN官方API的调用规范。引用[1]提到软件集成了PCAN USB操作,但实际开发中要特别注意接收超时处理和错误帧统计——这点在引用[2]的故障诊断算法里有印证。建议用户直接使用PCAN-Basic API而不是自己封装DLL,可以避免很多兼容性问题。 对于软件开发架构,考虑到用户使用C#(基于引用[1]的VS2013环境),应该推荐MVVM模式分离界面逻辑和协议解析。引用[3]的OSI模型在这里很实用,需要明确UDS属于应用层协议,而PCAN驱动处理的是物理层到数据链路层。 用户可能没意识到但实际很重要的点是时间同步问题。UDS的P2/P2*超时判定需要高精度计时器,这在Windows非实时系统上容易出问题。建议在回复时补充硬件时间戳的获取方法。 最后生成的三个问题都指向具体实施细节:第一个问题针对UDS特有的否定响应处理,这是协议实现中最易出错的部分;第二个问题聚焦硬件异常处理,引用[2]的故障诊断算法正好用上;第三个则解决实际工程中的性能瓶颈。</think>针对PCAN UDS上位机开发,结合通信协议、设备驱动和软件开发三方面,核心开发要点如下: --- ### 一、通信协议层实现 1. **UDS协议开发** - **服务实现**:需实现ISO 14229-1定义的26项核心服务(如$0x10$诊断会话控制、$0x22$读数据标识符) - **多帧传输**:支持ISO 15765-2定义的流控帧(Flow Control)和连续帧(Consecutive Frame),处理分包/重组逻辑 - **时序管理**:严格遵守P2/P2*超时(默认50ms/5000ms)[^3] 2. **CAN底层适配** - 采用**J1939/TP**或**CANopen**作为传输层协议(引用[2][3]) - 帧格式处理: ```c // 扩展帧示例 (29位ID) typedef struct { uint32_t id; // 0x18DAF1XX (XX:目标地址) uint8_t data[8]; uint8_t len; } CAN_Frame; ``` --- ### 二、设备驱动集成 1. **PCAN硬件操作** - **初始化流程**: ```csharp // C#示例 (PCAN-Basic.dll) TPCANStatus result = PCANBasic.Initialize( PCANBasic.PCAN_USBBUS1, TPCANBaudrate.PCAN_BAUD_500KBPS, PCANBasic.PCAN_FILTER_OPEN); ``` - **数据收发**: - 接收:使用`PCANBasic.Read()` + 回调事件处理 - 发送:构造`TPCANMsg`结构体调用`PCANBasic.Write()`[^1] 2. **抗干扰设计** - 硬件层:TVS二极管防护 + 共模扼流圈(引用[2]) - 软件层:CRC校验 + 自动重发机制(最大重试3次) --- ### 三、软件开发关键模块 ```mermaid graph TD A[上位机架构] --> B[驱动层] A --> C[协议层] A --> D[应用层] B --> B1[PCAN设备初始化] B --> B2[CAN帧收发] C --> C1[UDS服务解析] C --> C2[多帧组装] D --> D1[诊断控制台] D --> D2[故障码解析] D --> D3[刷写流程] ``` 1. **分层架构实现** - **驱动层**:封装PCAN API,提供`CAN_Init()`, `CAN_Send()`, `CAN_Receive()`接口 - **协议层**:实现UDS状态机,处理正/负响应码(如$0x7F$否定响应) - **应用层**: - 诊断控制台(会话模式切换、DID读取) - 基于ISO 15765的ECU刷写(例程控制$0x31$) 2. **开发工具链** - IDE:Visual Studio(C#/C++)(引用[1]) - 测试工具:CANoe模拟节点 + PCAN-View监控总线 --- ### 四、典型代码流程(UDS请求) ```python # 伪代码流程 def UDS_ReadDataByIdentifier(device, did): # 构造请求帧 frame = CAN_Frame(id=0x18DAF1EC, data=[0x22, did>>8, did&0xFF]) device.Send(frame) # 等待响应(带超时) response = device.Receive(timeout=0.5) if response[0] == 0x62: # 肯定响应 return response[1:] # 返回数据 elif response[0] == 0x7F: # 否定响应 raise Exception(f"NegResp: 0x{response[2]:02X}") ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值