Как сгенерированный код обменивается данными со окружением

Чтобы использовать код, который вы генерируете из модели, вы вызываете сгенерированные функции точки входа, такие как step и initialize. Окружению, в которой вы вызываете эти функции, должны предоставить входные сигналы данные и, в зависимости от вашего приложения, информацию о планировании. Затем сгенерированный алгоритм вычисляет выходные данные, которые может использовать вызывающее окружение. Окружения и алгоритм могут обмениваться этими данными через глобальные переменные или через формальные параметры (аргументы).

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

  • Написание кода, который вызывает сгенерированный код.

  • Сгенерируйте переиспользуемый (повторно входящий) код, который можно вызвать несколько раз в одном приложении.

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

В модели блоки Inport и Outport корневого уровня представляют первичные входные параметры и выходы алгоритма блока. По умолчанию генератор кода агрегирует эти блоки в стандартные структуры, которые хранят входные и выходные данные.

Для получения информации о том, как сгенерированный код хранит внутренние данные, которые не участвуют в интерфейсе модели, смотрите, Как Сгенерированный код хранит Внутренний сигнал, Состояние и Данные параметра.

Интерфейсы данных в сгенерированном коде

В этом примере показано, как сгенерированный код обменивается данными со окружением.

Исследуйте модель примера

Откройте пример модели rtwdemo_roll.

open_system('rtwdemo_roll')

На корневом уровне модель имеет ряд блоков Inport и один блок Outport.

В модели установите параметры конфигурации > Генерация кода > Системный целевой файл grt.tlc.

set_param('rtwdemo_roll','SystemTargetFile','grt.tlc')

Проверьте параметры конфигурации > Генерация кода > Интерфейс > Упаковка интерфейса кода. Настройка Nonreusable function означает, что сгенерированный код не является переиспользуемым (не входящим).

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

set_param('rtwdemo_roll','MatFileLogging','off')

Сгенерируйте непереиспользуемый код

Сгенерируйте код из модели.

slbuild('rtwdemo_roll')
### Starting build procedure for: rtwdemo_roll
### Successful completion of build procedure for: rtwdemo_roll

Build Summary

Top model targets built:

Model         Action                       Rebuild Reason                                    
=============================================================================================
rtwdemo_roll  Code generated and compiled  Code generation information file does not exist.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 7.4399s

Смотрите файл rtwdemo_roll.h. Файл определяет тип структуры, который представляет входные данные и тип, который представляет выходные данные.

file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.h');
rtwdemodbtype(file,...
    '/* External inputs (root inport signals with default storage) */',...
    '} ExtY_rtwdemo_roll_T;',1,1)
/* External inputs (root inport signals with default storage) */
typedef struct {
  real32_T Phi;                        /* '<Root>/Phi' */
  real32_T Psi;                        /* '<Root>/Psi' */
  real32_T Rate_FB;                    /* '<Root>/Rate_FB' */
  real32_T TAS;                        /* '<Root>/TAS' */
  boolean_T AP_Eng;                    /* '<Root>/AP_Eng' */
  boolean_T HDG_Mode;                  /* '<Root>/HDG_Mode' */
  real32_T HDG_Ref;                    /* '<Root>/HDG_Ref' */
  real32_T Turn_Knob;                  /* '<Root>/Turn_Knob' */
} ExtU_rtwdemo_roll_T;

/* External outputs (root outports fed by signals with default storage) */
typedef struct {
  real32_T Ail_Cmd;                    /* '<Root>/Ail_Cmd' */
} ExtY_rtwdemo_roll_T;

Каждое поле соответствует блоку Inport или Outport на корневом уровне модели. Имя каждого поля определяется именем блока.

Файл также задает тип структуры, структуру данных модели реального времени, одно поле которой хранит индикацию выполнения, столкнулся ли сгенерированный код с ошибкой во время выполнения.

rtwdemodbtype(file,'/* Real-time Model Data Structure */',...
    '/* Block states (default storage) */',1,0)
