主要内容

在生成的代码中使用枚举数据

枚举数据类型

枚举数据是指仅限于一组有限值的数据。枚举数据类型是一个 MATLAB® 类,它定义一组枚举值。每个枚举值包括一个枚举名称和一个基础整数,该数字由软件在内部以及生成的代码中使用。

此 MATLAB 类定义用于定义名为 BasicColors 的枚举数据类型。

classdef BasicColors < Simulink.IntEnumType
  enumeration
    Red(0)
    Yellow(1)
    Blue(2)
  end
end

有关枚举数据类型及其在 Simulink® 模型中的用法的基本信息,请参阅在 Simulink 模型中使用枚举数据。有关 Stateflow® 图中的枚举数据类型的信息,请参阅定义枚举数据类型 (Stateflow)

选择定义枚举数据类型的方法

以下方法可用于定义枚举数据类型:

下表列出了枚举数据类型定义条件和要求的示例,并为每种情况确定了推荐的方法。

条件或要求classdef 代码块 MATLAB 文件。Simulink.defineInEnumType 函数Simulink.importExternalCTypes Function
在 MATLAB 脚本文件中定义数据类型定义。X  
通过添加方法、回调、属性和其他自定义信息等内容扩展数据类型定义。 X  
从基类派生定义X  
在一个文件中存储多个数据类型定义。 X 
在单个 MATLAB 会话中的多次执行运行之间更改数据类型定义,而不会产生负面影响 X 
使用外部 C 头文件中的现有数据类型定义。  X

有关这些方法的详细信息,请参阅在 Simulink 模型中使用枚举数据和相关函数参考页

为枚举指定整数数据类型

为枚举指定数据类型时,您可以:

  • 通过指定超类来控制生成的代码中枚举数据类型的大小。

  • 减少 RAM/ROM 使用量。

  • 提高代码的可移植性。

  • 改善与现有代码的集成。

您可以指定以下整数数据类型:

  • int8

  • uint8

  • int16

  • uint16

  • int32

  • Simulink.IntEnumType.指定适合您的硬件平台的有符号整数范围内的值。

MATLAB 文件中使用类定义

要指定整数数据类型大小,请从整数数据类型派生枚举类。

classdef Colors < int8
   enumeration
     Red(0)
     Green(1)
     Blue(2)
   end
end

代码生成器生成以下代码:

typedef int8_T Colors;

#define Red      ((Colors)0)
#define Green ((Colors)1)
#define Blue     ((Colors)2)

使用函数 Simulink.defineIntEnumType

要指定整数数据类型大小,请指定名称-值对组 StorageType 作为整数数据类型。

Simulink.defineIntEnumType('Colors',{'Red','Green','Blue'},...
[0;1;2],'StorageType','int8')

代码生成器生成以下代码:

typedef int8_T Colors;

#define Red      ((Colors)0)
#define Green ((Colors)1)
#define Blue     ((Colors)2)

自定义枚举数据类型

当您从使用枚举数据的模型中生成代码时,可以实现下面这些静态方法,在仿真期间和生成的代码中自定义该枚举数据类型的行为:

  • getDefaultValue - 指定枚举数据类型的默认值。

  • getDescription - 指定枚举数据类型的说明。

  • getHeaderFile - 指定为生成的代码定义类型的头文件。

  • getDataScope - 指定生成的代码是否将枚举数据类型定义导出或导入单独的头文件。

  • addClassNameToEnumNames - 指定类名在生成的代码中是否变成前缀。

  • isTunableInCode - 指定枚举值在生成的代码中是否可调。

上述第一个方法 getDefaultValue 与仿真和代码生成有关,指定默认枚举值 中对此方法进行了说明。其他方法仅与代码生成有关。要自定义枚举类型的行为,请在枚举类定义的 methods(Static) 部分包含该方法的某个版本。如果您不想自定义类型,则可以省略 methods(Static) 部分。下表总结了每一种方法和要提供的数据。

静态方法用途未实现方法时的默认值自定义返回值
getDefaultValue指定类的默认枚举成员。枚举定义中指定的第一个成员包含类中某个枚举成员的名称的字符向量(请参阅对枚举进行实例化)。
getDescription指定枚举类的说明。''包含类型说明的字符向量。
getHeaderFile指定头文件的名称。方法 getDataScope 决定该文件的重要性。''

包含定义枚举类型的头文件的名称的字符向量。

