打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
编写S

环境:matlab2012b, windows8.1 x64,vs2010

目的:编写S-Function,创建Simulink模型并生成C++代码,编译生成可调用的动态库dll

操作步骤

·        编写S-Function

Ø 寻找一个S-Function模板

(1) 打开matlab主窗口,命令行中输入sfundemos

(2) 会弹出一个S-Function Examples的窗口,选择C++,选择C++ Objects

(3) 双击sfun_counter_cpp.cpp打开matlab编辑器

(4) 将代码copy一份并保存为add_my.cpp至自己的工作空间中,如E:\Workspace\MatlabWorkSpace\add\

Ø 修改为自己的S-Function 具体可参考相关S-Function C++编写方法,附个人测试例子:

  1. *******************************************************************  
  2. // **** To build this mex function use: mex add.cpp ****  
  3. // *******************************************************************  
  4.    
  5. #define S_FUNCTION_LEVEL 2  
  6. #define S_FUNCTION_NAME  add_my  
  7.    
  8. // Need to include simstruc.h for the definition of the SimStruct and  
  9. // its associated macro definitions.  
  10. #include "simstruc.h"  
  11.    
  12. //define self class  
  13. class Adder{  
  14.     double count;  
  15. public:  
  16.     Adder()  
  17.     {  
  18.         count = 0;  
  19.     }  
  20.       
  21.     double getSum(double a, double b)  
  22.     {  
  23.         count = a + b;  
  24.         return count;  
  25.     }  
  26.       
  27.     void setSum(double c)  
  28.     {  
  29.         count = c;  
  30.     }  
  31. };  
  32.    
  33. #define IS_PARAM_DOUBLE(pVal) (mxIsNumeric(pVal) && !mxIsLogical(pVal) &&\  
  34. !mxIsEmpty(pVal) && !mxIsSparse(pVal) && !mxIsComplex(pVal) && mxIsDouble(pVal))  
  35.    
  36. // Function: mdlInitializeSizes ===============================================  
  37. // Abstract:  
  38. //    The sizes information is used by Simulink to determine the S-function  
  39. //    block's characteristics (number of inputs, outputs, states, etc.).  
  40. static void mdlInitializeSizes(SimStruct *S)  
  41. {  
  42.     ssSetNumSFcnParams(S, 0);  
  43.    
  44.     // Parameter mismatch will be reported by Simulink  
  45.     if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {  
  46.         return;  
  47.     }  
  48.    
  49.     // Specify I/O  
  50.     if (!ssSetNumInputPorts(S, 1)) return;  
  51.     ssSetInputPortWidth(S, 0, DYNAMICALLY_SIZED);  
  52.     ssSetInputPortDirectFeedThrough(S, 0, 1);  
  53.     if (!ssSetNumOutputPorts(S,1)) return;  
  54.     ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED);  
  55.    
  56.     ssSetNumSampleTimes(S, 1);  
  57.    
  58.     // Reserve place for C++ object  
  59.     ssSetNumPWork(S, 1);  
  60.    
  61.     ssSetSimStateCompliance(S, USE_CUSTOM_SIM_STATE);  
  62.    
  63.     ssSetOptions(S,  
  64.                  SS_OPTION_WORKS_WITH_CODE_REUSE |  
  65.                  SS_OPTION_EXCEPTION_FREE_CODE);  
  66.    
  67. }  
  68.    
  69.    
  70. // Function: mdlInitializeSampleTimes =========================================  
  71. // Abstract:  
  72. //   This function is used to specify the sample time(s) for your  
  73. //   S-function. You must register the same number of sample times as  
  74. //   specified in ssSetNumSampleTimes.  
  75. static void mdlInitializeSampleTimes(SimStruct *S)  
  76. {  
  77.     ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);  
  78.     ssSetOffsetTime(S, 0, 0.0);  
  79.     ssSetModelReferenceSampleTimeDefaultInheritance(S);   
  80. }  
  81.    
  82. // Function: mdlStart =======================================================  
  83. // Abstract:  
  84. //   This function is called once at start of model execution. If you  
  85. //   have states that should be initialized once, this is the place  
  86. //   to do it.  
  87. #define MDL_START  
  88. static void mdlStart(SimStruct *S)  
  89. {  
  90.     // Store new C++ object in the pointers vector  
  91.     Adder *da  = new Adder();  
  92.     ssGetPWork(S)[0] = da;  
  93. }  
  94.    
  95. // Function: mdlOutputs =======================================================  
  96. // Abstract:  
  97. //   In this function, you compute the outputs of your S-function  
  98. //   block.  
  99. static void mdlOutputs(SimStruct *S, int_T tid)  
  100. {  
  101.     // Retrieve C++ object from the pointers vector  
  102.     Adder *da = static_cast<Adder *>(ssGetPWork(S)[0]);  
  103.       
  104.     // Get data addresses of I/O  
  105.     InputRealPtrsType  u = ssGetInputPortRealSignalPtrs(S,0);  
  106.                real_T *y = ssGetOutputPortRealSignal(S, 0);  
  107.    
  108.     // Call AddTo method and return peak value  
  109.     y[0] = da->getSum(*u[0], *u[1]);  
  110. }  
  111.    
  112.    
  113. // Function: mdlTerminate =====================================================  
  114. // Abstract:  
  115. //   In this function, you should perform any actions that are necessary  
  116. //   at the termination of a simulation.  For example, if memory was  
  117. //   allocated in mdlStart, this is the place to free it.  
  118. static void mdlTerminate(SimStruct *S)  
  119. {  
  120.     // Retrieve and destroy C++ object  
  121.     Adder *da = static_cast<Adder *>(ssGetPWork(S)[0]);  
  122.     delete da;  
  123. }  
  124.    
  125.    
  126. // Required S-function trailer  
  127. #ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */  
  128. #include "simulink.c"      /* MEX-file interface mechanism */  
  129. #else  
  130. #include "cg_sfun.h"       /* Code generation registration function */  
  131. #endif  


