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

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

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

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

На вкладке Modeling нажмите 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);
}

Похожие темы