默认情况下,生成的 #include 指令使用预处理器分隔符 ",而不是 <>。要生成指令 #include <myTypes.h>,请将自定义返回值指定为 '<myTypes.h>'

getDataScope指定生成的代码是导出还是导入枚举数据类型的定义。使用方法 getHeaderFile 指定定义该类型的生成的或包含的头文件。'Auto' 'Auto''Exported''Imported'
addClassNameToEnumNames指定在生成的代码中是否为类名称添加前缀。falsetruefalse
isTunableInCode指定枚举值在生成的代码中是否可调。falsetruefalse

指定描述信息

如果您有 Embedded Coder® 许可证,您可以启用 Simulink 数据对象描述模型配置参数,以便在生成代码中包含枚举数据类型的描述。要为枚举数据类型指定描述信息,请在枚举类的 methods(Static) 部分包含此方法:

function retVal = getDescription() 
% GETDESCRIPTION  Optional description of the data type.
  retVal = 'description';
end

使用 MATLAB 字符向量替换 description。定义枚举类型的生成代码会包括指定的描述信息。

在生成的代码中导入类型定义

为了防止在生成的代码中定义枚举数据类型,可在外部文件中提供定义,并在枚举类的 methods(Static) 部分包含这些方法:

    function retVal = getHeaderFile()
      % GETHEADERFILE Specifies the file that defines this type in generated code.
      % The method getDataScope determines the significance of the specified file.
      retVal = 'imported_enum_type.h';
    end

    function retVal = getDataScope()
      % GETDATASCOPE Specifies whether generated code imports or exports this type.
      % Return one of:
      % 'Auto':     define type in model_types.h, or import if header file specified
      % 'Exported': define type in a generated header file
      % 'Imported': import type definition from specified header file
      % If you do not define this method, DataScope is 'Auto' by default.
      retVal = 'Imported';
    end

这样,生成的代码将不会在 model_types.h 中定义类型(此为默认行为),而是通过使用与下面类似的 #include 语句从指定的头文件中导入定义:

#include "imported_enum_type.h"

代码生成器不创建导入的头文件。您必须使用方法 getHeaderFile 所指定的文件名提供定义枚举数据类型的头文件。

要创建与现有 C 代码枚举对应的 Simulink 枚举,请使用 Simulink.importExternalCTypes 函数。

当您导入枚举类型定义时,可以设置枚举值在生成的代码中可调。有关详细信息,请参阅为生成代码中的可调性配置枚举数据类型

在生成的代码中导出类型定义

要生成单独的定义枚举数据类型的头文件,请在枚举类的 methods(Static) 部分包含这些方法:

    function retVal = getDataScope()
      % GETDATASCOPE Specifies whether generated code imports or exports this type.
      % Return one of:
      % 'Auto':     define type in model_types.h, or import if header file specified
      % 'Exported': define type in a generated header file
      % 'Imported': import type definition from specified header file
      % If you do not define this method, DataScope is 'Auto' by default.
      retVal = 'Exported';
    end

    function retVal = getHeaderFile()
      % GETHEADERFILE Specifies the file that defines this type in generated code.
      % The method getDataScope determines the significance of the specified file.
      retVal = 'exported_enum_type.h';
    end

生成的代码将枚举类型定义导出到生成的头文件 exported_enum_type.h 中。

为类名添加前缀

默认情况下,在生成的代码中,枚举值的名称与枚举类定义中的名称相同。在您的代码中,也可以使用类名为枚举类中的每个枚举值添加前缀。您可以采用这种方法来防止标识符冲突或提高代码的可读性。要指定类名前缀,请在枚举类的 methods(Static) 部分包含此方法:

    function retVal = addClassNameToEnumNames()
      % ADDCLASSNAMETOENUMNAMES Specifies whether to add the class name
      % as a prefix to enumeration member names in generated code.
      % Return true or false.
      % If you do not define this method, no prefix is added.
      retVal = true;
    end

可以将返回值指定为 true 以启用类名前缀,或者指定为 false 以禁用前缀。如果指定 true,枚举类中的每个枚举值在生成的代码中都将以 EnumTypeName_EnumName 的形式显示。对于枚举数据类型中的示例枚举类 BasicColors,生成的代码中的数据类型定义可能如下所示:

#ifndef _DEFINED_TYPEDEF_FOR_BasicColors_
#define _DEFINED_TYPEDEF_FOR_BasicColors_

typedef enum {
  BasicColors_Red = 0,            /* Default value */
  BasicColors_Yellow = 1,
  BasicColors_Blue = 2,
} BasicColors;

