Функциональные блоки Simulink и генерация кода

Зачем генерировать код из функциональных блоков Simulink и вызывающих функций?

Функциональные блоки Simulink обеспечивают механизм генерации кода C or C++ для компонентов моделирования, которые представляют общие ресурсы. Вы определяете логику как ресурс в блоке Simulink Function, который отделяет интерфейс функции (имя и аргументы) от реализации логики. Функциональные вызывающие абоненты (блоки Function Caller, блоки MATLAB Function и Stateflow® графики) может затем повторно использовать логику функции на разных уровнях иерархии модели.

Функциональные блоки Simulink обеспечивают альтернативу переиспользуемым подсистемам. Для примера фактора использования блока Simulink Function вместо блока подсистемы состоит в том, что блок Simulink Function разделяет состояния между вызывающими функциями. Генератор кода производит одну функцию. Если блок Simulink Function содержит блоки, которые имеют состояния, такие как задержка или память, состояния, постоянные между вызывающими функциями. Порядок вызовов функций является важным фактором.

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

Другие способы использования функциональных блоков Simulink и вызывающих абонентов:

  • Вложение вызовов в функцию.

  • Вызов функции, определенной в одном компоненте моделирования, из другого компонента моделирования.

  • Генерация функций, которые являются глобально доступными или ограниченными по объему.

  • Создание кода для клиентского и серверного приложения.

Опции реализации

Выберите, как реализовать Simulink® функции и вызывающие абоненты на основе ваших требований к генерации кода. Факторы включают в себя:

  • Как вы представляете функцию и функции вызывающих абонентов в модели

  • Область видимости функции

  • Экспортировать ли функцию из модели (требует Embedded Coder®)

  • Индивидуальные настройки интерфейса кода функции (требует Embedded Coder)

  • Требования к генерации кода

  • Ограничения генерации кода

Выбор шаблона моделирования

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

Определение функцииЭлемент моделирования

codegen-folder/ subsystem.c

#include "timestwo_sf.h"

#include "ex_slfunc_comp_sf.h"
#include "ex_slfunc_comp_sf_private.h"

void timestwo_sf(real_T rtu_x, real_T *rty_y)
{
  *rty_y = 2.0 * rtu_x;
}

Функциональный блок Simulink

Вызывающий абонент функции Simulink вызывает функцию, заданную блоком Simulink Function. Из любого места в иерархии модели или графика можно вызвать функцию, заданную блоком Simulink Function, используя один из следующих элементов моделирования:

Вызов функцииЭлемент моделирования

codegen-folder/ model.c

