exponenta event banner

Доступ к структурированным данным через указатель, определяемый внешним кодом

В этом примере показано, как создать код, использующий глобальные данные, определенные некоторым рукописным кодом. В рукописном коде переменная указателя указывает на одну из трех структурных переменных, содержащих данные параметров. Рукописная функция переключает указатель между структурами. Сгенерированный код получает доступ к данным параметра путем отмены ссылки на переменную указателя.

Изучение внешнего кода

Открыть исходный файл примера rtwdemo_importstruct_user.c. Код определяет переменную структуры данных по умолчанию ReferenceStruct как константа (const) данных и статически инициализирует каждое поле. Эта структура представляет набор ссылочных данных.

/* Constant default data structure (reference data set) */
const DataStruct_type ReferenceStruct = 
{
  11,   /* OFFSET */
  2     /* GAIN */
};

Код определяет две другие структурные переменные, WorkingStruct1 и WorkingStruct2, как изменчивый (volatile) данные.

/* Volatile data structures (working data sets) */
volatile DataStruct_type WorkingStruct1;
volatile DataStruct_type WorkingStruct2;

Код определяет функцию, которая может инициализироваться:

  • Неактивная рабочая структура из активной рабочей структуры.

  • Обе рабочие структуры из ссылочной структуры.

/* Function to initialize inactive working structures from active structure */
void InitInactiveWorkingStructs(void)
{
    if (StructPointer == &WorkingStruct1) {
        /* Copy values from WorkingStruct1 to WorkingStruct2 */
        memcpy((void*)&WorkingStruct2, (void*)&WorkingStruct1, sizeof(ReferenceStruct));
        
    } else if (StructPointer == &WorkingStruct2) {
        /* Copy values from WorkingStruct2 to WorkingStruct1 */
        memcpy((void*)&WorkingStruct1, (void*)&WorkingStruct2, sizeof(ReferenceStruct));
        
    } else {
        /* Initialize both working structures from ReferenceStruct */
        memcpy((void*)&WorkingStruct1, &ReferenceStruct, sizeof(ReferenceStruct));
        memcpy((void*)&WorkingStruct2, &ReferenceStruct, sizeof(ReferenceStruct));
    }
}

Код определяет StructPointer, который является const volatile указатель на структуру. Код инициализирует указатель на адрес ReferenceStruct.

/* Define structure pointer.  Point to reference structure by default */
const volatile DataStruct_type *StructPointer = &ReferenceStruct;

Наконец, код определяет функцию, которая может динамически устанавливаться StructPointer для указания на ReferenceStruct, WorkingStruct1, или WorkingStruct2.

/* Function to switch between structures */
void SwitchStructPointer(Dataset_T Dataset)
{
    switch (Dataset) {
    case Working1:
        StructPointer = &WorkingStruct1;
        break;
    case Working2:
        StructPointer = &WorkingStruct2;
        break;
    default:
        StructPointer = &ReferenceStruct;
    }
}