#endif

枚举类名称 BasicColors 显示为每个枚举名称的前缀。

为生成代码中的可调性配置枚举数据类型

自 R2025a 起

当您导入在 MATLAB 环境外部的头文件中定义的枚举数据类型定义时,可以控制枚举值在生成的代码中是否可调。可调的枚举值使您能够在应用程序之间共享数据类型定义,例如在主数据字典中提供的定义。您可以根据需要更改、添加和重新排序生成代码中的枚举值,以符合每个应用程序的需求。

默认情况下,生成代码中的枚举值不可调。要启用枚举类型可调性,请在枚举类的 methods(Static) 部分中包含 getHeaderFilegetDataScopeisTunableInCode 方法。

  • getHeaderFile 指定在生成代码中定义枚举类型的外部文件。getDataScope 方法确定指定的文件的重要性。

  • getDataScope 指定生成代码是导入还是导出枚举类型定义。该方法返回:

    • Auto(如果代码生成器根据 getHeaderFile 是否指定用于导入类型定义的外部头文件,在导入的头文件或生成的头文件 model_types.h 之间选择)。

    • Exported(如果代码生成器在生成的头文件 model_types.h 中定义数据类型)。

    • Imported(如果代码生成器从指定的外部头文件导入数据类型定义)。

  • isTunableInCode 指定为枚举定义的值是否可调。

枚举类的以下示例 methods(Static) 部分指定生成的代码从 imported_enum_type.h 导入类型定义,并在生成代码中启用导入的枚举类型值的可调性。要禁用可调性,请对方法 isTunableInCode 指定返回值 false

classdef BasicColors < Simulink.IntEnumType
  enumeration
    Red(0)
    Yellow(1)
    Blue(2)
  end
  methods (Static = true)
    function retVal = getDataScope()
      retVal = "Imported";
    end    
    function retVal = getHeaderFile()
      retVal = "imported_enum_type.h";
    end
    function retVal = isTunableInCode()
      retVal = true;
    end
  end
end

与为可调枚举类型定义的每个枚举关联的数值必须唯一。例如,以下枚举类无效,因为枚举 YellowBlue 都与数值 1 相关联。

classdef BasicColors < Simulink.IntEnumType
  enumeration
    Red(0)
    Yellow(1)
    Blue(1)
  end
  methods (Static = true)
    function retVal = getDataScope()
      retVal = "Imported";
    end    
    function retVal = getHeaderFile()
      retVal = "imported_enum_type.h";
    end
    function retVal = isTunableInCode()
      retVal = true;
    end
  end
end

控制重复枚举成员名称的使用

从头文件导入枚举数据时,您可以控制在代码生成过程中重复枚举成员名称的使用。重复使用枚举成员名称可提高代码的可读性。使用模型配置参数重复的枚举成员名称可在代码生成期间允许对不同枚举类型使用重复枚举成员名称,或生成错误或警告消息。仅当两个枚举具有相同的 StorageType 并具有以下设定时,才能使用重复的枚举成员名称:

  • DataScope 设置为 'Imported'

  • StorageType 设置为 'int8''int16''int32''uint8''uint16''uint32'

  • Value 相同

例如:

typedef int32_T enum {
  Red = 0,
  Yellow = 1,
  Blue = 2,
}A;

typedef int32_T enum {
  Black = 0,
  Yellow = 1,
  White = 2,
}B;
您可以在枚举 AB 中使用 Yellow 枚举成员,而无需在成员名称前面加上类名,从而提高代码的可读性。

在生成的代码中控制枚举类型实现

假设您定义了一个枚举类型 BasicColors。您可以指定生成的代码通过以下方式实现该类型定义:

  • 使用 enum 模块。硬件的原生整数类型是枚举成员的基础整数类型。

  • 使用 typedef 语句和一系列 #define 宏。typedef 语句基于特定的整数数据类型(例如 int8)定义枚举类型名称。宏将枚举成员与基础整数值相关联。

使用 enum 模块实现枚举类型

要通过使用 enum 模块实现类型定义,请执行以下操作:

  • 在 Simulink 中,使用 classdef 模块在脚本文件中定义枚举类型。从类型 Simulink.IntEnumType 派生枚举。

  • 也可以使用函数 Simulink.defineIntEnumType。不要指定属性 StorageType

生成代码时,类型定义显示在 enum 模块中。

#ifndef _DEFINED_TYPEDEF_FOR_BasicColors_
#define _DEFINED_TYPEDEF_FOR_BasicColors_

