3. ARXML数据类型:基础数据类型、复合数据类型与引用类型

各位同学,今天我们来聊聊ARXML里的数据类型。说实话,我刚接触AUTOSAR那会儿,看到ARXML里密密麻麻的类型定义,头都大了。但后来我发现,搞懂了数据类型,整个AUTOSAR的骨架就清晰了一半。

ARXML的数据类型,说白了就是用来描述ECU之间、以及ECU内部各个模块之间传递的数据长什么样。它分三大类:基础数据类型、复合数据类型,还有引用类型。咱们一个一个来看。

3.1 基础数据类型

基础数据类型,就是那些不能再拆分的原子类型。嗯,就像盖房子的砖头。AUTOSAR里最常用的有这么几种:

类型 ARXML标签 说明
布尔型 Boolean true/false,常用于开关、标志位
整型 Integer 有符号/无符号,可指定位宽
浮点型 Float 单精度/双精度,用于物理量
字符串 String 文本数据,长度可固定或可变

我个人习惯,在定义信号时优先用Integer而不是Float。为什么?因为浮点数在嵌入式系统里处理起来开销大,而且不同芯片的浮点运算结果可能有微小差异。我在项目中遇到过两次,因为浮点数精度问题导致两个ECU对同一个车速值的判断不一致,最后排查了两天才找到原因。

来看一个ARXML里定义Integer的例子:

<INTEGER-TYPE>
  <SHORT-NAME>VehicleSpeed_T</SHORT-NAME>
  <CATEGORY>TYPE_REF</CATEGORY>
  <LOWER-MULTIPLICITY>0</LOWER-MULTIPLICITY>
  <UPPER-MULTIPLICITY>1</UPPER-MULTIPLICITY>
  <SW-DATA-DEF-PROPS>
    <SW-DATA-DEF-PROPS-VARIANTS>
      <SW-DATA-DEF-PROPS-CONDITIONAL>
        <PHYS-CONSTRS>
          <LOWER-LIMIT>0</LOWER-LIMIT>
          <UPPER-LIMIT>300</UPPER-LIMIT>
          <UNIT>km/h</UNIT>
        </PHYS-CONSTRS>
        <COMPU-METHOD>Linear_CompuMethod</COMPU-METHOD>
      </SW-DATA-DEF-PROPS-CONDITIONAL>
    </SW-DATA-DEF-PROPS-VARIANTS>
  </SW-DATA-DEF-PROPS>
</INTEGER-TYPE>

这里要注意,LOWER-LIMITUPPER-LIMIT定义的是物理值的范围,不是内部存储的位宽。位宽是在SW-BIT-REPRESENTATION里定义的,很多新手容易搞混。

避坑指南: 我曾经在定义车速信号时,只给了8位无符号整型,结果车速超过255km/h就溢出了。虽然一般车跑不到那么快,但测试用例里偏偏就有这个边界值。从那以后,我定义整型时都会先算好物理范围,再反推需要的位宽。

3.2 复合数据类型

复合数据类型,就是把多个基础类型组合在一起。你想想看,一个GPS位置信息,包含经度、纬度、海拔、时间戳,总不能定义四个独立的信号吧?这时候就需要复合类型了。

AUTOSAR里主要有两种复合类型:

  • Array(数组):相同类型元素的集合,比如一组温度传感器的读数
  • Record(记录):不同类型元素的集合,比如上面说的GPS位置信息

来看一个Record的例子,定义一个诊断故障码(DTC)的数据结构:

<RECORD-TYPE>
  <SHORT-NAME>DTC_Info</SHORT-NAME>
  <ELEMENTS>
    <RECORD-ELEMENT>
      <SHORT-NAME>DTC_Code</SHORT-NAME>
      <TYPE-TREF>/DataTypes/Integer_16bit</TYPE-TREF>
    </RECORD-ELEMENT>
    <RECORD-ELEMENT>
      <SHORT-NAME>DTC_Status</SHORT-NAME>
      <TYPE-TREF>/DataTypes/DTC_Status_Type</TYPE-TREF>
    </RECORD-ELEMENT>
    <RECORD-ELEMENT>
      <SHORT-NAME>Timestamp</SHORT-NAME>
      <TYPE-TREF>/DataTypes/UnixTimestamp</TYPE-TREF>
    </RECORD-ELEMENT>
  </ELEMENTS>
