前段时间完成了一次生成动态链接库并使用,没有做记录,结果又花了两天重新探索过程,及时记录非常有必要。
使用软件版本:matlab R2017a&R2017b , vs 2013 & vs2015。
完整的测试文件我已经发布至这里,可以免积分下载(该文件使用了R2017a)。
1.新建simulink模型,如下图所示。
2.配置仿真条件。
3 . 编译生成C代码
4. 编译生成动态链接库文件
上一级目录(与你的simulink模型同级的目录)得到
这里还有另外一种方法就是用nmake 编译其中的matlab_sourcecode.mk(makefile文件),这种方法会生成完整的*.exe可执行文件,找到其中的上图三个文件拷贝出来,一样可以使用。
5.使用动态链接库文件。
然后就可以在新的程序当中引用动态链接库了,比如我重新在matlab中使用该动态链接库:
用c写S-function :testsfun.c,然后执行mex testsfun.c 编译一次,就可以使用了。
以下为原simulink模型与动态链接库运行的结果对比,可以看到两个完全一致。
遇到的问题:不知道为什么,我第一次新建的simulink文件生成的代码始终有问题,我查看了生成的文件,在生成文件类型和内部变量的命名上都会有差异。生成dll没有问题,但是在使用时,每次运行都会导致软甲崩溃,必须重启才能使用。下边将部分差别标出来。
7.引用动态链接库所使用的文件testsfun.c & rtwdemo.h
/* File : testsfun.c
* Abstract:
*
* A one integration-step delay and hold "memory" function.
*
* Syntax: [sys, x0] = sfunmem(t,x,u,flag)
*
* This file is designed to be used in a Simulink S-Function block.
* It performs a one integration-step delay and hold "memory" function.
* Thus, no matter how large or small the last time increment was in
* the integration process, this function will hold the input variable
* from the last integration step.
*
* Use this function with a clock as input to get the step-size at each
* step of a simulation.
*
* This function is similar to the built-in "Memory" block.
*
* Copyright 1990-2013 The MathWorks, Inc.
*/
#define S_FUNCTION_NAME testsfun
#define S_FUNCTION_LEVEL 2
#include <string.h>
#include "simstruc.h"
#include <windows.h>
#define GETSYMBOLADDR GetProcAddress
#define LOADLIB LoadLibrary
#define CLOSELIB FreeLibrary
#define U(element) (*uPtrs[element]) /* Pointer to Input Port0 */
#include "rtwdemo.h"
int32_T i;
void* handleLib;
void (*mdl_initialize)(boolean_T);
void (*mdl_step)(void);
void (*mdl_terminate)(void);
uint8_T (*sum_outptr);
ExternalInputs_test (*mdl_Uptr);
ExternalOutputs_test (*mdl_Yptr);
/*====================*
* S-function methods *
*====================*/
/* Function: mdlInitializeSizes ===============================================
* Abstract:
* Call mdlCheckParameters to verify that the parameters are okay,
* then setup sizes of the various vectors.
*/
static void mdlInitializeSizes(SimStruct *S)
{
ssSetNumSFcnParams(S, 0); /* Number of expected parameters */
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
return; /* Parameter mismatch will be reported by Simulink */
}
handleLib = LOADLIB("./matlab_sourcecode_win64.dll");
if (!handleLib) {
printf("Cannot open the specified shared library.\n");
return(-1);
}
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 0);
if (!ssSetNumInputPorts(S, 2)) return;
ssSetInputPortWidth (S, 0, 1);
ssSetInputPortWidth (S, 1, 1);
ssSetInputPortDirectFeedThrough(S, 0, 1);
if (!ssSetNumOutputPorts(S, 1)) return;
ssSetOutputPortWidth(S, 0, 1);
ssSetNumSampleTimes(S, 1);
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0);
ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE);
ssSetOptions(S,
SS_OPTION_WORKS_WITH_CODE_REUSE |
SS_OPTION_EXCEPTION_FREE_CODE |
SS_OPTION_USE_TLC_WITH_ACCELERATOR);
#if (defined(LCCDLL)||defined(BORLANDCDLL))
/* Exported symbols contain leading underscores when DLL is linked with LCC or BORLANDC */
mdl_initialize =(void(*)(boolean_T))GETSYMBOLADDR(handleLib , "_matlab_sourcecode_initialize");
mdl_step =(void(*)(void))GETSYMBOLADDR(handleLib , "_matlab_sourcecode_step");
// mdl_terminate =(void(*)(void))GETSYMBOLADDR(handleLib , "_matlab_sourcecode_terminate");
mdl_Uptr =(ExternalInputs_test*)GETSYMBOLADDR(handleLib , "_matlab_sourcecode_U");
mdl_Yptr =(ExternalOutputs_test*)GETSYMBOLADDR(handleLib , "_matlab_sourcecode_Y");
// sum_outptr =(uint8_T*)GETSYMBOLADDR(handleLib , "_sum_out");
#else
mdl_initialize =(void(*)(boolean_T))GETSYMBOLADDR(handleLib , "matlab_sourcecode_initialize");
mdl_step =(void(*)(void))GETSYMBOLADDR(handleLib , "matlab_sourcecode_step");
// mdl_terminate =(void(*)(void))GETSYMBOLADDR(handleLib , "matlab_sourcecode_terminate");
mdl_Uptr =(ExternalInputs_test*)GETSYMBOLADDR(handleLib , "matlab_sourcecode_U");
mdl_Yptr =(ExternalOutputs_test*)GETSYMBOLADDR(handleLib , "matlab_sourcecode_Y");
// sum_outptr =(uint8_T*)GETSYMBOLADDR(handleLib , "sum_out");
#endif
mdl_initialize(1);
}
/* Function: mdlInitializeSampleTimes =========================================
* Abstract:
* S-function is continuous, fixed in minor time steps.
*/
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME);
ssSetOffsetTime(S, 0, FIXED_IN_MINOR_STEP_OFFSET);
ssSetModelReferenceSampleTimeDefaultInheritance(S);
}
#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ========================================
* Abstract:
* The memory state is stored in the RWork vector, initialize it to zero
*/
static void mdlInitializeConditions(SimStruct *S)
{
// real_T *rwork = ssGetRWork(S);
// int_T i;
//
// for (i = 0; i < ssGetNumRWork(S); i++) {
// rwork[i] = 0.0;
// }
}
/* Function: mdlOutputs =======================================================
* Abstract:
*
* y = rwork
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
real_T *y = ssGetOutputPortRealSignal(S,0);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
const real_T *u1 = &U(0);
const real_T *u2 = &U(1);
// UNUSED_ARG(tid); /* not used in single tasking mode */
mdl_Uptr->shuru1 =*u1;
mdl_Uptr->shuru2 =*u2;
mdl_step();
*y = mdl_Yptr->Output;
}
#define MDL_UPDATE
/* Function: mdlUpdate ========================================================
* Abstract:
* This function is called once for every major integration time step.
* Discrete states are typically updated here, but this function is useful
* for performing any tasks that should only take place once per integration
* step.
*/
static void mdlUpdate(SimStruct *S, int_T tid)
{
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
real_T *rwork = ssGetRWork(S);
int_T i;
// real_T *y = ssGetOutputPortRealSignal(S,0);
// UNUSED_ARG(tid); /* not used in single tasking mode */
// mdl_step();
// *y =10;
}
/* Function: mdlTerminate =====================================================
* Abstract:
* No termination needed, but we are required to have this routine.
*/
static void mdlTerminate(SimStruct *S)
{
UNUSED_ARG(S); /* unused input argument */
// mdl_terminate();
}
#if defined(MATLAB_MEX_FILE)
#define MDL_RTW
/* Function: mdlRTW ===========================================================
* Abstract:
* It registers the name "InputAtLastUpdate" for the RWork vector.
*/
static void mdlRTW(SimStruct *S)
{
if (!ssWriteRTWWorkVect(S, "RWork", 1 /* nNames */,
"InputAtLastUpdate", ssGetNumRWork(S))) {
return;
}
/*
This registration of the symbol "InputAtLastUpdate" allows sfunmem.tlc to
call LibBlockRWork(InputAtLastUpdate,[...])
*/
}
#endif /* MDL_RTW */
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */
#include "simulink.c" /* MEX-file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
/* File: rtwdemo.h
*
* Abstract:
* Header file for example application program to be
* used with ERT shared library target demo rtwdemo_shrlib.mdl.
*
* Copyright 2006-2007 The MathWorks, Inc.
*/
#ifndef _APP_MAIN_HEADER_
#define _APP_MAIN_HEADER_
typedef struct {
real_T shuru1;
real_T shuru2;
} ExternalInputs_test;
typedef struct {
real_T Output;
} ExternalOutputs_test;
#endif /*_APP_MAIN_HEADER_*/
/*End of file */