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积木块

when Screen1.Initialize() {
  WebViewer1.HomeUrl = "file:///android_asset/float_converter.html"
}

// 浮点数转字节
procedure 浮点数转字节(数值, 小端序) {
  global JSON = join("{\"cmd\":\"float2bytes\",\"value\":", 数值, ",\"littleEndian\":", 小端序, "}")
  WebViewer1.WebViewString = JSON
  // 等待WebView回调
}

when WebViewer1.WebViewStringChange(value) {
  global 结果 = JsonTextDecode(value)
  if (Dictionary.Get(结果, "result") != "") {
    global 字节列表 = Dictionary.Get(结果, "result")
    标签_字节.Text = join(字节列表)
  }
}

// 字节转浮点数
procedure 字节转浮点数(字节列表, 小端序) {
  global JSON = join("{\"cmd\":\"bytes2float\",\"bytes\":[", join(字节列表), "],\"littleEndian\":", 小端序, "}")
  WebViewer1.WebViewString = JSON
}

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

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

procedure 浮点数转近似字节(数值) {
  // 简化版:将浮点数拆为整数部分和小数部分
  // 注意:这不是标准IEEE 754,是自定义简化协议
  
  global 整数部分 = math.floor(math.abs(数值))
  global 小数部分 = 数值 - 整数部分
  
  // 整数部分用2字节
  global 高字节 = math.floor(整数部分 / 256)
  global 低字节 = modulo(整数部分, 256)
  
  // 小数部分用2字节(乘以10000保留4位精度)
  global 小数整数 = math.floor(小数部分 * 10000)
  global 小数高字节 = math.floor(小数整数 / 256)
  global 小数低字节 = modulo(小数整数, 256)
  
  // 符号字节
  global 符号 = 0
  if (数值 < 0) {
    global 符号 = 1
  }
  
  global 转换结果 = [符号, 高字节, 低字节, 小数高字节, 小数低字节]
}

procedure 近似字节转浮点数(字节列表) {
  global 符号 = selectListItem(字节列表, 1)
  global 整数部分 = selectListItem(字节列表, 2) * 256 + selectListItem(字节列表, 3)
  global 小数部分 = (selectListItem(字节列表, 4) * 256 + selectListItem(字节列表, 5)) / 10000
  global 结果 = 整数部分 + 小数部分
  if (符号 == 1) {
    global 结果 = -结果
  }
  global 解析结果 = 结果
}

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

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

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

procedure 发送温度(温度值) {
  // 温度值 × 10 保留1位小数,用2字节整数发送
  global 值 = math.floor(温度值 * 10)
  global 高字节 = math.floor(值 / 256)
  global 低字节 = modulo(值, 256)
  // AI2没有直接字符函数,这里假设有扩展或者自定义过程,仅作演示
  global 发送数据 = join(高字节, 低字节)
  BluetoothClient1.SendText(发送数据)
}

// 接收端还原
procedure 还原温度(高字节, 低字节) {
  global 值 = 高字节 * 256 + 低字节
  global 温度 = 值 / 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 ⭐⭐ ⭐⭐⭐⭐⭐
简化协议 近似 ⭐ ⭐⭐⭐
整数缩放 完全精确 ⭐ ⭐⭐⭐⭐
文档反馈