MBD软件开发之结构体变量建模

结构体类型在C语言中的定义如下:

            struct mystruct_T{

                  uint8 a;

                  int16 b;

                  uint16 c;};

这里mystruct_T就是结构体类型。结构体类型是一种组合数据类型,不同于数组,结构体的元素是可以有不同数据类型的,上面的例子中a、b、c的数据类型各不相同。

我们可以像使用基本数据类型一样使用结构体类型去定义变量,使用结构体类型定义的变量是结构体变量,比如,

            mystruct_T mystruct_var;

那么mystruct_var就是一个结构体变量,可以通过如下结构体变量右侧加点来访问结构体变量中的元素,比如

            mystruct_var.a = 30

            或者 tmp = mystruct_var.c;

这样,我们就有了结构体类型mystruct_T和结构体变量mystruct_var

我们做一个假设,如果上述结构体里面的元素c不是一个单个元素,而是一个结构体变量,情况将会怎么样?比如,

            struct mystruct_T{

                                uint8 a;

                                int16 b; 

                                substruct_T c;};

结构体里面还套着一个结构体,于是我们就有了结构体嵌套。

我们在C语言中定义变量的时候,可以定义单个变量,也可以定义一个数组,比如int8 x[10],结构体类型同样也可以用于定义结构体数组,比如 mystruct_T mystruct_array[10]

这样,我们就有了结构体数组。

下面我们一起看看如何在模型里建模或者配置,让生成的C代码里出现结构体变量、结构体嵌套和结构体数组。开始介绍之前,请大家记住两点:

1)C代码中的结构体变量跟模型中的Bus信号相对应;

2)C代码中的结构体类型跟模型中的Bus对象相对应。

一.结构体变量的代码实现

有模型如下:

数据字典中有Bus对象myBus定义如下:

将Inport端口的数据类型设置为myBus,Inport的外观发生变化,变成环形。为控制结构体变量的变量名如我们所期望,在信号线上设置信号名x、y。然后在数据字典中分别定义信号对象x、y。将x、y的数据类型设置为myBus,如下图:

当然,x、y的存储类设置跟非结构体代码生成一样,这里分别设置为ImportedExtern和ExportedGlobal。

除此之外,还需要把BusCreator的输出数据类型设置为myBus,如果你没做这个设置,Embeded Coder会提醒你设置。

做好上述设置,以及代码生成的基本设置之后,Build模型,代码就有了,你会发现结构体类型myBus的定义如下:

            typedef struct {

                            real_T a;

                            real_T b;

                            real_T c;

  } myBus;

变量y的定义如下:myBus y;

变量x的声明如下:extern myBus x;  

二. 结构体嵌套的代码实现

在上述例子中的数据字典中再定义一个Bus对象subBus,如下图:

再将myBus中的元素c的数据类型改为subBus,模型做相应的调整如下:

Build模型,代码中myBus的定义如下:

typedef struct {

  real_T a;

  real_T b;

  subBus c;

} myBus;

其中subBus定义如下:

typedef struct {

  real_T u;

  real_T v;

} subBus;

数据字典中信号对象x和y的定义跟前面的例子一样,结构体变量x和y在代码中的定义也跟前面的例子一样,整个算法的实现函数如下:

            void nestStructModel_step(void)

            {

                 y.a = K * x.a;  

                 y.b = K * x.b;  

                y.c.u = K *x.c.u;  

                y.c.v = K *x.c.v;

              }

很显然,结构体嵌套,对应到模型中,就是Bus嵌套。

三.结构体数组的代码实现

前面提到:1)C代码中的结构体变量跟模型中的Bus信号是对应的;2)C代码中的结构体类型跟模型中的Bus对象相对应。

从前面结构体变量和结构体嵌套的两个例子,我们也可以很清楚的体会到这两点,所以,结构体数组,对应到模型中,自然也就是多维的Bus信号了。

对图中Inport端口的Data type设置为Bus: myBus,Port dimensions设置为2;数据字典中和信号x对应的信号对象x做同样的设置,即Datatype为Bus: myBus,Dimensions为2。Selector模块分别选中两维信号的第一维和第二维。两组信号经过运算之后,再次通过Bus Creator模块组合成Bus信号,再把两路Bus信号使用Vector Concatenate模块连成维数为2的Bus信号y。

