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