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