</RECORD-TYPE>

Array的定义也很直观,比如定义一个5元素的数组:

<ARRAY-TYPE>
  <SHORT-NAME>Temperature_Sensor_Array</SHORT-NAME>
  <ELEMENT>
    <SHORT-NAME>Sensor_Value</SHORT-NAME>
    <TYPE-TREF>/DataTypes/Temperature_Type</TYPE-TREF>
    <ARRAY-SIZE>
      <NUM-ELEMENTS>5</NUM-ELEMENTS>
    </ARRAY-SIZE>
  </ELEMENT>
</ARRAY-TYPE>
小技巧: 定义Record时,元素的顺序很重要。因为ARXML里Record的内存布局是严格按照元素声明顺序排列的。我建议把最频繁访问的元素放在前面,这样在调试时看内存更方便。

3.3 引用类型与ID引用

引用类型,说白了就是「指向另一个数据类型的指针」。在ARXML里,我们不直接复制数据定义,而是通过引用来复用。这样做的好处是:改一处,处处生效。

引用类型有两种形式:

  • 类型引用(Type Reference):用TYPE-TREF标签,指向另一个已定义的数据类型
  • ID引用(ID Reference):用REF标签,指向具体的实例或对象

举个例子,假设多个信号都使用同一个「车速」数据类型:

<SIGNAL>
  <SHORT-NAME>FrontLeftWheelSpeed</SHORT-NAME>
  <DATA-TYPE>
    <TYPE-TREF>/DataTypes/VehicleSpeed_T</TYPE-TREF>
  </DATA-TYPE>
</SIGNAL>

<SIGNAL>
  <SHORT-NAME>FrontRightWheelSpeed</SHORT-NAME>
  <DATA-TYPE>
    <TYPE-TREF>/DataTypes/VehicleSpeed_T</TYPE-TREF>
  </DATA-TYPE>
</SIGNAL>

这里两个信号都引用了同一个VehicleSpeed_T类型。如果以后需要修改车速的范围或单位,只需要改一处定义,所有引用它的信号自动生效。这就是引用的威力。

核心要点: 引用类型让ARXML具备了「面向对象」的特性——封装、复用、解耦。一个设计良好的ARXML数据模型,引用关系应该清晰且层次分明,而不是到处复制粘贴。

3.4 知识体系总览

为了让大家更直观地理解这三类数据类型的关系,我画了一张图:

ARXML数据类型体系 ARXML数据类型 基础数据类型 Boolean Integer (有/无符号) Float (单/双精度) String 复合数据类型 Array(数组) Record(记录) Union(联合体) 引用类型 TYPE-TREF(类型引用) REF(ID引用) 实例引用 💡 基础类型是砖块,复合类型是墙体,引用类型是设计蓝图 三者结合,构建出完整、可复用的AUTOSAR数据模型

从这张图可以看出来,基础类型是最底层的构建单元,复合类型把它们组合成更复杂的数据结构,而引用类型则让整个模型具备了灵活性和可维护性。三者缺一不可。

3.5 实际项目中的选择建议

说了这么多理论,到底什么时候用哪种类型?我根据自己的项目经验,总结了几条原则:

  1. 能用基础类型就别用复合类型——简单就是美,调试也方便
  2. 多个信号共享同一物理含义时,一定要用引用——比如车速、转速、温度这些基础物理量
  3. Record里的元素不要超过10个——超过10个,建议拆分成多个子Record,否则维护起来很痛苦
  4. Array的长度尽量用常量定义——不要写死数字,用NUM-ELEMENTS引用一个常量,方便后期调整
个人经验: 我参与过一个项目,团队里有人把所有信号都定义成独立的Integer,结果整车有2000多个信号,光类型定义就占了ARXML文件的一半。后来我花了两周时间,把重复的类型统一成引用,文件大小直接缩减了60%。所以,设计阶段多花点心思在类型复用上,后期能省很多事。

好了,关于ARXML的数据类型,今天就聊到这里。记住:基础类型是砖,复合类型是墙,引用类型是图纸。把这三样搞明白了,AUTOSAR的数据建模你就掌握了八成。


公众号:蓝海资料掘金营,微信deep3321