/* Real-time Model Data Structure */
struct tag_RTM_rtwdemo_roll_T {
  const char_T *errorStatus;
};

Когда вы изменяете параметры конфигурации модели в соответствии с вашим приложением, эта структура может также содержать другие данные, которые относятся ко всей модели, такие как информация о планировании.

Для типа структуры, который представляет структуру данных модели реального времени, файл rtwdemo_roll_types.h создает псевдоним (typedef), который сгенерированный код позже использует, чтобы выделить память для структуры.

file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll_types.h');
rtwdemodbtype(file,'/* Forward declaration for rtModel */',...
    'RT_MODEL_rtwdemo_roll_T;',1,1)
/* Forward declaration for rtModel */
typedef struct tag_RTM_rtwdemo_roll_T RT_MODEL_rtwdemo_roll_T;

Используя эти типы структур, файл rtwdemo_roll.c определяет (выделяет память для) глобальные структурные переменные, которые хранят входные и выходные данные для сгенерированного алгоритма. Файл также задает переменные, которые представляют структуру данных модели реального времени и указатель на структуру.

file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.c');
rtwdemodbtype(file,...
    '/* External inputs (root inport signals with default storage) */',...
    '= &rtwdemo_roll_M_;',1,1)
/* External inputs (root inport signals with default storage) */
ExtU_rtwdemo_roll_T rtwdemo_roll_U;

/* External outputs (root outports fed by signals with default storage) */
ExtY_rtwdemo_roll_T rtwdemo_roll_Y;

/* Real-time model */
static RT_MODEL_rtwdemo_roll_T rtwdemo_roll_M_;
RT_MODEL_rtwdemo_roll_T *const rtwdemo_roll_M = &rtwdemo_roll_M_;

Файл rtwdemo_roll.h объявляет эти структурные переменные. Ваш внешний код может включать (#include) этот файл, общее имя которого model.h где model - имя модели для доступа к данным, которые участвуют в интерфейсе модели.

В rtwdemo_roll.c, модель step функция, которая представляет основной алгоритм модели, использует void void интерфейс (без аргументов).

rtwdemodbtype(file,...
    '/* Model step function */','void rtwdemo_roll_step(void)',1,1)
/* Model step function */
void rtwdemo_roll_step(void)

В определении функции алгоритм читает входные данные и записывает выходные данные путем прямого доступа к переменным глобальной структуры. Для примера, около конца алгоритма, код для EngSwitch блок считывает значение AP_Eng поле (которое представляет вход) и, исходя из этого значения, условно записывает постоянное значение в Ail_Cmd поле (которое представляет выход).

rtwdemodbtype(file,'if (rtwdemo_roll_U.AP_Eng) {','      }',1,1)
  if (rtwdemo_roll_U.AP_Eng) {
    /* Outputs for Atomic SubSystem: '<Root>/BasicRollMode' */
    /* Saturate: '<S1>/CmdLimit' */
    if (rtwdemo_roll_Y.Ail_Cmd > 15.0F) {
      /* Sum: '<S1>/Sum2' incorporates:
       *  Outport: '<Root>/Ail_Cmd'
       */
      rtwdemo_roll_Y.Ail_Cmd = 15.0F;
    } else if (rtwdemo_roll_Y.Ail_Cmd < -15.0F) {
      /* Sum: '<S1>/Sum2' incorporates:
       *  Outport: '<Root>/Ail_Cmd'
       */
      rtwdemo_roll_Y.Ail_Cmd = -15.0F;
    }

    /* End of Saturate: '<S1>/CmdLimit' */
    /* End of Outputs for SubSystem: '<Root>/BasicRollMode' */
  } else {
    /* Sum: '<S1>/Sum2' incorporates:
     *  Constant: '<Root>/Zero'
     *  Outport: '<Root>/Ail_Cmd'
     */
    rtwdemo_roll_Y.Ail_Cmd = 0.0F;
  }

  /* End of Switch: '<Root>/EngSwitch' */
}

