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

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

Исследуйте внешний код

Откройте пример исходного файла 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) встроенный файл заголовка Coder™ Simulink ® 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.

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

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

В Model Data Editor смотрите вкладку Параметры.

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

Нажмите кнопку Показать/обновить дополнительные сведения.

В Model Data Editor показаны строки, которые соответствуют параметрам Constant значения и Gain блоков и строк, которые соответствуют OFFSET и GAIN, который устанавливает значения параметров. В столбце «Класс памяти» OFFSET и GAIN использовать пользовательский класс памяти StructPointer, который ECoderDemos определяет пакет.

Откройте Custom Storage Class Designer и проверьте пользовательские классы памяти в ECoderDemos пакет. В командной строке используйте эту команду:

cscdesigner('ECoderDemos')

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

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

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

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

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

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

  • На вкладке «Атрибуты структуры» для имени Struct» задано значение StructPointer. Для FlatStructure пользовательский класс памяти, имя Struct задает имя переменной структуры в сгенерированном коде. В этом примере StructPointer - имя переменной, заданное внешним кодом.

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

В модели, в диалоговом окне Параметры конфигурации, смотрите панель Генерация кода > Пользовательский код.

В разделе Вставить пользовательский код С в сгенерированный выберите функцию Initialize. Это значение параметров задает код, который будет включен в сгенерированную функцию инициализации модели. В этой модели параметр конфигурации устанавливается так, что сгенерированный код вызывает 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);
}

Похожие темы