信号对象x、y除了数据类型设置为Bus: myBus之外,Storage Class均设置为ExportedGlobal。

由此,就有了如下结构体类型的定义:

typedef struct {

  real_T a;

  real_T b;

  real_T c;

} myBus;

和结构体数组的定义:

myBus x[2];

myBus y[2];

或许你已经注意到几个增益模块的参数值被设置为k.a,k.b,k.c,没错,既然myBus作为结构体类型是一种组合数据类型,同样也可以使用这个myBus设置参数k的数据类型,只是,一旦参数对象k的数据类型被设置为myBus,那么参数的初始化就不像以前那么简单的,这个例子中,设置如下:

k.Value =struct(‘a’,2, ‘b’,3, ‘c’,4);

如果参数k的存储类设置为ConstVolatile,那么代码中参数k的定义如下:

const volatile myBus k = {

  2.0,

  3.0,

  4.0

} ;

四.For-Each和结构体数组的结合

上面的例子,Bus信号的维数为2,所以我们很轻松的使用了Selector模块,把两维数据分别取出来实现后续算法,而现实中,我们可能面临几十甚至上百维的Bus信号,而后续的处理算法,对于每一维来讲都是一致的,这种情况下怎么办?我们可以想象的见,代码中是可以通过一个For循环去实现的,模型当然也可以,这就是For-Each子系统。

双击上图中的For-Each子系统,得到下图:

这个模型中Inport和x、y信号对象的Dimensions为100。生成代码之后,除了x、y两个结构体数组的维数变成100之外,算法中有如下代码:

结合For-Each模块,让我们的结构体数组建模更为方便。

本想就此结束本篇,想到还会有人惦记另外一些结构体相关的话题,就再说一说。

五. 位域结构体的代码实现

Simulink参数对象和信号对象的存储类(Storage Class)里面都有BitField (Custom)选项,必须要说明的是,如果你的数据类型设置为boolean,并且存储类选择为BitField,是可以生成位域结构体变量的,只是,正如上一篇微文有网友留言所说,这样做没法指定结构体元素的顺序,当然也没有Bus与之对应。

如果我们想得到我们期望的结构体变量,比如:

typedefstruct

{

    unsignedchar a  :1;

    unsignedchar a1 :1;

    unsignedchar a2 :1;

    unsignedchar a3 :1;

    unsignedchar a4 :1;

    unsignedchar a5 :1;

    unsignedchar a6 :2;

}myBitFieldBus;

此结构体类型中,前6个元素各占1个bit,而第7个元素占2个bit。

模型如下:

显然,Inport端口的数据类型应该为myBitFieldBus,信号对象input也一样。

数据字典中定义了myBitFieldBus如下:

不难看出如下信息:

1)myBitFieldBus内的元素a,a1,a2,a3,a4,a5,均为boolean类型,a6为uint8;

2)Bus对象myBitFieldBus的Data scope为Imported,并且定义在头文件mybitfieldstruct.h文件中,也就是说,结构体类型myBitFieldBus不在这个模块中定义,为了能够生成代码,需要提供mybitfieldstruct.h文件。

做完上述设置之后,生成代码,如下:

默认最外层输出的结构体类型:

typedefstruct {

  boolean_T Out1;

  boolean_T Out2;

  boolean_T Out3;

  boolean_T Out4;

  boolean_T Out5;

  boolean_T Out6;

  uint8_T Out7;

} ExtY_bitfieldstruct_T;

位域结构体变量input的定义: 

myBitFieldBus input;

输出结构体变量的定义:

ExtY_bitfieldstruct_Tbitfieldstruct_Y;

模型算法的实现函数:

void bitfieldstruct_step(void)

{

  bitfieldstruct_Y.Out1 = input.a;

  bitfieldstruct_Y.Out2 = input.a1;

  bitfieldstruct_Y.Out3 = input.a2;

  bitfieldstruct_Y.Out4 = input.a3;

  bitfieldstruct_Y.Out5 = input.a4;

  bitfieldstruct_Y.Out6 = input.a5;

  bitfieldstruct_Y.Out7 = input.a6;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

电力电子空间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值