项目场景:

想用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 对象,这里暂时先不赘述.

Logo

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

更多推荐