simulink调用C代码——C caller
项目场景:
想用simulink实现十进制数和IEEE754的转换,用搭模块的方式实现实在是麻烦。想着这个简单的功能可以让AI写个函数,嵌入到simulink里调用。正好simulink有现成的模块可以用C_Caller
解决方案:
一、把源文件和头文件放到simulink路径里,以下是两个文件的内容:
两个函数:
ieee754_convert是用来转换数据类型的,输入一个十进制数,按照IEEE754输出一个32位的数据.
split_32bit_to_bytes 把上面的32位数据,按照高中低拆分成四个字节的数据.
//源文件.c
# include "myHandCode754.h"
void split_32bit_to_bytes(uint32 data, uint8 bytes[4]) {
bytes[0] = (data >> 24) & 0xFF;
bytes[1] = (data >> 16) & 0xFF;
bytes[2] = (data >> 8) & 0xFF;
bytes[3] = data & 0xFF;
}
/* IEEE754 conversion for Simulink */
uint32 ieee754_convert(float num)
{
uint32 sign = 0;
uint32 exponent = 0;
uint32 mantissa = 0;
uint32 result = 0;
uint32 temp_int;
int temp;
int bitCount;
float frac;
if (num == 0.0f) {
return 0;
}
if (num < 0) {
sign = 1;
num = -num;
}
temp = (int)num;
if (temp > 0) {
bitCount = 0;
int tmp = temp;
while (tmp > 0) {
tmp >>= 1;
bitCount++;
}
exponent = bitCount - 1 + 127;
temp_int = temp & (~(1 << (bitCount - 1)));
if (23 - (bitCount - 1) >= 0)
mantissa = temp_int << (23 - (bitCount - 1));
else
mantissa = temp_int >> ((bitCount - 1) - 23);
frac = num - temp;
int fracBit = 22 - (bitCount - 1);
unsigned int fracMantissa = 0;
while (frac > 0 && fracBit >= 0) {
frac *= 2.0f;
if (frac >= 1.0f) {
fracMantissa |= (1 << fracBit);
frac -= 1.0f;
}
fracBit--;
}
mantissa |= fracMantissa;
} else {
frac = num;
int exponentVal = -1;
while (frac < 1.0f) {
frac *= 2.0f;
exponentVal--;
}
exponent = exponentVal + 127;
frac -= 1.0f;
unsigned int fracMantissa = 0;
int fracBit = 22;
while (frac > 0 && fracBit >= 0) {
frac *= 2.0f;
if (frac >= 1.0f) {
fracMantissa |= (1 << fracBit);
frac -= 1.0f;
}
fracBit--;
}
mantissa = fracMantissa;
}
result = (sign << 31) | (exponent << 23) | mantissa;
return result;
}
#ifndef MYHANDCODE754_H
#define MYHANDCODE754_H
typedef signed char int8;
typedef unsigned char uint8;
typedef short int16;
typedef unsigned short uint16;
typedef int int32;
typedef unsigned int uint32;
unsigned int ieee754_convert(float num);
void split_32bit_to_bytes(uint32 data, uint8 bytes[4]) ;
#endif
二.simulink的配置
在配置里,把源文件加进去,点击"基于源文件自动填充",simulink会根据源文件里添加的头文件自动解析到模型配置里.然后点击"应用".

三.C_Caller模块
在simulink里添加C_Caller模块.双击模块里刷新的按钮,下拉框里会出现C里定义的函数,选择要用的,就可以在simulink里调用了!

---------------------------------------------------------------------------------------------------------------------------
附:
关于C_Caller传递指针,指针又是输入,又是输出?
关于 函数 void split_32bit_to_bytes(uint32 data, uint8 bytes[4]) ; 是用来拆分高中低位用的,我想他的输出直接是一个大小为4的数组.所以通过函数的参数(指针)来修改数组内容.
在 C 语言中,函数的参数如果声明为数组形式,实际上会被编译器隐式地转换为指针。
也就是说:
void split_32bit_to_bytes(uint32 data, uint8 bytes[4])
完全等价于:
void split_32bit_to_bytes(uint32 data, uint8 *bytes)
而C_Caller在 分析函数原型时,看到 bytes 是一个非 const 指针,就会默认它既可能读取输入数据(作为输入),也可能修改数据(作为输出)。所以生成了一个 In/Out 端口。
实际上代码只写不读 bytes 的内容,但 C Caller 无法从函数体推断出这一点——它只看原型。所以把 split_32bit_to_bytes 加到simulink里后,长这样:

指针bytes即使输出,也是输入.
如何告诉 C Caller bytes 只是输出?
要解决这个问题,只要在 C Caller 模块的端口配置表中,手动将 bytes 参数的 Direction 从 In/Out 改为 Output。这样它就会变成一个纯粹的输出端口,不再要求你给它提供输入信号。


C_Caller模块还可以传递结构体,方法大同小异了,但是要在在MATLAB 中定义对应同名的 Bus 对象,这里暂时先不赘述.

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)