/* Model initialize function */
void rtwdemo_roll_initialize(void)
{
  /* Registration code */

  /* initialize error status */
  rtmSetErrorStatus(rtwdemo_roll_M, (NULL));

  /* states (dwork) */
  (void) memset((void *)&rtwdemo_roll_DW, 0,
                sizeof(DW_rtwdemo_roll_T));

  /* external inputs */
  (void)memset(&rtwdemo_roll_U, 0, sizeof(ExtU_rtwdemo_roll_T));

  /* external outputs */
  rtwdemo_roll_Y.Ail_Cmd = 0.0F;

  /* SystemInitialize for Atomic SubSystem: '<Root>/RollAngleReference' */
  /* InitializeConditions for UnitDelay: '<S4>/FixPt Unit Delay1' */
  rtwdemo_roll_DW.FixPtUnitDelay1_DSTATE = 0.0F;

  /* End of SystemInitialize for SubSystem: '<Root>/RollAngleReference' */

  /* SystemInitialize for Atomic SubSystem: '<Root>/BasicRollMode' */
  /* InitializeConditions for DiscreteIntegrator: '<S1>/Integrator' */
  rtwdemo_roll_DW.Integrator_DSTATE = 0.0F;
  rtwdemo_roll_DW.Integrator_PrevResetState = 0;

  /* End of SystemInitialize for SubSystem: '<Root>/BasicRollMode' */
}

/* Model terminate function */
void rtwdemo_roll_terminate(void)
{
  /* (no terminate code required) */
}

Из-за void void интерфейс и прямой доступ к данным, функция не возвращается. Если вы вызываете функцию несколько раз в приложении, каждый вызов считывает и записывает входные и выходные данные в одни и те же переменные глобальной структуры, что приводит к повреждению данных и непреднамеренному взаимодействию между вызовами.

Функция инициализации модели, rtwdemo_roll_initialize, инициализирует входные и выходные данные в нуле. Функция также инициализирует состояние ошибки. Функция непосредственно обращается к глобальным переменным, что означает, что функция не перевходящая.

rtwdemodbtype(file,'/* Model initialize function */',...
    'rtmSetErrorStatus(rtwdemo_roll_M, (NULL));',1,1)