Пример файла заголовка rtwdemo_importstruct_user.h определяет перечисление Dataset_T и тип структуры Datastruct_type. Файл включает в себя (#include) встроенный файл заголовка Simulink ® Coder™rtwtypes.h, которая определяет (typedef) Типы данных Simulink Coder, такие как int16_T.

#include "rtwtypes.h"

typedef enum {
    Reference = 0,
    Working1,
    Working2
} Dataset_T;

typedef struct DataStruct_tag {
  int16_T   OFFSET; /* OFFSET */
  int16_T   GAIN;   /* GAIN */
} DataStruct_type;

Файл также объявляет глобальные переменные и функции.

Назначение внешнего кода

Код разработан таким образом, чтобы исходный код алгоритма управления (сгенерированный или рукописный) мог считывать данные из ReferenceStruct, WorkingStruct1, или WorkingStruct2 путем дереференции (->) StructPointer. Две рабочие структуры (WorkingStruct1 и WorkingStruct2) находятся в энергозависимой памяти и предназначены для изменения во время выполнения внешним калибровочным инструментом. Инженер по калибровке не изменяет активную рабочую структуру. Вместо этого инженер изменяет значения параметров в неактивной рабочей структуре и затем активирует их путем переключения рабочих структур.

При необходимости для безопасности или при подготовке к останову приложения калибровочный инструмент может указать StructPointer кому ReferenceStruct вместо этого. ReferenceStruct сохраняет значения параметров по умолчанию, которые не изменяются во время выполнения.

Изучение примера модели

Откройте пример модели, rtwdemo_importstruct.

Модель создает переменные и объекты в базовом рабочем пространстве. Блок константы и блок усиления используют ECoderDemos.Parameter объекты GAIN и OFFSET для установки параметров «Постоянное значение» и «Блок усиления». ECoderDemos является примером пользовательского пакета, который определяет два класса, Parameter и Signalи некоторые пользовательские классы хранения.

На вкладке Моделирование (Modeling) щелкните Редактор данных модели (Model Data Editor).

В Редакторе данных модели (Model Data Editor) проверьте вкладку Параметры (Parameters).

Установите в раскрывающемся списке Изменить представление значение Code.

Нажмите кнопку Показать/обновить дополнительную информацию.

Редактор данных модели показывает строки, которые соответствуют параметрам «Постоянное значение» и «Коэффициент усиления» блоков и строк, которые соответствуют OFFSET и GAIN, которые устанавливают значения параметров. В столбце «Класс хранилища» OFFSET и GAIN использовать пользовательский класс хранения StructPointer, который ECoderDemos пакет определяет.

Откройте конструктор классов пользовательских хранилищ и проверьте классы пользовательских хранилищ в ECoderDemos пакет. В командной строке используйте следующую команду:

cscdesigner('ECoderDemos')

В этом примере пакет определяет несколько пользовательских классов хранения, включая StructPointer. Нельзя редактировать определения. Однако позже можно создать собственные пакеты и пользовательские классы хранения. Пример создания пакета и пользовательского класса хранения см. в разделе Создание и применение класса хранения.

В разделе Настраиваемые определения классов хранения щелкните StructPointer. Параметры этого пользовательского класса хранения позволяют сгенерированному коду взаимодействовать с переменной указателя, StructPointer, из внешнего кода. Например, в пользовательском классе хранения используются следующие параметры:

  • Для области данных установлено значение Imported потому что пример внешнего кода определяет (выделяет память для) StructPointer. С помощью этой настройки генератор кода избегает создания ненужных, повторяющихся определений для элементов данных, таких как ECoderDemos.Parameter объекты, использующие пользовательский класс хранения.

  • Для доступа к данным установлено значение Pointer потому что в примере внешний код, StructPointer является указателем.

  • Для раздела памяти установлено значение ConstVolatile потому что пример внешнего кода определяет StructPointer в виде постоянных, изменчивых данных (const volatile).

  • Тип имеет значение FlatStructure потому что в примере внешний код, StructPointer указывает на структуру. С помощью этой настройки сгенерированный код обрабатывает каждый элемент данных (ECoderDemos.Parameter объект) как поле плоской структуры, имя переменной и имя типа которого можно указать.

  • На вкладке Атрибуты структуры (Structure Attributes) для параметра Наименование структуры (Struct name) установлено значение StructPointer. Для FlatStructure custom storage class, Struct name указывает имя структурной переменной в созданном коде. В этом примере: StructPointer - имя переменной, определяемое внешним кодом.

  • Для имени типа установлено значение DataStruct_type, которое является именем типа структуры, определяемого внешним кодом примера.

В модели в диалоговом окне Параметры конфигурации (Configuration Parameters) проверьте панель Создание кода (Code Generation) > Пользовательский код (Custom Code).

В разделе Вставить пользовательский код C в сгенерированном выберите Инициализировать функцию. Это значение параметра определяет код для включения в создаваемую функцию инициализации модели. В этой модели параметр конфигурации устанавливается таким образом, что сгенерированный код вызывает InitInactiveWorkingStructs функция. InitInactiveWorkingStructs инициализирует рабочие структуры со значениями из ReferenceStruct. Затем код инициализации устанавливает указатель на первую рабочую структуру.

В разделе Дополнительные сведения о построении выберите Исходные файлы. Этот параметр конфигурации определяет пример файла внешнего кода rtwdemo_importstruct_user.c для включения в процесс построения после создания кода.

Создание и проверка кода

Создайте код из модели.

В созданном файле rtwdemo_importstruct.c, функция инициализации модели вызывает InitInactiveWorkingStructs.

/* Model initialize function */
void rtwdemo_importstruct_initialize(void)
{
  /* user code (Initialize function Body) */

  /* Initialize the working structures to reference values */
  InitInactiveWorkingStructs();

  /* Switch to first working structure */
  SwitchStructPointer(Working1);
}

/*

Алгоритм выполнения модели (step) функция удаляет переменную указателя StructPointer.

/* Model step function */
void rtwdemo_importstruct_step(void)
{
  /* Outport: '<Root>/Out' incorporates:
   *  Constant: '<Root>/Offset'
   *  Gain: '<Root>/Gain'
   *  Inport: '<Root>/In'
   *  Sum: '<Root>/Sum'
   */
  Sensor_Out = (int16_T)((int16_T)(Sensor_In - StructPointer->OFFSET) *
    StructPointer->GAIN);
}

Связанные темы