Main Content

本页翻译不是最新的。点击此处可查看最新英文版本。

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

枚举数据类型

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

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

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

为枚举指定整数数据类型

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

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

  • 减少 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 - 指定类名在生成的代码中是否变成前缀。

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

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

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

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

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

指定描述信息

要为枚举数据类型指定描述信息,请在枚举类的 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 显示为每个枚举名称的前缀。

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

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

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

要使用 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 包含枚举类型定义。

枚举的类型转换

安全转换

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

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

启用和禁用安全转换

您可以在代码生成期间为 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')

另请参阅

| |

相关主题