【问题标题】:receive data as float in processing programming from serial port从串口接收数据作为处理编程中的浮点数
【发布时间】:2021-10-07 08:04:09
【问题描述】:

下面是arduino的代码:


typedef union{
  float number;
  uint8_t bytes[4];
} FLOATUNION_t;

FLOATUNION_t myValue;

float getFloat(){ 
 int cont = 0; 
 FLOATUNION_t f; 
 while (cont < 4 ){ 
 f.bytes[cont] = Serial.read() ; 
 cont = cont +1; 
 } 
 return f.number; 
}

在处理编程(java)方面有什么替代方法吗?

我完全需要一个从串口接收二进制数据的代码,并且我希望在处理编程中使用浮点类型的数据。

最初我通过 Simulink 中的串行发送块发送一些数据到处理编程,我正在使用 processing.serial 库,但我无法获取这些位并将它们转换为浮点或整数。

【问题讨论】:

    标签: java arduino processing simulink


    【解决方案1】:

    你需要:

    1. 将 Simulink 中的每个字节一次缓冲到处理中:串行的 buffer() / serialEvent() / readBytes(bytesFromSimulink) 在这里可以很好地协同工作
    2. 将字节打包成一个int(根据需要移动字节)并OR-ing它们: int intBits = bytesFromSimulink[3] &lt;&lt; 24 | bytesFromSimulink[2] &lt;&lt; 16 | bytesFromSimulink[1] &lt;&lt; 8 | bytesFromSimulink[0];
    3. 通过Float.intBitsToFloat()将int转换为float:floatFromSimulink = Float.intBitsToFloat( intBits );

    这里有一个基本草图来说明上述想法:

    import processing.serial.*;
    
    // how many bytes are expecting sent in one go
    final int SERIAL_BUFFER_SIZE = 4;
    // pre-allocate serial read buffer
    byte[] bytesFromSimulink = new byte[SERIAL_BUFFER_SIZE];
    // float from bytes
    float floatFromSimulink;
    
    // serial port reference
    final String PORT_NAME = "COM2"; 
    final int    BAUD_RATE = 115200;
    Serial simulinkPort;
    
    void setup(){
      size(300, 300);
      
      try{
        simulinkPort = new Serial(this, PORT_NAME, BAUD_RATE);
        // only fire serialEvent() when the right number of bytes has been buffered
        simulinkPort.buffer(SERIAL_BUFFER_SIZE);
      }catch(Exception e){
        println("error opening serial port(" + PORT_NAME + "): double check the port name, wiring and make sure the port isn't already open in another application");
        e.printStackTrace();
        exit();
      }
    }
    
    void draw(){
      background(0);
      // format bytes to hex and float to 2 decimal places
      text(String.format("hex: %s\nfloat: %.2f", hex(byteFromSimulink), floatFromSimulink), 
           10, 15); 
    }
    
    void serialEvent(Serial port) {
      port.readBytes(bytesFromSimulink);
      // pack bytes into a 32bit int (shifting each byte accordingly): double check the byte order (e.g. LSB / MSB)
      int intBits = bytesFromSimulink[3] << 24 | 
                    bytesFromSimulink[2] << 16 | 
                    bytesFromSimulink[1] << 8  | 
                    bytesFromSimulink[0];
      // convert int to to float
      floatFromSimulink = Float.intBitsToFloat( intBits );
    }
    
    // pretty-print byte array
    String hex(byte[] data){
      String output = "";
      for(byte singleByte : data){
        output += hex(singleByte) + ' ';
      }
      return output;
    }
    

    希望以上内容可以正常工作,但请记住它是未经测试的代码。 我认为有两件事可能会出错:

    1. 字节未按正确顺序到达。 (假设 Simulink 连续流式传输串行数据,但处理稍后开始,仅从第 2、3 或 4 个字节而不是第一个字节捕获数据:数据将被移位)。您可以尝试使用阻塞循环删除buffer()/serialEvent(),一次获取一个字节(例如if(simulinkPort.available() &gt;= 1) myNewByte = simulinkPort.read();)并手动将字节计数/打包到字节数组中。您也可以尝试呼叫/响应方法:例如Simulink 不会发送任何数据,直到它从 Processing 接收到单个字符(比如“A”),然后开始流式传输,因此 Processing 从一开始就准备好一次缓冲 4 个字节。
    2. 我不确定从 simulink 发送字节的顺序:上面我假设从右到左,但它只是交换索引的另一种方式:int intBits = byteFromSimulink[0] &lt;&lt; 24 | byteFromSimulink[1] &lt;&lt; 16 | byteFromSimulink[2] &lt;&lt; 8 | byteFromSimulink[3];

    Java/Processing 中的另一个问题是字节从 -127 到 127,因此在检查时需要屏蔽字节:println(myByte &amp; 0xFF);

    根据 g00se 在下面 cmets 中的建议,这里尝试使用 ByteBuffer 选项:

    import java.nio.ByteBuffer;
    import processing.serial.*;
    
    // how many bytes are expecting sent in one go
    final int SERIAL_BUFFER_SIZE = 4;
    // pre-allocate serial read buffer
    ByteBuffer bytesFromSimulink; 
    // float from bytes
    float floatFromSimulink;
    
    // serial port reference
    final String PORT_NAME = "COM2"; 
    final int    BAUD_RATE = 115200;
    Serial simulinkPort;
    
    void setup(){
      size(300, 300);
      
      try{
        simulinkPort = new Serial(this, PORT_NAME, BAUD_RATE);
        // only fire serialEvent() when the right number of bytes has been buffered
        simulinkPort.buffer(SERIAL_BUFFER_SIZE);
        bytesFromSimulink = ByteBuffer.allocate(SERIAL_BUFFER_SIZE);
      }catch(Exception e){
        println("error opening serial port(" + PORT_NAME + "): double check the port name, wiring and make sure the port isn't already open in another application");
        e.printStackTrace();
        exit();
      }
    }
    
    void draw(){
      background(0);
      // format bytes to hex and float to 2 decimal places
      text(String.format("hex: %s\nfloat: %.2f", hex(bytesFromSimulink), floatFromSimulink), 
           10, 15); 
    }
    
    void serialEvent(Serial port) {
      // pass new data to the byte buffer
      bytesFromSimulink.put(port.readBytes(SERIAL_BUFFER_SIZE));
      // set the index back to 0
      bytesFromSimulink.rewind();
      // read the first (rewinded) 4 bytes as a float
      floatFromSimulink = bytesFromSimulink.getFloat();
    }
    
    // pretty-print byte array
    String hex(ByteBuffer data){
      String output = "";
      for(int i = 0 ; i < data.limit(); i++){
        output += hex(data.get(i)) + ' ';
      }
      return output;
    }
    

    【讨论】:

    • 您可能会发现ByteBuffer 方法更方便一些。字节顺序也可以改变
    • 哦哦!好主意:java.nio 包有很多更快的实用程序,ByteBuffer 也有 getFloat(),听起来很适合。
    • 我已经尝试过您的代码,例如:Simulink 中的输入为 25,二进制格式的代码输出如下:11001000000000000000000000000 但 25 的二进制格式为 00000000000000000000000000011001
    • 上述问题已解决 我刚刚将 LittleEndian 更改为 BigEndian,现在位顺序为真。但我想将此值用于即将进行的计算,如何将此十六进制值更改为整数或浮点数?
    • 这是个好消息:看起来数据输入正常,只需要交换字节顺序。如果您使用byte[] 选项,只需交换上面提到的索引添加。如果您使用ByteBuffer 选项,请尝试将order() 设置为正确的字节序类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多