从零开始simulink自定义代码生成----自定义硬件驱动库文件(3)

news2024/9/23 11:16:25

文章目录

    • 前言
    • C mex文件
      • mdlInitializeSizes
      • mdlInitializeSampleTimes
      • mdlOutputs
      • mdlTerminate
      • mdlRTW
      • c文件结尾
      • 编译c文件
    • tlc文件
      • Start函数
      • Outputs函数
      • 模型及生成的代码
    • 总结

前言

在很早的时候,做过一些Simulink自定义硬件驱动库的相关探索,但是后面没有继续更新下去了。现在有空打算再重新整理一下。本文接着之前的那篇文章继续编写DO的C mex函数和tlc文件

C mex文件

首先配置s-function名称和level


#define S_FUNCTION_NAME  s12xep_dio_dout
#define S_FUNCTION_LEVEL 2

该名称需要与之前设计界面时填入的名称保持一致

level配置为2,可以扩展的功能更多。

必须要包含simstruc.h头文件,以调用API函数及结构

/*
 * Need to include simstruc.h for the definition of the SimStruct and
 * its associated macro definitions.
 */
#include "simstruc.h" 

定义参数枚举及获取参数的宏定义

/* 
 *  DIOPORT_GROUP    - Port Group A/B 
 *  BIT_NUM          - Bit Num for Control
 */

enum {
    DIOPORT_GROUP=0, 
    BIT_NUM, 
    N_PARAMS
};

#define DIOPORT(S)          (mxGetScalar(ssGetSFcnParam(S, DIOPORT_GROUP)))
#define BITARRAY_ARG(S)     (            ssGetSFcnParam(S, BIT_NUM))


这个宏定义和s-function中的参数对应,用来获取参数值

ssGetSFcnParam 获取指向控件中参数的指针, mxGetScalar获取指针指向地址的数值

mdlInitializeSizes

设置或获取输入和输出端口的数量、宽度以及一些其他信息


/* Function: mdlInitializeSizes ===============================================
 * Abstract:
 *   Initialize the sizes array
 */
static void mdlInitializeSizes(SimStruct *S)
{
    int nBits;
    
    /* Set and Check parameter count  */
    ssSetNumSFcnParams(S, N_PARAMS);
    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) return;
    ssSetSFcnParamNotTunable(S, 0);//设置模块参数值在仿真过程中不可变
    ssSetSFcnParamNotTunable(S, 1);//设置模块参数值在仿真过程中不可变

    nBits  = mxGetNumberOfElements(BITNUM(S));//获取对象中元素个数

    /* Single input port of width equal to nBits */
    if (!ssSetNumInputPorts( S, 1)) return;//设置输入端口个数为1
    if (!ssSetNumOutputPorts(S, 1)) return;//设置输出端口个数为1
    

      
         ssSetInputPortWidth(    S, 0, nBits);
         ssSetInputPortDataType( S, 0, SS_BOOLEAN);
         ssSetOutputPortWidth(   S, 0, nBits);
         ssSetOutputPortDataType(S, 0, SS_BOOLEAN);
  
    
    ssSetInputPortRequiredContiguous(S, 0, 1);//设置输入端口号为0的端口输入值必须为连续
    ssSetInputPortDirectFeedThrough( S, 0, 1);//设置输入端口直接馈通状态
    /* No output port of width equal to nBits */
    
    /* sample times */
    ssSetNumSampleTimes(S, 1 );
    //其中numSampleTimes > 0。这告诉Simulink你的s函数有基于块的样本时间。
    //Simulink调用mdlInitializeSampleTimes,它反过来设置示例时间。
    /* options */
    ssSetOptions(S, (SS_OPTION_EXCEPTION_FREE_CODE |
                     SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME));
    //SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME 用于禁止S-Function块继承常数样例时间。
} /* end mdlInitializeSizes */


使用ssSetNumSFcnParams函数设置参数个数