Ø 编译

(1) 在命令行输入mex –setup,选择需要的编译器(已选择则无需此操作)

(2) 选择自己需要的Visual Studio版本

(3) Matlab切换工作空间至E:\Workspace\MatlabWorkSpace\add\

(4) 在命令行输入 mex add_my.cpp,会编译成add_my.mexw64


·        创建simulink模型

Ø 在主面板点击Simulink Library,File->New->Model,会出现一个新的模型窗口,向此界面拖拽你的模型的元素,此处拖一个基本的加法模型 “a+b=c

(1) 首先拖一个s-function到此窗口,目录为Simulink->User-Defined Functions->S-Function

(2) 拖入a,b的输入模块,目录为Simulink->Commonly Used Blocks->Constant

(3) 拖入结果c显示模块,目录为Simulink->Sinks->Display

(4) 模块连线

(5) 关联界面到可执行文件,双击s-function,在s-functionname处填写自定义的s-function名称,此名称位于s-function文件add_my.cpp中,”#defineS_FUNCTION_NAME add_my”

(6) 填写输入参数,双击constant,Constantvalue输入要计算加法运算的a,b,以一个向量的方式输入,[100123.123]

Ø 保存模型,如add_model.slx

·        生成C++代码,生成可调用的动态库dll

Ø 配置编译参数

(1) 在菜单选择Code->C/C++ Code->Code GenerationOptions

(2) 选择Code Generation,目标文件grt.tlc,语言C++

(3) 选择Solver,开始时间0.0,结束时间1Solver options选择Type:Fixed-step,固定步长设为1(默认为1s)

Ø 生成C++代码

(1) 在菜单选择Code->C/C++ Code->Build Model编译生成的C++工程

(2) matlab主窗口会有相关打印log,有错误时会有错误窗口,根据提示修改即可

(3) 可打开VS工程调试一下生成的代码

Ø 生成可调用的动态库dll

(1) 通过分析生成的代码工程发现,工程里的一些文件并非是生成的代码,而是matlab下的代码,如rt_matrx.c,rt_main.clinux下可能为grt_main.c,具体根据前面生成代码选项的选择)等

(2) 新建一个VS动态库dll工程,把上述代码copy到新的工程下,修改rt_main.c文件,将mian()函数改名为mymain()

(3) 修改工程配置项,如包含的头文件目录,编译选项,连接的库等,具体可参考生成代码的工程

(4) 添加dll导出文件,编译通过,即可生成dll

  1. #ifndef ModelExport_H_  
  2. #define ModelExport_H_  
  3.   
  4. #ifdef _WIN32  
  5.     #if defined(ADD_MODEL_EXPORTS)  
  6.         #define ADD_MODEL_API __declspec(dllexport)  
  7.     #else  
  8.         #define ADD_MODEL_API __declspec(dllimport)  
  9.     #endif  
  10. #endif  
  11.   
  12. #ifdef _LINUX  
  13.     #ifdef MESSAGEBOARD_EXPORTS  
  14.         #define ADD_MODEL_API __attribute__(visibility("default"))  
  15.     #else  
  16.         #define ADD_MODEL_API  
  17.     #endif  
  18. #endif  
  19.   
  20. /* Function: main ============================================================= 
  21.  * 
  22.  * Abstract: 
  23.  *   Execute model on a generic target such as a workstation. 
  24.  */  
  25. ADD_MODEL_API int mymain(int argc, const char *argv[]);  
  26.   
  27.   
  28. #endif   

·        写测试例子,调用生成的dll

Ø 创建可执行程序工程,

在主函数文件中

#include “ModelExport.h”

int main(int argc, const char* argv[])

{

     Mymain(argc,argv);

     Return 0;

}

 

 

注:本测试验证只是调用dll可行性,具体如何动态向simulink模型传递参数,并从simulink模型取参数还需要进一步详细分析。

参考:”From Simulink model to DLLA tutorial”   by Roland Pfeiffer


2014-3-5更新:

获取输入输出参数的方法为:

1,首先在grt_shell.c中添加相关matlab API调用,以下为输出参数例子代码:

  1. SimStruct *S = add_model_M->childSfunctions[0];  
  2.         int outputNum = ssGetNumOutputPorts(S);  
  3.         printf("outputNum=%d\n",outputNum);  
  4.   
  5.         double *outputP = (double *)ssGetOutputPortRealSignal(S,0);  
  6.   
  7.         double outputValue = *outputP;  
  8.   
  9.         printf("outputNum=%f\n",outputValue);  

2,封装相关API,从dll导出即可

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
MATLAB中的S-Function的用法(C语言)
Matlab:手写C MEX S-Function,没那么难
VS2010中创建DLL图解
Simulink中使用已有的c代码进行仿真和代码生成
一步一步教你用VC和VB调用C DLL
静态链接库(Lib)和动态链接库(DLL)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服