Этот пример показывает, как сгенерировать код С из модели алгоритма управления и интегрировать тот код с существующим кодом внешнего приложения. В законченном приложении, которое состоит из трех модулей, модуль алгоритма должен обмениваться данными с другими модулями через глобальные переменные. В примере вы конфигурируете сгенерированный код, чтобы взаимодействовать с существующими внешними переменными, напомнить внешний код по внешности и организацию, и соответствовать определенным требованиям кодирования.
Установите свою текущую папку на перезаписываемое местоположение.
Скопируйте скрипт 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
выберите View> 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. В модели выберите Code> C/C ++ Code> Configure Model in Code Perspective.
Под блок-схемой при Отображениях Кода> Значения по умолчанию Данных, для Внутренней строки данных, в столбце Класса памяти выбирают 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','ex_my_code_template.cgt'))
Этот новый шаблон соответствует более тесно организации внешних файлов. Например, шаблон организует подобные построения кода в именованные разделы (разграниченный комментариями) и, наверху шаблона, указывает только минимальную информацию о каждом сгенерированном файле.
В модели выберите Configuration Parameters> Code Generation> Templates.
Под шаблонами Кода и шаблонами Данных, набор эти четыре параметра конфигурации к ex_my_code_template.cgt
.
Также, чтобы скопировать файл и установить параметры, в командной строке, используют эти команды.
copyfile(fullfile(matlabroot,'examples','ecoder','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
. Вы должны системы управления файла конфигурации и инструменты сборки, чтобы использовать эти папки и файлы.