使用ssGetNumSFcnParams获取参数个数,与界面中设置的参数个数校验

使用ssSetNumInputPorts函数设置输入端口个数

使用ssSetNumOutputPorts设置输出端口个数,0表示第一个端口

使用ssSetInputPortWidth设置输入端口的宽度,0表示第一个端口

使用ssSetInputPortDataType设置输入端口的数据类型,输出同理

使用ssSetNumSampleTimes设置采样时间个数,具体采样时间在后面配置

mdlInitializeSampleTimes

设置采样时间

/* Function: mdlInitializeSampleTimes =========================================
 * Abstract:
 *    Initialize the sample times array.
 */
static void mdlInitializeSampleTimes(SimStruct *S)
{
    ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);//引用模型的采样时间
    ssSetOffsetTime(S, 0, 0.0);
    
} /* end mdlInitializeSampleTimes */

mdlOutputs

此处没有添加代码

/* Function: mdlOutputs =======================================================
 * Abstract:
 *   Compute the outputs of the S-function.
 */
static void mdlOutputs(SimStruct *S, int_T tid)
{

} /* end mdlOutputs */


mdlTerminate

此处没有添加代码


/* Function: mdlTerminate =====================================================
 * Abstract:
 *    Called when the simulation is terminated.
 */
static void mdlTerminate(SimStruct *S)
{
} /* end mdlTerminate */


mdlRTW

在函数 mdlRTW 中设置模块参数,模块 tlc描述文件通过获取模块参数值来生成不同的模块代码


#define MDL_RTW
static void mdlRTW(SimStruct *S)
{
    uint8_T   dioPort     = (uint8_T) DIOPORT(S);
    uint16_T *bits        = (uint16_T *) mxGetData(BITNUM(S));

    /* Write out parameters for this block.*/
    if (!ssWriteRTWParamSettings(S, 2, 
                                 SSWRITE_VALUE_DTYPE_NUM,"DIOPort",
                                 &dioPort,DTINFO(SS_UINT8, COMPLEX_NO),                              
                                 
                                 SSWRITE_VALUE_DTYPE_VECT, "Bits",
                                 bits,
                                 mxGetNumberOfElements(BITNUM(S)),
                                 DTINFO(SS_UINT16, COMPLEX_NO)
                                 )) {
        return; /* An error occurred which will be reported by SL */
    }
}

ssWriteRTWParamSettings函数的用法如下:

int_T ssWriteRTWParameters(SimStruct *S, int_T nParams, int_T 
paramType, const char_T *paramName, const char_T *stringInfo, 
...)

nParams表示需要传递的参数个数,paramType表示参数类型,paramName表示参数名称,stringInfo一般省略。

此处通过RTW传递数据给TLC,一个传递两个参数,第一个数据为Uint8类型的数值,表示PORT A/B的索引,注意此处传递的为地址

第二个数据为bit位置,传递的是数据向量,有三个参数,第一个参数为首地址,第二个参数为长度,第三个参数为数据类型

具体的paramType参数类型见下表:



c文件结尾

/*==============================================*
* Enforce use of inlined S-function             * 
* (e.g. must have TLC file s12xep_dio_dout.tlc) *
*===============================================*/

#ifdef    MATLAB_MEX_FILE  /* Is this file being compiled as a MEX-file?    */
# include "simulink.c"     /* MEX-file interface mechanism                  */
#else                      /* Prevent usage by RTW if TLC file is not found */
# error "Attempted use non-inlined S-function s12xep_dio_dout.c"
#endif

结尾必须要加入该段,mex命令编译时,MATLAB_MEX_FILE自动被定义

编译c文件

编写好c文件后,使用mex命令编译c文件,可以命令行,也可以做成m脚本

mex s12xep_dio_dout.c


成功之后会生成.mexw64文件

tlc文件

tlc文件主要用来自定义生成的代码

%implements  s12xep_dio_dout "C"

