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

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

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

Откройте исходный файл в качестве примера 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.

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

В модели выберите View> Model Data Editor.

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

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

Нажмите кнопку дополнительной информации Show/refresh.

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

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

cscdesigner('ECoderDemos')

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

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

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

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

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

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

  • На вкладке Structure Attributes имя Struct определяется к StructPointer. Для FlatStructure пользовательский класс памяти имя Struct задает имя переменной структуры в сгенерированном коде. В этом примере StructPointer является именем переменной, которую задает внешний код.

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

В модели, в диалоговом окне Configuration Parameters, осматривают Генерацию кода> панель Пользовательского кода.

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

Похожие темы