void ex_slfunc_comp_sf_step(void)
{
  real_T rtb_FunctionCaller1;

timestwo_sf(ex_slfunc_comp_sf_U.In1, &rtb_FunctionCaller1);

ex_slfunc_comp_sf_Y.Out1 = rtb_FunctionCaller1;
.
.
.

Блок вызывающего абонента функции

codegen-folder/ model.c

void ex_slfunc_comp_gf_step(void)
{
  real_T rtb_y1_l;

  timestwo_gf(ex_slfunc_comp_gf_U.In4, &rtb_y1_l);

  ex_slfunc_comp_gf_Y.Out4 = rtb_y1_l;  
  .
  .
  .

Переход на диаграмму Stateflow

codegen-folder/ model.c

void ex_slfunc_comp_mf_step(void)
{ 
  real_T rtb_y;
  
  timestwo_mf(ex_slfunc_comp_mf_U.In3, &rtb_y);

  ex_slfunc_comp_mf_Y.Out3 = rtb_y;
  .
  .
  .

Блок MATLAB function

Для получения дополнительной информации о вариантах моделирования смотрите Обзор функций Simulink.

Задайте возможности функции

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

  • Global --- Генератор кода помещает код для глобальной функции в исходные и заголовочные файлы, которые отделены от файлов кода модели (для примера, function.c и function.h) . Отдельные файлы делают код функции доступным для совместного использования между вызывающими абонентами функции.

  • Scoped --- Генератор кода помещает код для функции scoped в файлы кода модели (model.c и model.h). Чтобы вызвать функцию scoped в контексте модели, вызывающий функцию должен быть на том же уровне, что и функция в иерархии модели, или на одном или нескольких уровнях ниже.

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

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

Решите, генерировать ли код экспорта функций

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

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

Задайте интерфейс кода функции Индивидуальных настроек

С помощью Embedded Coder упростите интегрирование сгенерированного кода с внешним кодом, настроив сгенерированные интерфейсы кода функции для блоков Simulink Function и Function Caller. Можно настроить интерфейсы функций для:

  • Глобальные функциональные блоки Simulink

  • Масштабные функциональные блоки Simulink, которые находятся на корневом уровне модели

Для получения дополнительной информации смотрите Сконфигурируйте интерфейсы функции точки входа для блоков Simulink Function и Function Caller.

Незакрытые функциональные блоки Simulink

Если вы используете блок Simulink Function в модели на основе скорости и не вызываете эту функцию, генератор кода рассматривает блок Simulink Function как константу и не производит код функции. Для примера это может произойти во время разработки модели, когда вы готовы задать функцию, но не готовы идентифицировать вызывающего абонента.

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

Требования

  • В рамках иерархии модели имена функции являются уникальными. Если генератор кода находит несколько функций с таким же именем, это вызывает ошибку. Измените имя одной из функций и удалите slprj папка.

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

    • Если генератор кода сначала находит функцию, и сигнатура вызывающего абонента функции не совпадает, генератор кода выдает ошибку. Измените сигнатуру вызывающего абонента функции так, чтобы она совпадала с сигнатурой блока Simulink Function или удалите slprj папка.

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

  • В определении блока Simulink Function не задайте входные и выходные сигналы для блоков Argument Inport и Argument Outport с классом памяти.

  • Не указывайте блоки Inport аргумента и Outport аргумента в качестве тестовых точек.

  • Если вы задаете тип данных входов и выходных сигналов для блоков Аргумента Inport и Аргумент Outport как Simulink.IntEnumType, Simulink.AliasType, или Simulink.Bus, установите DataScope свойство к Imported или Exported.

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

Ограничения

  • Чтобы сгенерировать код из модели, которая включает ограниченные функции Simulink, модель должна быть моделью экспорта функций. Генератор кода не поддерживает основанные на скорости модели, которые включают ограниченные функции Simulink.

  • Можно использовать блок Simulink Function, чтобы задать область видимости функции в модели-ссылке. Однако вы не можете сгенерировать код для модели экспорта функций, которая использует блок Function Caller в атомарной подсистеме, чтобы вызвать эту функцию.

  • Можно вызвать функцию C++, которую генератор кода производит из блока Simulink Function с кодом, сгенерированным из диаграммы Stateflow. Из-за текущих ограничений возможностей для сгенерированных функций C++, вы должны вызвать эти функции с кодом, сгенерированным из блока Function Caller.

  • Функции Simulink и вызывающие абоненты не выполняют MaxStackSize параметр.

  • Генерация кода для интерфейса класса C++ поддерживает только ограниченные области функций Simulink.

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

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

Требования к коду для глобальной функции:

  • Имена функции начинаются с префикса func_.

  • Имена входных аргументов имеют вид x n, где n является уникальным целым значением.

  • Имена выходных аргументов имеют вид y n, где n является уникальным целым значением.

  • Входные и выходные аргументы являются целыми числами (int) и передаются по ссылке. Размер собственного целого числа целевого компьютера составляет 32 бита.

Вы создаете функцию, которая вызывает сгенерированный код переиспользуемой функции. Затем вы создаете и конфигурируете модель, соответствующую требованиям кода.

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

Смотрите внешний код, который вызывает переиспользуемую функцию

В корневой папке генерации кода создайте файлы call_times2.h и call_times2.c. Если вы предпочитаете, можно скопировать файлы из matlabroot\help\toolbox\ecoder\examples.

call_times2.h

typedef int my_int;

call_times2.c

#include "call_times2.h"

void call_times2(void)
{
  int times2result;

  func_times2(x1, &y1);

  printf('Times 2 Value:', y1);
}

Этот код С вызывает переиспользуемую функцию func_times2. Функция умножает целочисленное входное значение x1 на 2 и возвращает результат следующим y1.

Создайте модель

Откройте пример модели ex_slfunc_comp, который доступен в папке matlabroot\help\toolbox\ecoder\examples. Модель включает две функции Simulink, смоделированные как блоки Simulink Function, func_times2 и func_times3и вызов каждой функции. Как указано в модели, видимость блока Simulink Function для func_times2 установлено в global. Эта настройка видимости делает код функции доступным для другого кода, включая внешний код, который вы хотите интегрировать с сгенерированным кодом. Видимость для func_times3 установлено в scoped.

Если вы конфигурируете модель с системным целевым файлом GRT или с системным целевым файлом ERT, File packaging format установлено на Modularгенератор кода производит код функции для модели.

Для получения дополнительной информации смотрите Сгенерировать код для функции Simulink и вызывающего абонента функции.

Сконфигурируйте сгенерированный код, чтобы повторно использовать пользовательский тип данных

Пример принимает, что сгенерированный код запускается на целевом компьютере с собственным целым числом 32 бита. Внешний код представляет целые числа с типом данных my_int, который является псевдонимом int. Сконфигурируйте генератор кода, чтобы использовать my_int вместо типа данных, используемого генератором кода по умолчанию, который является int32_T.

  1. Создайте объект Simulink .AliasType, чтобы представлять пользовательский тип данных my_int.

    my_int = Simulink.AliasType
    
    my_int =
    
      AliasType with properties:
    
        Description: ''
          DataScope: 'Auto'
         HeaderFile: ''
           BaseType: 'double'
  2. Установите свойства типа псевдонима. Введите описание, установите возможности равной Imported, укажите заголовочный файл, который включает определение типа и связать тип псевдонима с базовым типом Simulink int32.

    my_int.Description='Custom 32-bit int representation';
    my_int.DataScope='Imported';
    my_int.HeaderFile='call_times2.h';
    my_int.BaseType='int32';
    
    my_int
      AliasType with properties:
    
        Description: 'Custom 32-bit int representation'
          DataScope: 'Imported'
         HeaderFile: 'call_times2.h'
           BaseType: 'int32'
    
  3. Сконфигурируйте генератор кода, чтобы заменить образцы типа int32_T с my_int. В диалоговом окне Параметров конфигурации откройте панель Code Generation Data Type Replacement .

    • Выберите Replace data type names in the generated code.

    • В таблице Data type names введите my_int для имени замены для int32.

Сконфигурируйте переиспользуемую глобальную функцию

Чтобы внешний код вызывал глобальную функцию, сконфигурируйте соответствующий блок Simulink Function с глобальной видимостью и интерфейсом, который соответствует ожидаемому внешними вызывающими абонентами.

  1. Откройте блок, который представляет times2 функция.

  2. Сконфигурируйте имя функции и видимость путем установки Trigger Port параметров блоков. Например, требования к коду определяют, что имя функции начинается с префикса func_.

    • Установите Function name равными func_times2.

    • Установите Function visibility значение global.

  3. Сконфигурируйте входной параметр функции и выходные аргументы путем установки параметров Argument Inport и Argument Outport параметров блоков. Например, требования к коду определяют, что имена аргумента имеют форму x n и y n. Требования также определяют, что аргументы должны быть типами my_int.

    • На вкладке Main установите Argument name равным x1 (вход) и y1 (выход).

    • На вкладке Signal Attributes установите Data type равным int32. С указанной ранее заменой типа данных int32 появляется в сгенерированном коде следующим myint.

  4. Сконфигурируйте интерфейс блочного кода Simulink Function. На верхнем уровне модели щелкните правой кнопкой мыши блок, представляющий глобальную функцию func_times2. В контекстном меню выберите C/C++ Code Configure C/C++ Function Interface.

    • Установите C/C++ function name значение func_times2.

    • Установите C/C++ return argument значение void.

    • Установите C/C++ Identifier Name для аргумента x1 на x1.

    • Установите C/C++ Identifier Name для аргумента y1 на y1.

    Если в диалоговом окне перечислен выходной аргумент y1 перед входным параметром x1, переупорядочить аргументы путем перетаскивания строки для x1 над строкой для y1.

Сконфигурируйте локальную функцию

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

  1. Откройте блок, который представляет times3 функция.

  2. Сконфигурируйте имя функции и видимость путем установки Trigger Port параметров блоков. Например, требования к коду определяют, что имя функции начинается с префикса func_.

    • Установите Function name равными func_times3.

    • Установите Function visibility значение scoped.

  3. Сконфигурируйте входной параметр функции и выходные аргументы путем установки параметров Argument Inport и Argument Outport параметров блоков. Например, требования к коду определяют, что имена аргумента имеют форму x n и y n. Требования также определяют, что аргументы должны быть типами my_int.

    • На вкладке Main установите Argument name равным x1 (вход) и y1 (выход).

    • На вкладке Signal Attributes установите Data type равным int32. С указанной ранее заменой типа данных int32 появляется в сгенерированном коде следующим my_int.

  4. Сконфигурируйте интерфейс блочного кода Simulink Function. На верхнем уровне модели щелкните правой кнопкой мыши по функции scoped func_times3. В меню выберите C/C++ Code Configure C/C++ Function Interface. В этом случае генератор кода управляет именованием функции и аргументов. Имя функции объединяет имя корневой модели и имя функции, которое вы задаете для порта триггера блока Simulink Function. В этом примере имя являетсяex_slfunc_comp_func_times3.

    Можно задать C/C++ return argument имя аргумента, заданное для блока Argument Outport или void. В данном примере установите для него значение void.

    Для аргументов генератор кода готовится rtu_ (вход) или rty_ (выход) в имя аргумента, заданное для блока Argument Inport.

    Если в диалоговом окне перечислен выходной аргумент y1 перед входным параметром x1, переупорядочить аргументы путем перетаскивания строки для x1 над строкой для y1.

Сконфигурируйте вызывающих абонентов функции

Для каждого вызывающего абонента функции сконфигурируйте параметры блоков Function Caller:

  • Установите Function prototype значение y1 = func_times2(x1).

  • Установите Input argument specifications значение int32(1).

  • Установите Output argument specifications значение int32(1).

Сгенерируйте и смотрите код

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

  • Глобальный код функции

    Исходный код для глобальной, переиспользуемой функции func_times2 находится в папке сборки в файле подсистемы, func_times2.c.

    #include "func_times2.h"
    
    /* Include model header file for global data */
    #include "ex_slfunc_comp.h"
    #include "ex_slfunc_comp_private.h"
    
    void func_times2(my_int x1, my_int *y1)
    {
      *y1 = x1 << 1;
    }
  • Код локальной функции

    Генератор кода помещает определение для локальной (scoped) функции func_times3 в папке сборки файлов в ex_slfunc_comp.c файлов.

    void ex_slfunc_comp_func_times3(my_int rtu_x1, my_int *rty_y1)
    {
      *rty_y1 = 3 * rtu_x1;
    }
  • Вызовы сгенерированных функций

    Функция выполнения модели (шаг) в файле модели ex_slfunc_comp.c, вызывает две функции Simulink: глобальную функцию func_times2 и локальная функция ex_slfunc_comp_func_times3. Имя ex_slfunc_comp_func_times3 отражает возможности локальной функции путем объединения имени модели и имени функции.

    void ex_slfunc_comp_step(void)
    {
      my_int rtb_FunctionCaller2;
    
      func_times2(ex_slfunc_comp_U.In1, &rtb_FunctionCaller2);
      
      ex_slfunc_comp_Y.Out1 = rtb_FunctionCaller2;
    
      ex_slfunc_comp_func_times3(ex_slfunc_comp_U.In2, &rtb_FunctionCaller2);
    
      ex_slfunc_comp_Y.Out2 = rtb_functionCaller2;
      .
      .
      .
  • Объявление точки входа для локальной функции

    Файл заголовка модели ex_slfunc_comp.h включает в себя extern объявление для ex_slfunc_comp_func_times3 функции. Этот оператор объявляет точку входа функции.

    extern void ex_slfunc_comp_func_times3(my_int rtu_x1, my_int *rty_y1);
  • Включите операторы для глобальной функции

    Файл заголовка модели ex_slfunc_comp.h списки включают операторы для глобальной функцииfunc_times2.

    #include "func_times2_private.h"
    #include "func_times2.h"
    
  • Локальные макросы и данные для глобальной функции

    Файл заголовка подсистемы func_times2_private.h задает макросы и включает заголовочные файлы, которые объявляют данные и функции для глобальной функции, func_times2.

    #ifndef RTW_HEADER_func_times2_private_h_
    #define RTW_HEADER_func_times2_private_h_
    #ifndef ex_slfunc_comp_COMMON_INCLUDES_
    #define ex_slfunc_comp_COMMON_INCLUDES_
    #include "rtwtypes.h"
    #endif
    #endif
    
  • Объявление точки входа для глобальной функции

    Общий заголовочный файл func_times2.h, в общей папке утилит slprj/ stf/ _sharedutils, списки общих типов включают для rtwtypes.h. Файл также включает extern объявление для глобальной функции, func_times2. Этот оператор объявляет точку входа функции.

    #ifndef RTW_HEADER_func_times2_
    #define RTW_HEADER_func_times2_
    
    #include "rtwtypes.h"
    
    extern void func_times2(my_int rtu_x1, my_int *rty_y1);
    
    #endif
    

Сгенерируйте код для функции Simulink и вызывающего абонента функции

В этом примере показано, как сгенерировать код С для блоков Simulink Function и Function Caller, и отображается соответствующий сгенерированный код.

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

Сгенерируйте код для определения функции

  1. Чтобы просмотреть содержимое подсистемы, дважды кликните мышью rtwdemo_functions. Блок Simulink Function является f3 подсистема, определяемая как y = f3(u).

  2. Сгенерируйте код.

Генератор кода создает rtwdemo_functions.c. Этот файл содержит определение функции и код инициализации функции.

  • Код инициализации для функции f3:

    void f3_Init(void)
    {
      rtDWork.Delay_DSTATE = 1;
    }
  • Код для функции f3:

    void f3(real_T rtu_u, real_T *rty_y)
    {
      rtY.TicToc10 = rtDWork.Delay_DSTATE;
    
      rtDWork.Delay_DSTATE = (int8_T)(int32_T)-(int32_T)rtY.TicToc10;
    
      adder_h(rtB.Subtract, rtU.U2, rtu_u, rtB.FunctionCaller);
    
      *rty_y = rtB.FunctionCaller;
    }
    
    void adder_h(real_T rtu_u1, 
                 real_T rtu_u2, 
                 real_T rtu_u3, 
                 real_T *rty_y)
    {
      *rty_y = (rtu_u1 + rtu_u2) + rtu_u3;
    }

  • Общий заголовочный файл f3.h содержит объявление точки входа для функции f3.

    #include "rtwtypes.h"
    
    extern void f3(real_T rtu_u, real_T *rty_y);
    

Сгенерируйте код для вызывающего абонента функции

  1. В rtwdemo_export_functions модель, дважды кликните rtwdemo_caller для просмотра содержимого подсистемы вызывающего абонента.

  2. Сгенерируйте код.

Генератор кода создает файлы rtwdemo_caller.h и rtwdemo_caller.c в папке rtwdemo_caller_ert_rtw.

rtwdemo_caller.h включает общий заголовочный файл, f3.h, который содержит объявление точки входа функции.

rtwdemo_caller.c вызывает функцию f3.

void rtwdemo_caller_t_10tic(const real_T *rtu_u, 
                            real_T *rty_y)
{
  f3(*rtu_u, rty_y);
}

Похожие темы