使用implements指定TLC语言类型,此处设置为C语言

%include "driver_utils.tlc"

该TLC文件中包含了一些公用的文件

Start函数

%% Function: Start ==========================================================
%%
%% Purpose:
%%      Port A/B Digital Input initialization code.
%%
%function Start(block, system) Output
 
    /* S-Function "s12xep_dio_dout" initialization Block: %<Name> */
    %%
    %% Select DIO Port A or Port B and enable the selected Bits   
    %assign nPars       = SIZE(SFcnParamSettings.Bits,1)
    %assign port = getPort(SFcnParamSettings.DIOPort)
    %assign portId = CAST("Number", SFcnParamSettings.DIOPort)
    %assign nextChannel = 0 
    %% 

    %if ISEQUAL(portId,1)
          %% Configure Pins 0-3 of PORTA as outputs.
          %assign ddr = "DDRA"      
    %else
          %assign ddr = "DDRB"        
    %endif

      %foreach idx=nPars
        %assign bitIdx = CAST("Number",SFcnParamSettings.Bits[idx])
        %<ddr> =  %<ddr>  |  (0x1 << %<bitIdx>);  /* Select bit to be output */
        %<port> = %<port> | (0x1 << %<bitIdx>); /* Initial state */     
        %assign nextChannel = nextChannel+1
      %endforeach
 
  
%endfunction

通过SIZE函数获取bit个数,此处只可能为1

通过getPort函数获取PORT名称,此处为PORTA或PORTB

通过CAST函数获取对应PORT参数中的Number,应该是从1开始的。

通过DDRA/B对应bit设置为1确定输出方向,通过PORTA/B配置输出电平高低,此处默认高电平

Outputs函数

%% Function: Outputs ==========================================================
%%
%% Purpose:
%%      Code generation rules for mdlOutputs function.
%%
%function Outputs(block, system) Output
  
    /* S-Function "s12xep_dio_dout" Block: %<Name> */

    %assign port        = getPort(SFcnParamSettings.DIOPort)
    %assign nPars       = SIZE(SFcnParamSettings.Bits, 1)
    %assign nextChannel = 0 
    %%
   
      %foreach idx=nPars
        %assign u      = LibBlockInputSignal(0, "", "", %<nextChannel>)
        %assign bitIdx = CAST("Number",SFcnParamSettings.Bits[idx])
        %<port> = (%<port> & ~(1 << %<bitIdx>)) | ((%<u>) << %<bitIdx>); /* Clear the bit and set it to the input val */
        %assign nextChannel = nextChannel+1
    %endforeach

 
%% 
%endfunction

通过LibBlockInputSignal获取输入参数的值,然后对对应的bit进行set

模型及生成的代码

增加一个DO模块,实际放到1000ms task中运行,关于task的建立后面再讲

初始化:



  /* S-Function "s12xep_dio_dout" initialization Block: <S1>/DO1 */
  DDRB = DDRB | (0x1 << 1);            /* Select bit to be output */
  PORTB = PORTB | (0x1 << 1);          /* Initial state */

实际运行函数:


void
 task_1000ms(void)
{
  /* Output and update for function-call system: '<Root>/Function-Call Subsystem' */

  /* Delay: '<S1>/Delay' */
  LED_value = tsk_test_DW.Delay_DSTATE;

  /* S-Function (s12xep_dio_dout): '<S1>/DO' */

  /* S-Function "s12xep_dio_dout" Block: <S1>/DO */
  PORTB = (PORTB & ~(1 << 1)) | ((LED_value) << 1);
                                 /* Clear the bit and set it to the input val */


  /* Update for Delay: '<S1>/Delay' incorporates:
   *  Logic: '<S1>/Logical Operator'
   */
  tsk_test_DW.Delay_DSTATE = !LED_value;
}

总结

以上,一个简单的自定义DO输出硬件驱动库就完成了。后面有空会更新其他模块。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/732499.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