typedef enum {
  Red = 0,            /* Default value */
  Yellow,
  Blue,
} BasicColors;

#endif

如果您在 MATLAB 命名空间内定义枚举类型,则默认情况下,代码生成器会在命名空间中生成枚举,以用于 C++ 代码生成。对于 C 代码生成,代码生成器会将 MATLAB 命名空间作为枚举的前缀。要禁止在生成代码中生成 C++ 命名空间和 C 前缀,请取消选中模型配置参数在生成的代码中保留 MATLAB 命名空间

下表显示在在生成的代码中保留 MATLAB 命名空间分别处于选中和未选中的情况下,在 MATLAB 命名空间 MyColors 中的枚举类型 Colors 的生成代码。

语言选中清除
C
typedef enum {
    black,
    white,
} MyColors_Colors;
typedef enum {
    black,
    white
}  Colors;
C++
namespace MyColors {
    enum class Colors : int32_t {
        black,
        white
    };
}
enum class Colors : int32_t {
        black,
        white
    };

使用特定的整数类型实现枚举类型

要使用 typedef 语句和 #define 宏实现类型定义,请执行以下操作:

  • 在 Simulink 中,使用 classdef 模块在脚本文件中定义枚举类型。从特定的整数类型(如 int8)派生枚举。

  • 也可以使用函数 Simulink.defineIntEnumType。使用特定的整数类型(例如 int8)指定属性 StorageType

当您生成代码时,类型定义显示为 typedef 语句和一系列 #define 宏。

#ifndef _DEFINED_TYPEDEF_FOR_BasicColors_
#define _DEFINED_TYPEDEF_FOR_BasicColors_

typedef int8_T BasicColors;

#define Red ((BasicColors)0)            /* Default value */
#define Yellow ((BasicColors)1)
#define Blue ((BasicColors)2)

#endif

默认情况下,生成的文件 model_types.h 包含枚举类型定义。

枚举的类型转换

安全转换

Data Type Conversion 模块接受整数类型的信号。此模块可将输入转换为枚举类型的基础值之一。

如果输入值与枚举类型值的基础值不匹配,Simulink 将插入一个安全转换,用枚举类型的默认值替换输入值。

启用和禁用安全转换

您可以在代码生成期间为 Data Type Conversion 模块或 Stateflow 模块启用或禁用枚举的安全转换。

要控制安全转换,请启用或禁用对整数溢出进行饱和处理模块参数。此参数的工作原理如下:

  • 启用:Simulink 在仿真期间会使用枚举值的默认值替换不匹配的输入值。软件将在代码生成期间生成安全转换函数。

  • 禁用:Simulink 在仿真期间遇到不匹配的输入值时会产生一个错误。软件将在代码生成过程中忽略安全转换函数。这种情况下,代码的效率更高,但可能更容易出现运行时错误。

生成的代码中的安全转换函数

此示例说明为 32 位硬件生成代码时,枚举 BasicColors 的安全转换函数 int32_T ET08_safe_cast_to_BasicColors 在生成代码中如何显示。

static int32_T ET08_safe_cast_to_BasicColors(int32_T input)
{
	int32_T output;
	/* Initialize output value to default value for BasicColors (Red) */
	output = 0;
	if ((input >= 0) && (input <= 2)) {
	/* Set output value to input value if it is a member of BasicColors */
		output = input;
	}
	return output;
}
通过此函数,当输入值与枚举类型值的基础值不匹配时,将使用枚举类型的默认值。

如果禁用了模块的对整数溢出进行饱和处理参数,此函数将不会出现在生成的代码中。

有关枚举类型的限制

  • 生成的代码不支持记录枚举数据。

  • 对于基于 uint32 的枚举,枚举值必须小于或等于 intmax("int32")

  • 对于生成代码中的可调枚举值:

    • 必须导入数据类型定义。

    • 数据类型定义不能包括重复的枚举成员名称。

    • 如果某数值或空值(如 0 或 [])会导致运行时参数成为可调枚举类型,则不能使用该值指定该参数。

    • 不支持可能折叠的包含可调枚举的参数表达式。

    • 生成的代码不基于底层枚举值执行范围分析。

    • 与为可调枚举类型定义的每个枚举关联的数值必须唯一。

    • 当接口类型配置为输出到头文件 Rte_Type.h 时,AUTOSAR 接口类型不支持可调枚举类型。

另请参阅

| | | |

主题