В этом примере показано, как использовать блок C Caller с условным выполнением. Модель в качестве примера содержит два блока Вызывающей стороны C, выходные параметры которых вводятся ветви в блок switch. Каждый блок C Caller вызывает одну из пользовательских функций кода С sort_ascend()
и sort_descend()
. Только одно из значений от входных ветвей передается выходной стороне блока switch. Функциональный блок C с теми же настройками может также использоваться вместо блока C Caller, чтобы вызвать эти функции пользовательского кода.
Этот пример иллюстрирует следующие концепции:
Вызов пользовательского кода С от Simulink® блокируется в условном контексте выполнения.
Конфигурирование детерминированных функций функцией в пользовательском коде.
Эта модель вызывает пользовательский код через блок C Caller, который соединяется с входной ветвью блока switch.
open_system('slexCCallerConditional'); % Create a temporary folder for the build and inspection process. currentDir=pwd; [~,cgDir]=rtwdemodir();
Функции пользовательского кода в этой модели не были идентифицированы как детерминированные функции. Когда код сгенерирован из модели, и функции C выполняются в процессе моделирования и в сгенерированном коде, даже при том, что блок switch требует выхода только одной из функций.
slbuild(bdroot); cfile = fullfile(cgDir,'slexCCallerConditional_grt_rtw','slexCCallerConditional.c'); rtwdemodbtype(cfile,'/* Model step', '/* Matfile logging', 1, 0);
### Starting build procedure for: slexCCallerConditional ### Successful completion of build procedure for: slexCCallerConditional Build Summary Top model targets built: Model Action Rebuild Reason ======================================================================================================= slexCCallerConditional 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 25.644s /* Model step function */ void slexCCallerConditional_step(void) { real_T rtb_CCallerascend[6]; real_T rtb_CCallerdescend[6]; int32_T i; /* CCaller: '<Root>/C Caller (ascend)' incorporates: * Inport: '<Root>/In2' */ for (i = 0; i < 6; i++) { rtb_CCallerascend[i] = slexCCallerConditional_U.In2[i]; } sort_ascend(rtb_CCallerascend, 6); /* End of CCaller: '<Root>/C Caller (ascend)' */ /* CCaller: '<Root>/C Caller (descend)' incorporates: * Inport: '<Root>/In2' */ for (i = 0; i < 6; i++) { rtb_CCallerdescend[i] = slexCCallerConditional_U.In2[i]; } sort_descend(rtb_CCallerdescend, 6); /* End of CCaller: '<Root>/C Caller (descend)' */ for (i = 0; i < 6; i++) { /* Switch: '<Root>/Switch' incorporates: * Inport: '<Root>/In1' */ if (slexCCallerConditional_U.In1 > 0.0) { /* Outport: '<Root>/Out3' */ slexCCallerConditional_Y.Out3[i] = rtb_CCallerascend[i]; } else { /* Outport: '<Root>/Out3' */ slexCCallerConditional_Y.Out3[i] = rtb_CCallerdescend[i]; } /* End of Switch: '<Root>/Switch' */ }
Откройте диалоговое окно Configuration Parameters.
В Целевой панели Симуляции, в группе Пользовательского кода Импорта, устанавливает функции Determinsitic на By function
. Нажмите Specify by Function и добавьте функции sort_ascend
и sort_descend
к списку. Это действие говорит модели, что заданные функции пользовательского кода имеют детерминированное поведение, то есть, те же входные значения к функциям всегда дают те же выходные параметры. Если функция собирается быть детерминированной, она не должна быть названа, если это находится во входной ветви, соответствующей ложному значению блока switch.
configset.highlightParameter(bdroot,'DefaultCustomCodeDeterministicFunctions'); set_param(bdroot,'DefaultCustomCodeDeterministicFunctions','ByFunction'); set_param(bdroot,'CustomCodeDeterministicFunctions','sort_ascend,sort_descend');
Теперь, когда вы задали детерминированные функции, сгенерированный код более эффективен, потому что только блок C Caller в истинной ветви блока switch выполняется. Тот же КПД применяется, когда вы симулируете модель в Simulink.
slbuild(bdroot); cfile = fullfile(cgDir,'slexCCallerConditional_grt_rtw','slexCCallerConditional.c'); rtwdemodbtype(cfile,'/* Model step', '/* Matfile logging', 1, 0); close_system(bdroot, 0);
### Starting build procedure for: slexCCallerConditional ### Successful completion of build procedure for: slexCCallerConditional Build Summary Top model targets built: Model Action Rebuild Reason ====================================================================================== slexCCallerConditional 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 10.423s /* Model step function */ void slexCCallerConditional_step(void) { real_T rtb_CCallerascend[6]; int32_T i; /* Switch: '<Root>/Switch' incorporates: * Inport: '<Root>/In1' */ if (slexCCallerConditional_U.In1 > 0.0) { /* CCaller: '<Root>/C Caller (ascend)' incorporates: * Inport: '<Root>/In2' */ for (i = 0; i < 6; i++) { rtb_CCallerascend[i] = slexCCallerConditional_U.In2[i]; } sort_ascend(rtb_CCallerascend, 6); /* End of CCaller: '<Root>/C Caller (ascend)' */ } else { /* CCaller: '<Root>/C Caller (descend)' incorporates: * Inport: '<Root>/In2' */ for (i = 0; i < 6; i++) { rtb_CCallerascend[i] = slexCCallerConditional_U.In2[i]; } sort_descend(rtb_CCallerascend, 6); /* End of CCaller: '<Root>/C Caller (descend)' */ } /* End of Switch: '<Root>/Switch' */ /* Outport: '<Root>/Out3' */ for (i = 0; i < 6; i++) { slexCCallerConditional_Y.Out3[i] = rtb_CCallerascend[i]; } /* End of Outport: '<Root>/Out3' */
C Caller | C Function | Детерминированные функции | Задайте функцией