惊喜!Alibaba架构师终于发布“微服务架构与实践”文档

前言&#xff1a; 对于微服务架构的概念&#xff0c;相信大家应该都不陌生&#xff0c;无论使用 Apache Dubbo、还是 Spring Cloud&#xff0c;都可以去尝试微服务&#xff0c;把复杂而庞大的业务系统拆分成一些更小粒度且独立部署的 Rest 服务。 但是这个过程&#xff0c;具…

单表查询练习

查看表的字符集编码 show create table tbname; 查看系统默认字符集 SHOW VARIABLES LIKE character_set_database; 显示所有可用的字符集 SHOW CHARACTER SET; 修改系统默认字符集 ①在 /etc/my.cnf 文件中的 [mysqld] 下添加&#xff1a; ②重启数据服务 systemctl re…

Linux:PXE网络装机

要实现需要开启以下服务 dhcp --- 开机没有u盘或光盘的引导电脑会去寻找网络中的引导 tftp --- 用于引导系统 ftp&& http --- 制作yum仓库让引导的系统去ftp或者http上找rpm包 1.ftp&& http yum仓库搭建 Linux&#xff1a;YUM仓库服务_鲍海超-GNUBHC…

Mycat【Mycat安全设置(SQL拦截白名单、SQL拦截黑名单、Mycat-web安装 )】(九)-全面详解(学习总结---从入门到深化)

目录 Mycat安全设置_user标签权限控制 Mycat安全设置_privileges标签权限控制 Mycat安全设置_SQL拦截白名单 Mycat安全设置_SQL拦截黑名单 Mycat性能监控_Mycat-web安装 Mycat性能优化 Mycat实施指南 Mycat安全设置_user标签权限控制 目前 Mycat 对于中间件的连接控制并…

Mac矢量绘图工具 Sketch

Sketch是一款适用于 UI/UX 设计、网页设计、图标制作等领域的矢量绘图软件&#xff0c; 其主要特点如下&#xff1a; 1. 简单易用的界面设计&#xff1a;Sketch 的用户界面简洁明了&#xff0c;使得用户可以轻松上手操作&#xff0c;不需要复杂的学习过程。 2. 强大的矢量绘图功…

Lua快速入门笔记

文章目录 Lua快速入门笔记前言1、Lua概述2、Lua环境安装3、快速体验Lua编程4、数据类型5、变量6、循环7、流程控制8、函数9、运算符10、字符串11、数组12、迭代器13、表14、模块与包15、元表16、协同程序 Lua快速入门笔记 前言 本文是笔者参考菜鸟教程对Lua的一个快速入门学习&…

2023-07-08:RabbitMQ如何做到消息不丢失?

2023-07-08&#xff1a;RabbitMQ如何做到消息不丢失&#xff1f; 答案2023-07-08&#xff1a; 1.持久化 发送消息时设置delivery_mode属性为2&#xff0c;使消息被持久化保存到磁盘&#xff0c;即使RabbitMQ服务器宕机也能保证消息不丢失。同时&#xff0c;创建队列时设置du…

vue开发:Vue的状态管理 - Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 我个人的理解是&#xff0c;如果有一些公共的数据需要在多个组件中共享或者某一个状态的改变会影响多个组件&a…

基础之linux常用命令精华

目录 第一章.shell 1.1查看内部命令 1.2外部命令存放于 echo $PATH 一个一个找&#xff0c;找到为止&#xff0c;找不到就报无命令 第二章.linux常用命令 2.1.编辑linux命令行的辅助操作 2.2命令帮助help和--help&#xff0c;man手册使用 2.3.目录和文件的管理命令 2.…

消失的她-InsCode Stable Diffusion 美图活动一期

一、 Stable Diffusion 模型在线使用地址&#xff1a; https://inscode.csdn.net/inscode/Stable-Diffusion 二、模型相关版本和参数配置&#xff1a; Model: Cute_Animals Version: v1.2.0 Size: 512x512 Model hash: 57bd734213 Steps: 20 Sampler: Heun CFG scale: 7 三、图…

