技术博客

28/07/2022 作者 Lars-Göran Fredriksson

将DINRail SE410S-X10作为CAN FD转换器使用

在本博客中,我将展示如何使用Kvaser DINRail作为CAN FDCAN转换器。我将使用一个已定义信号的数据库,并展示如何在t脚本中使用它们。新的Kvaser DIN Rail SE410S-X10允许创建独立的CAN转换单元,而不需要额外的电脑来运行。

本博客所需的所有信息和工具均不需要许可证,可在我们的主页www.kvaser.cn上获取。

本博客中提到的所有代码示例和模型都可以免费使用。

任何具有t编程功能的Kvaser多通道设备都可以用于测试和调试。我将使用Kvaser DIN Rail SE410S-X10

如果你对本博客有任何疑问,请随时与我们联系。只需将问题或评论发送至:SUPPORT@KVASER.COM

现场应用工程师, Kvaser AB

Lars-Göran Fredriksson

lgfr@kvaser.com

1 测试模型

我没有一个可用的物理网络,所以需要创建一个。我决定使用一个CAN FD网络和一个标准CAN网络:

我必须说,这是一幅非常美丽的图画。我要显示的是两路端接良好的CAN总线,连接到一个DINRail SE410适配器。


1.1 我的CAN FD网络

在我的FD网络(连接到通道1和通道2的网络)上有一个神奇的设备,它可以发送和接收报文TEST_MSG_101。它是一个ID101CAN FD帧,包含八种不同的信号:纬度、经度、高度、地面速度、地面航向、横滚、俯仰和航向。这些可以是来自组合式GPS/陀螺传感器的典型值。


1.2 我的(标准)CAN网络

在我的标准CAN网络(连接到通道3和通道4的网络)上,我有三个神奇的设备,可以发送和接收报文TEST_MSG_201TEST_MSG_202TEST_MSG_203

第一帧报文处理横滚、俯仰和航向信号。第二帧处理纬度、经度和高度。第三帧处理地面速度和地面航向。

(请查看附录A以了解对DBC文件和这些信号的解释)

为什么我要创建一个不存在的网络?大多数情况下,当使用DBC文件时,通信协议遵循J1939标准。J1939SAE拥有的标准,我不可以发布他们的任何协议或信号id

DINRail上,通道13将用于t脚本。通道24将用作调试通道,以便我可以模拟我的神奇设备。(我将使用Kvaser CANKing软件在通道2和通道4上发送和接收文本报文。)


2 关于t脚本

(要了解如何使用t脚本,请查看5.4)

(在附录AB中,你可看到完整的t脚本文件和DBC文件目录)


2.1 基本设置

variables {
  const int MyCANFDch=0;
  const int MyCANch=2;
}

on start {
  printf("Script started...\n");

  canBusOff(MyCANFDch);
  canBusOff(MyCANch);

  //Set First channel (FD)
  canSetBitrate(MyCANFDch,canFD_BITRATE_500K_80P);
  canSetBusOutputControl(MyCANFDch, canDRIVER_NORMAL);

  canSetBitrateFd(MyCANFDch,canFD_BITRATE_2M_80P);
  canSetCommunicationMode(MyCANFDch, canMODE_CAN_FD);

  //Set Second channel (STD)
  canSetBitrate(MyCANch,canBITRATE_250K);
  canSetBusOutputControl(MyCANch, canDRIVER_NORMAL);


  canBusOn(MyCANFDch);
  canBusOn(MyCANch);
}

on stop {
  canBusOff(MyCANFDch);
  canBusOff(MyCANch);
printf("Script stopped...\n");
}

这个脚本几乎做不了什么,但是它最重要的作用是启动两个CAN通道。

第一个通道设置为500kbit/2Mbit CAN FD通道,第二个通道设置为250kbit标准CAN通道。

如果我们在TRX中编译并运行这个脚本,我们将看到此脚本开始和停止。

好吧,正是我们想要的,但还没有开始施展魔法。


2.2 添加文件DB_FD.DBC

打开菜单:项目,选择:添加数据库(Add Database)

将出现一个对话框,你可以给你的项目添加DBC文件。

