App Inventor 2 浮点数与字节转换教程

« 返回首页

概述

在串口通信、蓝牙通信中,经常需要将浮点数转换为字节发送,接收后再还原。App Inventor没有内置浮点数-字节转换,需要手动实现。

已有文档hex_binary.md 介绍了进制转换和位运算。本文聚焦浮点数与字节的转换。

IEEE 754浮点数格式

单精度(32位/4字节)

部分 位数 说明
符号位 1位 0=正,1=负
指数位 8位 偏移127
尾数位 23位 小数部分

转换示例

浮点数 3.14 的IEEE 754表示:
二进制: 0 10000000 10010001111010111000011
十六进制: 40 48 F5 C3
字节序(大端): [0x40, 0x48, 0xF5, 0xC3]

方案一:通过WebView用JavaScript转换(推荐)

JavaScript的 DataView 提供精确的浮点数-字节转换:

HTML页面

<!-- float_converter.html -->
<script>
setInterval(function() {
  var msg = window.AppInventor.getWebViewString();
  if (msg && msg !== "") {
    try {
      var data = JSON.parse(msg);
      if (data.cmd === "float2bytes") {
        var buf = new ArrayBuffer(4);
        var view = new DataView(buf);
        view.setFloat32(0, data.value, data.littleEndian || false);
        var bytes = [];
        for (var i = 0; i < 4; i++) bytes.push(view.getUint8(i));
        window.AppInventor.setWebViewString(JSON.stringify({result: bytes}));
      } else if (data.cmd === "bytes2float") {
        var buf = new ArrayBuffer(4);
        var view = new DataView(buf);
        for (var i = 0; i < data.bytes.length; i++) view.setUint8(i, data.bytes[i]);
        var value = view.getFloat32(0, data.littleEndian || false);
        window.AppInventor.setWebViewString(JSON.stringify({result: value}));
      } else if (data.cmd === "double2bytes") {
        var buf = new ArrayBuffer(8);
        var view = new DataView(buf);
        view.setFloat64(0, data.value, data.littleEndian || false);
        var bytes = [];
        for (var i = 0; i < 8; i++) bytes.push(view.getUint8(i));
        window.AppInventor.setWebViewString(JSON.stringify({result: bytes}));
      }
    } catch(e) {
      window.AppInventor.setWebViewString(JSON.stringify({error: e.message}));
    }
  }
}, 50);
</script>

App Inventor积木块

当 Screen1.初始化
  设 WebView_转换器.主页地址 = "file:///android_asset/float_converter.html"

' 浮点数转字节
定义 浮点数转字节(数值, 小端序) 返回 字节列表
  设 JSON = "{""cmd"":""float2bytes"",""value"":" & 数值 & ",""littleEndian"":" & 小端序 & "}"
  设 WebView_转换器.WebView字符串 = JSON
  ' 等待WebView回调

当 WebView_转换器.WebView字符串改变(值)
  设 结果 = 调用 文本.从JSON解析(值)
  如果 从字典 结果 获取 "result" ≠ 未定义
    设 字节列表 = 从字典 结果 获取 "result"
    标签_字节.文本 = 列表转文本(字节列表, ", ")

' 字节转浮点数
定义 字节转浮点数(字节列表, 小端序) 返回 数值
  设 JSON = "{""cmd"":""bytes2float"",""bytes"":[" & 列表转文本(字节列表, ",") & "],""littleEndian"":" & 小端序 & "}"
  设 WebView_转换器.WebView字符串 = JSON

方案二:纯积木块实现(近似)

对于精度要求不高的场景,可以用数学方法拆分:

定义 浮点数转近似字节(数值) 返回 字节列表
  ' 简化版:将浮点数拆为整数部分和小数部分
  ' 注意:这不是标准IEEE 754,是自定义简化协议
  
  设 整数部分 = 数学.向下取整(数学.绝对值(数值))
  设 小数部分 = 数值 - 整数部分
  
  ' 整数部分用2字节
  设 高字节 = 数学.向下取整(整数部分 / 256)
  设 低字节 = 整数部分 模 256
  
  ' 小数部分用2字节(乘以10000保留4位精度)
  设 小数整数 = 数学.向下取整(小数部分 * 10000)
  设 小数高字节 = 数学.向下取整(小数整数 / 256)
  设 小数低字节 = 小数整数 模 256
  
  ' 符号字节
  设 符号 = 如果 数值 < 0 则 1 否则 0
  
  返回 [符号, 高字节, 低字节, 小数高字节, 小数低字节]

定义 近似字节转浮点数(字节列表) 返回 数值
  设 符号 = 列表第1项(字节列表)
  设 整数部分 = 列表第2项(字节列表) * 256 + 列表第3项(字节列表)
  设 小数部分 = (列表第4项(字节列表) * 256 + 列表第5项(字节列表)) / 10000
  设 结果 = 整数部分 + 小数部分
  如果 符号 = 1
    设 结果 = -结果
  返回 结果

方案三:通过蓝牙/串口直接发送

大多数嵌入式系统使用简单的自定义协议而非IEEE 754:

发送温度值(2字节整数 × 10)

定义 发送温度(温度值)
  ' 温度值 × 10 保留1位小数,用2字节整数发送
  设 值 = 数学.向下取整(温度值 * 10)
  设 高字节 = 数学.向下取整(值 / 256)
  设 低字节 = 值 模 256
  设 发送数据 = 字符(高字节) & 字符(低字节)
  调用 蓝牙1.发送文本(发送数据)

' 接收端还原
定义 还原温度(高字节, 低字节) 返回 温度
  设 值 = 高字节 * 256 + 低字节
  返回 值 / 10.0

字节序(大小端)

字节序 说明 常见场景
大端序(Big-Endian) 高位字节在前 网络协议、Java
小端序(Little-Endian) 低位字节在前 x86、ARM、大多数MCU
' 大端序: 3.14 → [0x40, 0x48, 0xF5, 0xC3]
' 小端序: 3.14 → [0xC3, 0xF5, 0x48, 0x40]

常见问题

Q1: 转换后数值有误差?

IEEE 754单精度只有约7位有效数字。3.14 可能变成 3.140000104904175。这是正常的浮点数精度问题。

Q2: 发送后MCU解析错误?

  • 确认两端使用相同的字节序
  • 确认数据类型一致(float/double)
  • 使用hexdump工具查看原始字节确认

Q3: 有没有现成扩展?

部分串口扩展内置了浮点数转换功能。如果使用纯BluetoothClient,需要自行实现。

总结

方案 精度 难度 推荐度
WebView + JS ✅ IEEE 754 ⭐⭐ ⭐⭐⭐⭐⭐
简化协议 近似 ⭐⭐⭐
整数缩放 完全精确 ⭐⭐⭐⭐

版权声明:MIT App Inventor 官方文档采用 CC BY-SA 4.0 授权,本文档由 ai2claw 🐝 整理。

文档反馈