Этот пример показывает, как сгенерировать код C из модели алгоритма управления и интегрировать этот код с существующим кодом внешнего приложения. В полном приложении, которое состоит из трех модулей, модуль алгоритма должен обмениваться данными с другими модулями через глобальные переменные. В примере вы конфигурируете сгенерированный код так, чтобы он взаимодействовал с существующими внешними переменными, напоминал внешний код во внешнем виде и организации и соответствовал определенным требованиям к кодированию.
Установите текущую папку в место с возможностью записи.
Скопируйте скрипт prepare_ext_code
в текущую папку и запустите скрипт. Скрипт копирует файлы внешнего кода в несколько папок.
try copyfile(fullfile(matlabroot,'examples','ecoder','main','prepare_ext_code.m'),... 'prepare_ext_code.m','f'); catch end run('prepare_ext_code.m');
В текущей папке откройте ext_code_main.c
. Этот код приложения представляет встраиваемой системе с тривиальным алгоритмом планирования (a while
цикл) и три модуля, алгоритмы которых выполняются в каждом цикле выполнения: ex_ext_inputs_proc
, ex_ext_ctrl_alg
, и ex_ext_outputs_proc
.
type('ext_code_main.c')
В shared
папка, смотрите ex_ext_projTypes.h
. Файл задает два пользовательских типа данных (typedef
), которые используют данные в модулях.
type(fullfile('shared','ex_ext_projTypes.h'))
В io_drivers
папка, смотрите ex_sensor_accessors.c
. Этот файл определяет функции, get_fromSensor_flow
и get_fromSensor_temp
, которые возвращают необработанные данные, записанные датчиком потока и датчиком температуры. В данном примере функции возвращают тривиальные синусоидальные раздражители для алгоритма управления.
type(fullfile('io_drivers','ex_sensor_accessors.c'))
В ex_ext_inputs_proc
папка, смотрите ex_ext_inputs_proc.c
. The ex_ext_inputs_proc
модуль считывает данные датчика (путем вызова функций доступа), фильтрует данные и хранит их в двух глобальных переменных, PROC_INPUT_FLOW
и PROC_INPUT_TEMP
. Эти глобальные переменные определены в файле ex_ext_proc_inputs.c
и объявленный в ex_ext_proc_inputs.h
.
type(fullfile('ex_ext_inputs_proc','ex_ext_inputs_proc.c'))
Алгоритм фильтра в этом модуле и алгоритмы в двух других модулях требуют данных о состоянии, которые должны сохраняться между циклами выполнения приложения. Каждый модуль хранит соответствующие данные о состоянии как глобальные переменные. Для примера, в ex_ext_inputs_proc
модуль, ex_ext_inputs_proc.c
задает следующие переменные:
flowFilterIn_state_data
tempFilterIn_state_data
flowFilterIn_tmp_data
tempFilterIn_tmp_data
Пустой ex_ext_ctrl_alg
папка является заполнителем для сгенерированного кода. The ex_ext_ctrl_alg
модуль должен выполнить управление ПИД для фильтрованных измерений расхода и температуры. Позже вы исследуете требования к этому коду, которые основаны на коде в других модулях.
В ex_ext_outputs_proc
папка, смотрите ex_ext_outputs_proc.c
. Этот модуль считывает ПИД выходные сигналы от глобальных переменных с именем CONTR_SIG_FLOW
и CONTR_SIG_TEMP
. The ex_ext_ctrl_alg
модуль (сгенерированный код) должен задать эти переменные. The ex_ext_outputs_proc
затем модуль фильтрует эти сигналы и передает отфильтрованные значения в функции, представляющие приводы устройства для приводов (для примера, клапана и нити накала нагревателя).
type(fullfile('ex_ext_outputs_proc','ex_ext_outputs_proc.c'))
Функции привода определены в io_drivers
папка в файле ex_actuator_accessors.c
.
Рисунок показывает предполагаемый поток данных через систему. Рисунок также показывает файлы кода, которые определяют и объявляют данные (глобальные переменные), которые пересекают контуры модуля.
Откройте пример модели ex_ext_ctrl_alg
.
open_system('ex_ext_ctrl_alg')
Блоки в модели реализуют необходимый алгоритм управления ПИД. Модель использует настройки генерации кода по умолчанию для целевого файла системы на основе ERT (ert.tlc
).
Чтобы завершить работу приложения, выполнив функцию ex_ext_ctrl_alg
модуль, код, сгенерированный из этой модели, должен:
Используйте пользовательские типы данных dataPath_flow_T
и dataPath_temp_T
из внешнего файла ex_ext_projTypes.h
.
Считайте отфильтрованные данные о датчике из глобальных переменных PROC_INPUT_FLOW
и PROC_INPUT_TEMP
. Сгенерированный код не должен определять эти переменные, потому что модуль ex_ext_inputs_proc
определяет их, объявляя их в ex_ext_proc_inputs.h
.
Запись ПИД управляющих сигналов в глобальные переменные с именем CONTR_SIG_FLOW
и CONTR_SIG_TEMP
. Сгенерированный код должен задать эти переменные и объявить их в файле с именем ex_ext_ctrl_sigs.h
. Затем, ex_ext_outputs_proc
модуль может считывать необработанные сигналы управления от них.
Соответствует стандартам именования переменных, которые управляют внешним приложением. Например, сгенерированный код должен хранить данные о состоянии в глобальных переменных, имена которых заканчиваются _data
. В сложение для этого примера имена переменных локальной функции должны заканчиваться на _local
.
Соответствовать стандартам, которые регулируют организацию кода в каждом из внешних файлов. Например, каждый файл содержит разделы, разделенные комментариями, которые агрегируют подобные конструкции кода, такие как определения типов, объявления переменных и определения функций.
Чтобы вы и другие могли взаимодействовать с алгоритмом управления во время выполнения, для этого примера вы также конфигурируете сгенерированный код, чтобы задать и объявить const
глобальные переменные с именем PARAM_setpoint_flow
и PARAM_setpoint_temp
, которые представляют ПИД-регулятору уставки. Определения должны находиться в файле с именем ex_ext_ctrl_params.c
и объявления должны находиться в файле с именем ex_ext_ctrl_params.h
.
Установите текущую папку в shared
папка.
Используйте функцию Simulink.importExternalCTypes
чтобы сгенерировать Simulink.AliasType
объекты, которые представляют пользовательские типы данных dataPath_flow_T
и dataPath_temp_T
.
cd('shared') Simulink.importExternalCTypes('ex_ext_projTypes.h');
Объекты появляются в базовом рабочем пространстве.
В ex_ext_ctrl_alg
на вкладке Моделирование (Modeling) щелкните Редактор данных модели (Model Data Editor).
В Model Data Editor для блока Inport, который представляет PROC_INPUT_FLOW
, Установите Тип Данных dataPath_flow_T
.
Для блока Inport, который представляет PROC_INPUT_TEMP
, Установите Тип Данных dataPath_temp_T
.
Выберите вкладку Signals.
В модели выберите выходной сигнал каждого блока Constant. В Model Data Editor установите для типа данных значение Inherit: Inherit via back propagation
. С помощью этой настройки каждый блок Constant наследует свой тип выходных данных от блока сразу после, в этом случае, блока Sum.
Кроме того, чтобы сконфигурировать типы данных, в командной строке используйте эти команды.
set_param('ex_ext_ctrl_alg/In1','OutDataTypeStr','dataPath_flow_T') set_param('ex_ext_ctrl_alg/In2','OutDataTypeStr','dataPath_temp_T') set_param('ex_ext_ctrl_alg/Flow Setpt','OutDataTypeStr',... 'Inherit: Inherit via back propagation') set_param('ex_ext_ctrl_alg/Temp Setpt','OutDataTypeStr',... 'Inherit: Inherit via back propagation')
Обновите блок. Схема показывает, что из-за наследования и распространения типа данных сигналы в модели используют пользовательский тип данных.
Сконфигурируйте модель, чтобы сгенерировать код, который обращается и определяет правильные глобальные переменные, такие как PROC_INPUT_FLOW
и CONTR_SIG_TEMP
.
В Model Data Editor выберите вкладку Inports/Outports и установите в раскрывающемся списке Change view значение Code
.
Выберите строки, которые соответствуют двум блокам Inport.
Для каждой строки установите значение класса памяти равным ImportFromFile
и заголовочный файл для ex_ext_proc_inputs.h
. С классом памяти ImportFromFile
каждый блок Inport появляется в сгенерированном коде как глобальная переменная. Однако сгенерированный код не определяет переменную, вместо этого включая (#include
) объявление переменной из ex_ext_proc_inputs.h
.
Для строк, которые соответствуют блокам Outport, установите:
Класс памяти, к ExportToFile
Заголовочный файл для ex_ext_ctrl_sigs.h
Файл определения для ex_ext_ctrl_sigs.c
С ExportToFile
сгенерированный код определяет глобальную переменную.
Кроме того, чтобы сконфигурировать сигналы, в командной строке используйте эти команды.
temp = Simulink.Signal; temp.CoderInfo.StorageClass = 'Custom'; temp.CoderInfo.CustomStorageClass = 'ImportFromFile'; temp.CoderInfo.CustomAttributes.HeaderFile = 'ex_ext_proc_inputs.h'; portHandles = get_param('ex_ext_ctrl_alg/In1','portHandles'); outportHandle = portHandles.Outport; set_param(outportHandle,'SignalObject',copy(temp)) portHandles = get_param('ex_ext_ctrl_alg/In2','portHandles'); outportHandle = portHandles.Outport; set_param(outportHandle,'SignalObject',copy(temp)) temp.CoderInfo.CustomStorageClass = 'ExportToFile'; temp.CoderInfo.CustomAttributes.HeaderFile = 'ex_ext_ctrl_sigs.h'; temp.CoderInfo.CustomAttributes.DefinitionFile = 'ex_ext_ctrl_sigs.c'; set_param('ex_ext_ctrl_alg/Out1','SignalObject',copy(temp)) set_param('ex_ext_ctrl_alg/Out2','SignalObject',copy(temp))
Чтобы применить класс памяти к параметрам блоков, такому как параметр Constant значения блока Constant, необходимо создать такой объект параметра, как Simulink.Parameter
. Можно использовать Редактор данных модели (Model Data Editor), чтобы создать объекты параметров.
Выберите вкладку Parameters и установите Change view на Design
.
В модели выберите маркированный блок Constant Flow Setpt
.
В Model Data Editor установите значение PARAM_setpoint_flow
.
Рядом с PARAM_setpoint_flow
, нажмите кнопку действия (с тремя вертикальными точками) и выберите Create.
В диалоговом окне «Создание новых данных» установите значение Simulink.Parameter(3)
.
Установите положение на Model Workspace
и нажмите «Создать».
В PARAM_setpoint_flow
диалоговое окно свойств, установите для класса памяти значение Const
.
Установите значение HeaderFile на ex_ext_ctrl_params.h
и DefinitionFile, чтобы ex_ext_ctrl_params.c
.
Для другого блока Constant используйте Model Data Editor, чтобы создать Simulink.Parameter
объект с именем PARAM_setpoint_temp
со значением 2
.
Кроме того, чтобы сконфигурировать блоки, в командной строке используйте эти команды.
PARAM_setpoint_flow = Simulink.Parameter(3); PARAM_setpoint_flow.CoderInfo.StorageClass = 'Custom'; PARAM_setpoint_flow.CoderInfo.CustomStorageClass = 'Const'; PARAM_setpoint_flow.CoderInfo.CustomAttributes.HeaderFile = 'ex_ext_ctrl_params.h'; PARAM_setpoint_flow.CoderInfo.CustomAttributes.DefinitionFile = 'ex_ext_ctrl_params.c'; PARAM_setpoint_temp = copy(PARAM_setpoint_flow); PARAM_setpoint_temp.Value = 2; mdlwks = get_param('ex_ext_ctrl_alg','ModelWorkspace'); assignin(mdlwks,'PARAM_setpoint_flow',copy(PARAM_setpoint_flow)) assignin(mdlwks,'PARAM_setpoint_temp',copy(PARAM_setpoint_temp)) set_param('ex_ext_ctrl_alg/Flow Setpt','Value','PARAM_setpoint_flow') set_param('ex_ext_ctrl_alg/Temp Setpt','Value','PARAM_setpoint_temp') clear temp PARAM_setpoint_flow PARAM_setpoint_temp mdlwks portHandles outportHandle
Во внешнем коде внутренние данные, которые не участвуют в интерфейсах модуля, таких как данные о состоянии и локальные переменные в функциях, соответствуют схемам именования. В модели сконфигурируйте внутренние данные, которые появляются в сгенерированном коде, чтобы имитировать эти схемы именования.
В диалоговом окне Параметры конфигурации модели смотрите панель Генерация кода > Идентификаторы. Когда вы задаете значения для схем именования под управлением формата идентификатора:
$R
представляет имя модели, ex_ext_ctrl_alg
.
$N
представляет имя каждого элемента модели, к которому применяется схема, такого как сигнал, состояние блока или стандартная структура данных.
$M
представляет текст управления именами, который вставляет генератор кода, при необходимости, чтобы избежать конфликтов имен. Для большинства правил именования требуется эта лексема.
Установите глобальные переменные на $R$N_data$M
. Этот параметр управляет именами глобальных переменных, таких как те, которые представляют данные о состоянии. Схема именования $R$N_data_$M
наиболее близко аппроксимирует схему, которую используют переменные состояния во внешнем коде.
Установите Локальные временные переменные и выходные переменные Локальные блоки в $N_local$M
.
Кроме того, чтобы задать параметры конфигурации, в командной строке используйте эти команды.
set_param('ex_ext_ctrl_alg','CustomSymbolStrGlobalVar','$R$N_data$M') set_param('ex_ext_ctrl_alg','CustomSymbolStrTmpVar','$N_local$M') set_param('ex_ext_ctrl_alg','CustomSymbolStrBlkIO','$N_local$M')
Сконфигурируйте данные о состоянии в модели, чтобы они появлялись в сгенерированном коде как отдельные глобальные переменные вместо полей стандартной структуры DWork. Включите перспективу Кода. В галерее Apps нажмите Embedded Coder.
Под блок схемой в разделе Кода Отображений > Значения по умолчанию для строки внутренних данных в Класс памяти столбце выберите ExportedGlobal
.
Кроме того, чтобы сконфигурировать этот класс памяти по умолчанию, используйте следующие команды в командной строке:
coder.mapping.create('ex_ext_ctrl_alg'); coder.mapping.defaults.set('ex_ext_ctrl_alg','InternalData',... 'StorageClass','ExportedGlobal');
Установите текущую папку в ex_ext_ctrl_alg
папка.
cd(fullfile('..','ex_ext_ctrl_alg'))
В командной строке перейдите к папке, содержащей встроенный шаблон генерации кода ert_code_template.cgt
. По умолчанию, когда вы генерируете код с системным целевым файлом ert.tlc
этот шаблон управляет организацией и, отчасти, внешним видом кода в каждом сгенерированном файле.
currentFolder = pwd; cd(fullfile(matlabroot,'toolbox','rtw','targets','ecoder'))
Скопируйте ert_code_template.cgt
файл в буфер обмена.
Вернуться к ex_ext_ctrl_alg
папка. Чтобы избежать перезаписи буфера обмена, вместо использования командной строки для перехода в папку можно использовать кнопку «Назад» в MATLAB.
cd(currentFolder)
clear currentFolder
Вставьте файл в ex_ext_ctrl_alg
папка. Переименуйте файл в ex_my_code_template.cgt
.
Откройте файл и замените содержимое этим кодом.
type(fullfile(matlabroot,'examples','ecoder','data','ex_my_code_template.cgt'))
Этот новый шаблон более точно соответствует организации внешних файлов. Например, шаблон организует подобные конструкции кода в именованные разделы (разделенные комментариями) и, в верхней части шаблона, задает только минимальную информацию о каждом сгенерированном файле.
В модели выберите Параметры конфигурации > Генерация кода > Шаблоны.
В разделе Шаблоны кода и шаблоны данных установите четыре параметра конфигурации равными ex_my_code_template.cgt
.
Кроме того, чтобы скопировать файл и задать параметры, в командной строке используйте эти команды.
copyfile(fullfile(matlabroot,'examples','ecoder','data','ex_my_code_template.cgt'),... 'ex_my_code_template.cgt','f') set_param('ex_ext_ctrl_alg','ERTSrcFileBannerTemplate','ex_my_code_template.cgt') set_param('ex_ext_ctrl_alg','ERTHdrFileBannerTemplate','ex_my_code_template.cgt') set_param('ex_ext_ctrl_alg','ERTDataSrcFileTemplate','ex_my_code_template.cgt') set_param('ex_ext_ctrl_alg','ERTDataHdrFileTemplate','ex_my_code_template.cgt')
Потому что внешний код уже определяет main
выберите Параметры конфигурации > Сгенерировать только код и очистить Параметры конфигурации > Сгенерировать пример основной программы.
set_param('ex_ext_ctrl_alg','GenCodeOnly','on') set_param('ex_ext_ctrl_alg','GenerateSampleERTMain','off')
Сгенерируйте код из модели.
rtwbuild('ex_ext_ctrl_alg')
В отчете о генерации кода проверьте сгенерированные файлы. Код соответствует требованиям. Для примера, ex_ext_ctrl_sigs.c
определяет выходные сигналы управления, CONTR_SIG_FLOW
и CONTR_SIG_TEMP
.
file = fullfile('ex_ext_ctrl_alg_ert_rtw','ex_ext_ctrl_sigs.c'); rtwdemodbtype(file,'dataPath_flow_T CONTR_SIG_FLOW;',... 'dataPath_temp_T CONTR_SIG_TEMP;',1,1)
Параметры уставки появляются в ex_ext_ctrl_params.c
.
file = fullfile('ex_ext_ctrl_alg_ert_rtw','ex_ext_ctrl_params.c'); rtwdemodbtype(file,'const dataPath_flow_T PARAM_setpoint_flow = 3.0;',... 'const dataPath_temp_T PARAM_setpoint_temp = 2.0;',1,1)
Файл ex_ext_ctrl_alg.c
задает глобальные переменные для хранения данных о состоянии. Переменные следуют указанной схеме именования. Код аналогичен следующему:
dataPath_temp_T ex_ext__Integrator_DSTATE_datag; dataPath_flow_T ex_ext_c_Integrator_DSTATE_data; dataPath_temp_T ex_ext_ctrl_Filter_DSTATE_datad; dataPath_flow_T ex_ext_ctrl__Filter_DSTATE_data;
В том же файле функция выполнения модели, ex_ext_ctrl_alg_step
, создает локальные переменные функции для хранения временных вычислений. Переменные следуют указанной схеме именования. Код аналогичен следующему:
dataPath_flow_T Diff_local; dataPath_flow_T FilterCoefficient_local; dataPath_temp_T Diff1_local; dataPath_temp_T FilterCoefficient_locali;
Некоторые глобальные и локальные имена переменных содержат дополнительные искривляющие символы, которые предотвращают конфликты имен. Эти дополнительные символы соответствуют $M
лексема, заданный в схемах именования.
Сгенерированные коды находятся в сгенерированных папках ex_ext_ctrl_alg_ert_rtw
и slprj
. Необходимо сконфигурировать системы управления файлами и инструменты сборки, чтобы использовать эти папки и файлы.