В этом примере показано, как сгенерировать код С из модели алгоритма управления и интегрировать тот код с существующим кодом внешнего приложения. В законченном приложении, которое состоит из трех модулей, модуль алгоритма должен обмениваться данными с другими модулями через глобальные переменные. В примере вы конфигурируете сгенерированный код, чтобы взаимодействовать с существующими внешними переменными, напомнить внешний код по внешности и организацию, и соответствовать определенным требованиям кодирования.
Установите свою текущую папку на перезаписываемое местоположение.
Скопируйте скрипт 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
. Этот код приложения представляет встраиваемую систему тривиальным алгоритмом планирования (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
. 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
папка является заполнителем для сгенерированного кода. ex_ext_ctrl_alg
модуль должен выполнить управление ПИДом на отфильтрованных измерениях потока и измерениях температуры. Позже, вы исследуете требования на этот код, которые основаны на коде в других модулях.
В ex_ext_outputs_proc
папка, смотрите ex_ext_outputs_proc.c
. Этот модуль читает выходные сигналы ПИДа глобальных переменных под названием CONTR_SIG_FLOW
и CONTR_SIG_TEMP
. ex_ext_ctrl_alg
модуль (сгенерированный код) должен задать эти переменные. 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 выпадающий список на Code
.
Выберите строки, которые соответствуют этим двум Inport блокам.
Для любой строки, Класса памяти набора к ImportFromFile
и заголовочный файл к ex_ext_proc_inputs.h
. С классом памяти ImportFromFile
, каждый Inport блок появляется в сгенерированном коде как глобальная переменная. Однако сгенерированный код не задает переменную, вместо этого включая (#include
) объявление переменной от ex_ext_proc_inputs.h
.
Для строк, которые соответствуют блокам Выходного порта, установите:
Класс памяти к 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, необходимо создать объект параметра, такой как Simulink.Parameter
. Можно использовать Model Data Editor, чтобы создать объекты параметра.
Выберите вкладку Parameters и установите представление Change на Design
.
В модели блок Constant выбор, пометил Flow Setpt
.
В Model Data Editor, установленном Значении к PARAM_setpoint_flow
.
Рядом с PARAM_setpoint_flow
, кликните по кнопке действий (с тремя вертикальными точками) и выберите Create.
В диалоговом окне Create New Data, установленном Значении к Simulink.Parameter(3)
.
Установите местоположение на Model Workspace
и нажмите Create.
В 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
Во внешнем коде внутренние данные, которые не участвуют в интерфейсах модуля, таких как данные состояния и локальные переменные в функциях, соответствуют схемам именования. В модели сконфигурируйте внутренние данные, которые, кажется, в сгенерированном коде подражают этим схемам именования.
В диалоговом окне модели Configuration Parameters смотрите Генерацию кода> панель Идентификаторов. Когда вы задаете значения для схем именования под управлением форматом Идентификатора:
$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'))
Этот новый шаблон соответствует более тесно организации внешних файлов. Например, шаблон организует подобные построения кода в именованные разделы (разграниченный комментариями) и, наверху шаблона, указывает только минимальную информацию о каждом сгенерированном файле.
В модели выберите Configuration Parameters> Code Generation> Templates.
Под шаблонами Кода и шаблонами Данных, набор эти четыре параметра конфигурации к 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
функционируйте, выберите Configuration Parameters> код Generate только и очиститесь, Параметры конфигурации> Генерируют пример основная программа.
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
. Вы должны системы управления файла конфигурации и инструменты сборки, чтобы использовать эти папки и файлы.