重要提示:必须保存你的项目。如果使用FILE/SAVE,则只能保存t文件。你需要使用PROJECT/Save PROJECT As(项目/另存为项目)


2.3使用DBC报文作为变量

当我们给项目添加DBC文件后,就可以创建报文和信号变量。

DBC文件中定义的CAN报文之一是:TEST_MSG_101

现在我将创建此类型的一个全局变量(FD_GPS)
在此块里: Variables {},添加以下行:
CanMessageFd_TEST_MSG_101 FD_GPS;

MessageName中添加文本“CanMessageFD_”TRX将理解应该在DBC文件中查找它。

variables  {
  const int MyCANFDch =0;
  const int MyCANch   =2;

  CanMessageFd_TEST_MSG_101 FD_GPS;


  int FD_GPS_TEST=0;

}

现在我已得到了一个可用的全局变量。


2.4 以DBC报文作为标识符

on CanMessageFd <MyCANFDch> TEST_MSG_101 {
  printf("Detected TEST_MSG_101 :%d\n", this.id);
}

每当CAN FD总线上出现ID101的报文时,此HOOK将被激活。

现在魔法来了:我们可以使用这些信号的物理值,而无需任何繁琐的高级计算。

on CanMessageFd <MyCANFDch> TEST_MSG_101 {
  printf("Detected TEST_MSG_101 :%d\n", this.id);

  printf("LAT P:%f\n", this.S_101_LAT.Phys);
  printf("LAT R:%d\n", this.S_101_LAT.Raw);
}

运行上述脚本,并检测“101”报文。