/* Model initialize function */
void rtwdemo_roll_initialize(void)
{
  /* Registration code */

  /* initialize error status */
  rtmSetErrorStatus(rtwdemo_roll_M, (NULL));
rtwdemodbtype(file,'  /* external inputs */',...
    '/* SystemInitialize for Atomic SubSystem:',1,0)
  /* external inputs */
  (void)memset(&rtwdemo_roll_U, 0, sizeof(ExtU_rtwdemo_roll_T));

  /* external outputs */
  rtwdemo_roll_Y.Ail_Cmd = 0.0F;

Сгенерируйте переиспользуемый код

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

В модели установите Параметры конфигурации > Генерацией кода > Интерфейс > Кодом упаковку интерфейсов Reusable function.

set_param('rtwdemo_roll','CodeInterfacePackaging','Reusable function')

Сгенерируйте код из модели.

slbuild('rtwdemo_roll')
### Starting build procedure for: rtwdemo_roll
### Successful completion of build procedure for: rtwdemo_roll

Build Summary

Top model targets built:

Model         Action                       Rebuild Reason                   
============================================================================
rtwdemo_roll  Code generated and compiled  Generated code was out of date.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 6.1374s

Теперь, в rtwdemo_roll.hструктура данных модели реального времени содержит указатели на индикацию ошибки, входные данные, выходные данные и дополнительные данные в виде DWork подструктура (которая сохраняет, для примера состояний блока такое как состояние блока Интегратора Дискретного Времени).

file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.h');
rtwdemodbtype(file,'/* Real-time Model Data Structure */',...
    '/* External data declarations for dependent source files */',1,0)
/* Real-time Model Data Structure */
struct tag_RTM_rtwdemo_roll_T {
  const char_T *errorStatus;
  ExtU_rtwdemo_roll_T *inputs;
  ExtY_rtwdemo_roll_T *outputs;
  DW_rtwdemo_roll_T *dwork;
};

Чтобы вызвать сгенерированный код несколько раз в приложении, ваш код должен выделить память для структуры данных модели реального времени на каждый вызов. Файл rtwdemo_roll.c задает специализированную функцию, которая выделяет память для новой структуры данных модели реального времени и возвращает указатель на структуру. Функция также выделяет память для подструктур, на которые указывают поля в структуре данных моделей, таких как входная и выходная структуры.

file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.c');
rtwdemodbtype(file,'/* Model data allocation function */',...
    'RT_MODEL_rtwdemo_roll_T *rtwdemo_roll(void)',1,1)
/* Model data allocation function */
RT_MODEL_rtwdemo_roll_T *rtwdemo_roll(void)

В rtwdemo_roll.c, модель step функция принимает аргумент, который представляет структуру данных модели реального времени.

file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.c');
rtwdemodbtype(file,...
    '/* Model step function */','void rtwdemo_roll_step',1,1)
/* Model step function */
void rtwdemo_roll_step(RT_MODEL_rtwdemo_roll_T *const rtwdemo_roll_M)

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

rtwdemodbtype(file,...
    '*rtwdemo_roll_DW =','rtwdemo_roll_M->outputs;',1,1)
  DW_rtwdemo_roll_T *rtwdemo_roll_DW = rtwdemo_roll_M->dwork;
  ExtU_rtwdemo_roll_T *rtwdemo_roll_U = (ExtU_rtwdemo_roll_T *)
    rtwdemo_roll_M->inputs;
  ExtY_rtwdemo_roll_T *rtwdemo_roll_Y = (ExtY_rtwdemo_roll_T *)
    rtwdemo_roll_M->outputs;

Затем, чтобы получить доступ к входным и выходным данным, хранящимся в глобальной памяти, алгоритм взаимодействует с этими локальными переменными.

rtwdemodbtype(file,'  if (rtwdemo_roll_U->AP_Eng) {',...
    '  /* End of Switch: ''<Root>/EngSwitch'' */',1,1)
  if (rtwdemo_roll_U->AP_Eng) {
    /* Outputs for Atomic SubSystem: '<Root>/BasicRollMode' */
    /* Saturate: '<S1>/CmdLimit' */
    if (rtwdemo_roll_Y->Ail_Cmd > 15.0F) {
      /* Sum: '<S1>/Sum2' incorporates:
       *  Outport: '<Root>/Ail_Cmd'
       */
      rtwdemo_roll_Y->Ail_Cmd = 15.0F;
    } else if (rtwdemo_roll_Y->Ail_Cmd < -15.0F) {
      /* Sum: '<S1>/Sum2' incorporates:
       *  Outport: '<Root>/Ail_Cmd'
       */
      rtwdemo_roll_Y->Ail_Cmd = -15.0F;
    }

    /* End of Saturate: '<S1>/CmdLimit' */
    /* End of Outputs for SubSystem: '<Root>/BasicRollMode' */
  } else {
    /* Sum: '<S1>/Sum2' incorporates:
     *  Constant: '<Root>/Zero'
     *  Outport: '<Root>/Ail_Cmd'
     */
    rtwdemo_roll_Y->Ail_Cmd = 0.0F;
  }

Точно так же функция инициализации модели принимает структуру данных модели реального времени как аргумент.

rtwdemodbtype(file,...
    '/* Model initialize function */','void rtwdemo_roll_initialize',1,1)
/* Model initialize function */
void rtwdemo_roll_initialize(RT_MODEL_rtwdemo_roll_T *const rtwdemo_roll_M)

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

Сконфигурируйте интерфейс данных

Для управления характеристиками интерфейса данных в сгенерированном коде смотрите Управляющие данные и Функциональный интерфейс в Сгенерированном коде.

Похожие темы