操作系统中的线程进程和同步异步和并发并行

目录 一、进程和线程1.1 进程1.2 线程1.3 实现多任务的方法1.3.1 使用多进程实现多任务1.3.2 使用多线程(单个进程包含多个线程)实现多任务1.3.3 使用多进程多进程实现多任务 1.4 进程和线程的比较1.5 Java的多线程模型的应用 二、同步和异步2.1 同步2.2 异步 三、并发与并行3.…

QTday2

点击登录&#xff0c;登陆成功&#xff0c;跳转到新的界面 主函数 #include "widget.h" #include "second.h" #include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();Second s;QObject::connect…

MySQL数据库介绍流程(最新mysql)

版本介绍 第一步&#xff1a;下载MySQL数据库 1、下载地址&#xff1a;http://dev,mysql.com/downloads/windows/installer/8.0html 2、就是直接搜索&#xff1a;mysql官方 msyql官方网站 这里就安装成功 第二步&#xff1a;这么启动和停止mysql 第三步&#xff1a;这么快捷停…

B - Get an Even String

Get an Even String - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题意&#xff1a;题目要使字符串变成偶字符串&#xff0c;对于每一个奇数i都和后面i1的位置字符相同。求给定字符串最少去掉几个字符能得到偶字符串。 解题思路&#xff1a;贪心&#xff0c;找每次第一对出现…

黑客(网安)自学

建议一&#xff1a;黑客七个等级 黑客&#xff0c;对很多人来说充满诱惑力。很多人可以发现这门领域如同任何一门领域&#xff0c;越深入越敬畏&#xff0c;知识如海洋&#xff0c;黑客也存在一些等级&#xff0c;参考知道创宇 CEO ic&#xff08;世界顶级黑客团队 0x557 成员…

5、Task_stat() always report used == size他两总是相等

1、今天想查看一下任务的堆栈使用情况&#xff0c;按官方手册加入下面调试下面代码 Task_Stat statbuf; /* declear buffer */ Task_stat(Task_self(),&statbuf); /*call func to get status */ If(statbuf.used > (statbuf.stackSize * 9 / 10)) { System_printf(“…

Python——— 函数大全

&#xff08;一&#xff09;初识函数 函数是可重用的程序代码块。 函数的作用&#xff0c;不仅可以实现代码的复用&#xff0c;更能实现代码的一致性。一致性指的是&#xff0c;只要修改函数的 代码&#xff0c;则所有调用该函数的地方都能得到体现。 在编写函数时&#xff0…

LabVIEW开发空气动力学实验室的采集和控制系统

LabVIEW开发空气动力学实验室的采集和控制系统 在航空航天模拟设施中&#xff0c;通常的做法是准备一种针对当前正在进行的实验的数据采集和控制软件。该软件通常是根据当前要求编辑的更通用程序的修订版&#xff0c;或者可能是专门为该测试编写的自定义程序&#xff0c;具体取…

iview-admin前后台分离管理系统

加油&#xff0c;新时代打工人&#xff01; layui已淘汰&#xff0c;下面介绍vue管理后台系统&#xff0c;当然市场上不止下面一种框架。 layuimini后台管理系统的简单使用 iview-admin是iview生态圈的成员之一。是一套基于 Vue.js&#xff0c;搭配ivew UI(https://www.iviewu…

【LeetCode周赛】2022上半年题目精选集——二分

文章目录 2141. 同时运行 N 台电脑的最长时间解法1——二分答案补充&#xff1a;求一个int数组的和&#xff0c;但数组和会超int 解法2——贪心解法 2251. 花期内花的数目解法1——二分答案代码1——朴素二分写法代码2——精简二分⭐ 解法2——差分⭐⭐⭐ 2258. 逃离火灾解法1—…