我们可以直接寻址信号S_101_LAT中的数据。我们可将其作为物理值(Physical values)或原始值(Raw values)访问。在上面的输出中,我们可以看到1800000的值相当于0.000度。(虽然它打印出来是0.000015,但已经非常接近0.000


2.5 添加一个CanMessageFdhook

on CanMessageFd <MyCANFDch> TEST_MSG_101 {
  CanMessage_TEST_MSG_201   STD_GPS_RPH;
  CanMessage_TEST_MSG_202   STD_GPS_LatLonAlt;
  CanMessage_TEST_MSG_203   STD_GPS_SogCog;

//  printf("Detected TEST_MSG_101 :%d\n", this.id);
//  printf("LAT P:%f\n", this.S_101_LAT.Phys);
//  printf("LAT R:%d\n", this.S_101_LAT.Raw);

  STD_GPS_RPH.S_201_ROLL.Phys      =this.S_101_ROLL.Phys;
  STD_GPS_RPH.S_201_PITCH.Phys     =this.S_101_PITCH.Phys;
  STD_GPS_RPH.S_201_HEAD.Phys      =this.S_101_HEADING.Phys;
  canWrite(MyCANch,STD_GPS_RPH);
  
  STD_GPS_LatLonAlt.S_202_LAT.Phys =this.S_101_LAT.Phys;
  STD_GPS_LatLonAlt.S_202_LON.Phys =this.S_101_LON.Phys;
  STD_GPS_LatLonAlt.S_202_ALT.Phys =this.S_101_ALT.Phys;
  canWrite(MyCANch,STD_GPS_LatLonAlt);

  STD_GPS_SogCog.S_203_SOG.Phys    =this.S_101_SOG.Phys;
  STD_GPS_SogCog.S_203_COG.Phys    =this.S_101_COG.Phys;
  canWrite(MyCANch,STD_GPS_SogCog);
}

FD 报文“101”将被分为3个标准CAN报文。

201202203报文中的信号在其值中的分辨率较低,但我们不需要担心这一点。t脚本将承担逻辑位和字节的翻译。


2.6添加3个 CanMessage hooks

on CanMessage <MyCANch> TEST_MSG_201 {

  FD_GPS.S_101_ROLL.Phys    =this.S_201_ROLL.Phys;
  FD_GPS.S_101_PITCH.Phys   =this.S_201_PITCH.Phys;
  FD_GPS.S_101_HEADING.Phys =this.S_201_HEAD.Phys;

  FD_GPS_TEST= (FD_GPS_TEST | 1);  

  if (FD_GPS_TEST>=7) {
    canWrite(MyCANFDch,FD_GPS);
    FD_GPS_TEST=0;
  }
}
on CanMessage <MyCANch> TEST_MSG_202 {

  FD_GPS.S_101_LAT.Phys  =this.S_202_LAT.Phys;
  FD_GPS.S_101_LON.Phys  =this.S_202_LON.Phys;
  FD_GPS.S_101_ALT.Phys  =this.S_202_ALT.Phys;

  FD_GPS_TEST= (FD_GPS_TEST | 2);  

  if (FD_GPS_TEST>=7) {
    canWrite(MyCANFDch,FD_GPS);
    FD_GPS_TEST=0;
on CanMessage <MyCANch> TEST_MSG_203 {

  FD_GPS.S_101_COG.Phys  =this.S_203_COG.Phys;
  FD_GPS.S_101_SOG.Phys  =this.S_203_SOG.Phys;

  FD_GPS_TEST= (FD_GPS_TEST | 4);  

  if (FD_GPS_TEST>=7) {
    canWrite(MyCANFDch,FD_GPS);
    FD_GPS_TEST=0;
    FD_GPS_TEST=(FD_GPS_TEST & (1+2+0));
  }
}

我们必须在收到所有3条报文后,才能重新传输“101”报文。


3将t脚本保存到内存中

Kvaser DIN Rail SE410S-X10具备电池支持的16GB不可替换内存。它通过电池确保所有未提交的更改在关机前正确保存。

内存区域可用于存储本地数据和t脚本。可通过SDK(CANlib)t脚本或Kvaser Device Guide (1)(2)中的filehandler对内存进行修改。

(1) 具备filehandler2020-12-20版本尚未发布。计划与5.36版一起发布。

(2) 如果你在CANlib SDK 5.36发布之前阅读此博客,并且想测试filehandler,请发电子邮件给我,我会将其发给你。(lgfr@kvaser.com)

有关详细的内存限制,请参见附录C


3.1自动启动t脚本

(此信息也可在用户指南中查看)

Kvaser DIN Rail SE410S-X10在通电时可通过内存自动加载和运行最多四个t脚本。这是通过将t脚本的名称输入到一个特定文件,autoexec.txt来实现的,并复制已编译的t脚本(*.TXE)和AUTOEXEC.TXT到内存。

要停止t脚本在通电时启动,只需从闪存中删除AUTOEXEC.TXT或编辑AUTOEXEC.TXT文件。


3.2 AUTOEXEC.TXT

这是一个特殊的文本文件,Kvaser DIN Rail SE410S-X10在通电时会从闪存中读取它。每行必须具有以下格式

Filename,Channel,slot(文件名,通道,插口)


3.2.1 文件名

文件名是已编译的t脚本的名称。它的扩展名是TXE


3.2.2 通道

通道是t脚本默认使用的CAN通道。(在我们的脚本中没有使用默认通道)

(有关更多详细信息,请参阅Kvaser t编程语言指南。)


3.2.3 插口

插口是Kvaser DIN Rail SE410S-X10t脚本可用的四个编号为03的插口之一。


3.3 我们的AUTOEXEC.TXT文件

我命名我的t脚本为: T-DEM-FD

编译名称: T-DEM-FD.TXE

让我们通过以下行创建一个名为“autoexec.txt”的文件:

T-DEM-FD.TXE, 0, 0

启动T-DEM-FD,使用默认通道0并在插口0中启动。


4 结论

t程序中使用DBC文件很简单。当报文ID和信号在DBC文件中被定义之后,处理它们就容易多了。

我们仍然必须创建如何传输数据以及如何在不同信号之间转换的逻辑,但我们不需要处理原始数据。

由于精度和范围的差异,t脚本不会检查数据丢失。这必须在创建脚本时做好准备。

我希望本博客中的信息能对你有所帮助。欢迎评论和提问!

现场应用工程师, Kvaser AB

Lars-Göran Fredriksson

lgfr@kvaser.com

5实用的参考和工具

5.1 文档T-DEMO-FD.t

这是一个包含本博客中使用的t程序代码的文本文档,请查看附录B以获取完整列表。


5.2 文件DB_FD.DBC

请见附录A

此文件包含本博客中使用的报文和信号。


5.3 Kvaser SDK和驱动程序


5.4 Kvaser t编程语言

用户指南中的说明:
Kvaser t
语言是以事件为中心,以C语言为模型。它可以用来定制Kvaser Eagle和其他支持Kvaser t脚本的设备的操作。
t
程序通过hooks调用,hook是在特定事件发生时操作的入口点。例如,这些事件可以是特定CAN报文的接收、计时器到了时间或外部输入。
通过直接在Kvaser设备上运行的t程序,该设备可更快地对CAN总线上的事件做出反应(例如,加快文件传输协议或模拟缺失的硬件)。一些Kvaser设备也可以完全自主运行,例如Kvaser记录仪。

我不在这里介绍Kvaser t编程的基础知识,请查看其用户手册: The Kvaser t Programming Language.
https://www.kvaser.com/download/?utm_source=software&utm_ean=7330130980327&utm_status=latest

这里是我们网站主页上的一些相关博客:
https://www.kvaser.com/developer_category/t-script/


5.5 TRX软件

Kvaser TRX一个轻量级集成开发环境,用于为支持t脚本的Kvaser设备开发定制脚本。

https://www.kvaser.com/resource/trx-guide/

在安装Kvaser SDK时,会安装此软件。


5.6 Kvaser 数据库编辑器3

我将不介绍如何创建、使用和维护信号数据库。Kvaser有一个免费工具:Kvaser Database Editor 3

通过此工具,你可以查看、创建和编辑*.DBC文件。

https://www.kvaser.com/download/?utm_source=software&utm_ean=7330130981942&utm_status=latest

我们的主页上还有一些博客供参考:
https://www.kvaser.com/developer_category/dbc/
https://www.kvaser.com/developer_category/database/


5.7 Kvaser CANKing

一个免费的通用CAN总线监测器。它可与Kvaser的所有CAN适配器以及虚拟CAN总线联合使用。

https://www.kvaser.com/download/utm_source=software&utm_ean=7330130980686&utm_status=latest


6 Appendix A, the file DB_FD.DBC

请注意,CAN FD报文(101)中的信号比CAN报文(201202203)中的信号具有更高的分辨率。其目的是显示在t脚本中转换信号值很容易。我不会分析这将造成的精度损失。


6.1 DB_FD.DBC中的报文

6.1.1 TEST_MSG_101


6.1.2 TEST_MSG_201


6.1.3 TEST_MSG_202


6.1.4 TEST_MSG_203


6.2 数据库DB_FD.DBC源代码

请将以下信息复制并粘贴到一个文本文件中,并将其命名为: DB_FD.DBC

VERSION “”
NS_ :
NS_DESC_
CM_
BA_DEF_
BA_
VAL_
CAT_DEF_
CAT_
FILTER
BA_DEF_DEF_
EV_DATA_
ENVVAR_DATA_
SGTYPE_
SGTYPE_VAL_
BA_DEF_SGTYPE_
BA_SGTYPE_
SIG_TYPE_REF_
VAL_TABLE_
SIG_GROUP_
SIG_VALTYPE_
SIGTYPE_VALTYPE_
BO_TX_BU_
BA_DEF_REL_
BA_REL_
BA_DEF_DEF_REL_
BU_SG_REL_
BU_EV_REL_
BU_BO_REL_
SG_MUL_VAL_

BS_:

BU_:

BO_ 3221225472 VECTOR__INDEPENDENT_SIG_MSG: 0 Vector__XXX
SG_ NewSignal_0008 : 0|0@1+ (1,0) [0|0] “” Vector__XXX

BO_ 101 TEST_MSG_101: 32 Vector__XXX
SG_ S_101_LAT : 0|32@1+ (0.001,-180) [-180|180] “deg” Vector__XXX
SG_ S_101_LON : 32|32@1+ (0.001,-180) [-180|180] “deg” Vector__XXX
SG_ S_101_ALT : 64|32@1+ (0.001,-1000) [-1000|20000] “m” Vector__XXX
SG_ S_101_SOG : 96|32@1+ (0.001,0) [0|1000] “m/s” Vector__XXX
SG_ S_101_COG : 128|32@1+ (0.001,0) [0|360] “deg” Vector__XXX
SG_ S_101_ROLL : 160|32@1+ (0.001,-180) [-180|180] “deg” Vector__XXX
SG_ S_101_PITCH : 192|32@1+ (0.001,-180) [-180|180] “deg” Vector__XXX
SG_ S_101_HEADING : 224|32@1+ (0.001,-180) [-180|180] “deg” Vector__XXX

BO_ 201 TEST_MSG_201: 6 Vector__XXX
SG_ S_201_ROLL : 0|16@1+ (0.1,-180) [-180|180] “deg” Vector__XXX
SG_ S_201_PITCH : 16|16@1+ (0.1,-180) [-180|180] “deg” Vector__XXX
SG_ S_201_HEAD : 32|16@1+ (0.1,-180) [-180|180] “deg” Vector__XXX

BO_ 202 TEST_MSG_202: 6 Vector__XXX
SG_ S_202_LAT : 0|16@1+ (0.1,-180) [-180|180] “deg” Vector__XXX
SG_ S_202_LON : 16|16@1+ (0.1,-180) [-180|180] “deg” Vector__XXX
SG_ S_202_ALT : 32|16@1+ (0.1,-1000) [-1000|20000] “m” Vector__XXX

BO_ 203 TEST_MSG_203: 4 Vector__XXX
SG_ S_203_SOG : 0|16@1+ (0.1,0) [0|1000] “m/s” Vector__XXX
SG_ S_203_COG : 16|16@1+ (0.1,0) [0|360] “deg” Vector__XXX

BA_DEF_ BO_ “CANFD_BRS” ENUM “0”,”1″;
BA_DEF_ “BusType” STRING ;
BA_DEF_ BU_ “ECU” STRING ;
BA_DEF_ BO_ “VFrameFormat” ENUM “StandardCAN”,”ExtendedCAN”,”reserved”,”reserved”,”reserved”,”reserved”,”reserved”,”reserved”,”reserved”,”reserved”,”reserved”,”reserved”,”reserved”,”reserved”,”StandardCAN_FD”,”ExtendedCAN_FD”;
BA_DEF_DEF_ “CANFD_BRS” “1”;
BA_DEF_DEF_ “BusType” “”;
BA_DEF_DEF_ “ECU” “”;
BA_DEF_DEF_ “VFrameFormat” “StandardCAN”;
BA_ “BusType” “CAN FD”;
BA_ “VFrameFormat” BO_ 101 14;
BA_ “VFrameFormat” BO_ 201 0;
BA_ “VFrameFormat” BO_ 202 0;
BA_ “VFrameFormat” BO_ 203 0;


7 附录B,文件T-DEMO-FD.t

variables {
  const int MyCANFDch =0;
  const int MyCANch   =2;

  CanMessageFd_TEST_MSG_101 FD_GPS;
  //CanMessage_TEST_MSG_201   STD_GPS_RPH;
  //CanMessage_TEST_MSG_202   STD_GPS_LatLonAlt;
  //CanMessage_TEST_MSG_203   STD_GPS_SogCog;

  int FD_GPS_TEST=0;
  
}

on start {
  printf("Script started...\n");

  canBusOff(MyCANFDch);
  canBusOff(MyCANch);

  //Set First channel (FD)
 
  canSetBitrate(MyCANFDch,canFD_BITRATE_500K_80P); //canSetBitrate(MyCANFDch,canBITRATE_500K);
  canSetBusOutputControl(MyCANFDch, canDRIVER_NORMAL);
  canSetBitrateFd(MyCANFDch,canFD_BITRATE_2M_80P);
  canSetCommunicationMode(MyCANFDch, canMODE_CAN_FD);

  //Set Second channel (STD)
  canSetBitrate(MyCANch,canBITRATE_250K);
  canSetBusOutputControl(MyCANch, canDRIVER_NORMAL);


  canBusOn(MyCANFDch);
  canBusOn(MyCANch);
}

on stop {
  canBusOff(MyCANFDch);
  canBusOff(MyCANch);
  printf("Script stopped...\n");
}

on CanMessageFd <MyCANFDch> TEST_MSG_101 {
  CanMessage_TEST_MSG_201   STD_GPS_RPH;
  CanMessage_TEST_MSG_202   STD_GPS_LatLonAlt;
  CanMessage_TEST_MSG_203   STD_GPS_SogCog;

//  printf("Detected TEST_MSG_101 :%d\n", this.id);
//  printf("LAT P:%f\n", this.S_101_LAT.Phys);
//  printf("LAT R:%d\n", this.S_101_LAT.Raw);

  STD_GPS_RPH.S_201_ROLL.Phys      =this.S_101_ROLL.Phys;
  STD_GPS_RPH.S_201_PITCH.Phys     =this.S_101_PITCH.Phys;
  STD_GPS_RPH.S_201_HEAD.Phys      =this.S_101_HEADING.Phys;
  canWrite(MyCANch,STD_GPS_RPH);
  
  STD_GPS_LatLonAlt.S_202_LAT.Phys =this.S_101_LAT.Phys;
  STD_GPS_LatLonAlt.S_202_LON.Phys =this.S_101_LON.Phys;
  STD_GPS_LatLonAlt.S_202_ALT.Phys =this.S_101_ALT.Phys;
  canWrite(MyCANch,STD_GPS_LatLonAlt);

  STD_GPS_SogCog.S_203_SOG.Phys    =this.S_101_SOG.Phys;
  STD_GPS_SogCog.S_203_COG.Phys    =this.S_101_COG.Phys;
  canWrite(MyCANch,STD_GPS_SogCog);
}

on CanMessage <MyCANch> TEST_MSG_201 {

  FD_GPS.S_101_ROLL.Phys    =this.S_201_ROLL.Phys;
  FD_GPS.S_101_PITCH.Phys   =this.S_201_PITCH.Phys;
  FD_GPS.S_101_HEADING.Phys =this.S_201_HEAD.Phys;

  FD_GPS_TEST= (FD_GPS_TEST | 1);  

  if (FD_GPS_TEST>=7) {
    canWrite(MyCANFDch,FD_GPS);
    FD_GPS_TEST=0;
  }
}

on CanMessage <MyCANch> TEST_MSG_202 {

  FD_GPS.S_101_LAT.Phys  =this.S_202_LAT.Phys;
  FD_GPS.S_101_LON.Phys  =this.S_202_LON.Phys;
  FD_GPS.S_101_ALT.Phys  =this.S_202_ALT.Phys;

  FD_GPS_TEST= (FD_GPS_TEST | 2);  

  if (FD_GPS_TEST>=7) {
    canWrite(MyCANFDch,FD_GPS);
    FD_GPS_TEST=0;
  }
}

on CanMessage <MyCANch> TEST_MSG_203 {

  FD_GPS.S_101_COG.Phys  =this.S_203_COG.Phys;
  FD_GPS.S_101_SOG.Phys  =this.S_203_SOG.Phys;

  FD_GPS_TEST= (FD_GPS_TEST | 4);  

  if (FD_GPS_TEST>=7) {
    canWrite(MyCANFDch,FD_GPS);
    FD_GPS_TEST=0;
  }
}


8 附录C,存储区域的文件结构

存储区的内部格式遵循FAT-32格式,但在如何使用存储区方面有几个限制。

我们不支持任何目录,因此所有文件都位于内存区域的根目录(ROOT)中。

DIN Rail SE410S-X10, 使用8.3文件名约定。

文件名的可用字符包括:
大写字母 A–Z
小写字母 a–z (以A–Z使用)
数字 0–9
下划线 “_”

不允许:
ASCII 0 – ASCII 32 (控制 0–31 个字符和空格)
ASCII127 – ASCII255 (包括 DEL(127))
” * + / : ; < = > ? \ [ ] |
! @ (有些文件系统中可用,但我们不用)
# $ % & ‘ ( ) – ^ ` { } ~

在其他Kvaser适配器中,存储区可能已经有一些文件(例如在Kvaser Memorator中)。

不要使用下列任何文件名:
*.LIF
LOG*.KMF
DATABASE.BIN

此外,请避免使用下列文件名,Kvaser设备上允许使用这些文件名,但复制时可能会导致错误。
COM, COM1, COM2, COM3
LPT, LPT1,LPT2,LPT3
CON
DEVICE

具有预定义函数的文件名
AUTOEXEC.TXT (用于启动*.TXE文件)

Author Image

Lars-Göran Fredriksson