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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Функциональное определениеМоделирование элемента

codegen-folder/subsystemC

#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. Отовсюду в иерархии модели или графика, можно вызвать функцию, определяемую с Функциональным блоком Simulink при помощи одного из этих элементов моделирования:

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

codegen-folder/modelC

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;
.
.
.

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

codegen-folder/modelC

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/modelC

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).

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

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

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

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

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

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

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

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

Для получения информации смотрите, Генерируют Исходный код Компонента для Экспорта во Внешнюю Кодовую базу (Embedded Coder) и Обзор Моделей Экспорта функций (Simulink).

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

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

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

  • Ограниченные по объему Функциональные блоки Simulink, которые являются на корневом уровне модели

Для получения дополнительной информации смотрите, Настраивают Интерфейсы Функции Точки входа для Simulink Функциональные и Функциональные Блоки Вызывающей стороны (Embedded Coder).

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

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

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

Требования

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

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

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

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

  • В определении Функционального блока Simulink не задавайте сигналы ввода и вывода для Аргумента Inport и блоки Выходного порта Аргумента с классом памяти.

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

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

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

Ограничения

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

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

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

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

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

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

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

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

  • Имена функций запускаются с префиксного func_.

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

  • Имена выходных аргументов имеют форму yn, где 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, func_times2 и func_times3, и вызов каждой функции. Как обозначено в модели, видимости Функционального блока Simulink для 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. В диалоговом окне Configuration Parameters откройте панель Data Type Replacement Code Generation.

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

    • В таблице Data type names введите my_int поскольку замена называет для int32.

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

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

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

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

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

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

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

    • На вкладке Main, набор Argument name к x1 (введите) и y1 вывод .

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

  4. Сконфигурируйте интерфейс Функционального блока Simulink кода. В верхнем уровне модели щелкните правой кнопкой по блоку, представляющему глобальный функциональный 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, который представляет локальную функцию с ограниченной по объему видимостью. На основе требований кода вам придется также сконфигурировать имя функции, имена аргумента ввода и вывода и типы и функциональный интерфейс.

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

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

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

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

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

    • На вкладке Main, набор Argument name к x1 (введите) и y1 вывод .

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

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

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

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

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

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

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

  • Установите 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;
    }
  • Код локальной функции

    Генератор кода помещает определение для локального (ограниченного по объему) функционального 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 списки включают операторы для глобальной переменной functionfunc_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, Функциональная и Функциональная Вызывающая сторона блокирует и отображает соответствующий сгенерированный код.

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

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

  1. Чтобы просмотреть содержимое подсистемы, дважды кликните rtwdemo_functions. Функциональным блоком Simulink является 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);
}

Похожие темы