App Inventor 2 进制转换与位运算教程 - 十六进制、二进制、补码、字节操作

« 返回首页

一、为什么需要进制转换

在 App Inventor 2 开发中,进制转换和位运算在以下场景中非常常见:

  • 串口通信:蓝牙、BLE、USB 串口收发的数据通常是十六进制或字节流
  • 物联网协议:Modbus、MQTT 等协议的数据帧涉及多字节拼合和解析
  • 传感器数据:温度、加速度等传感器返回的原始数据需要按字节解析
  • 颜色编码:ARGB 颜色值本质上是十六进制表示的 32 位整数

App Inventor 2 内置了丰富的数学积木块来支持这些操作,本文将逐一详解。


二、App Inventor 2 内置的进制相关积木块

2.1 基本数字块(Basic Number Block)

基本数字块 number 不仅仅支持十进制,还支持通过 C 语言风格前缀输入其他进制:

前缀 进制 示例 十进制值
0b 二进制(Base-2) 0b1010 10
0o 八进制(Base-8) 0o14 12
0x 十六进制(Base-16) 0xFF 255

使用方法:直接在数字块中输入带前缀的数字,App Inventor 会自动将其识别为对应进制并转换为十进制值。

数字块: 0xFF    → 值为 255
数字块: 0b1010  → 值为 10
数字块: 0o17    → 值为 15

注意:十六进制字母不区分大小写,0xFF0xff 等价。

2.2 基数数字块(Radix Number Block)

基数数字块提供了一种更直观的进制输入方式。点击下拉菜单可以选择输入进制:

  • decimal(十进制,Base-10):支持正数、负数、小数
  • binary(二进制,Base-2):仅支持非负整数
  • octal(八进制,Base-8):仅支持非负整数
  • hexadecimal(十六进制,Base-16):仅支持非负整数
基数数字块 [hex] FF → 值为 255
基数数字块 [binary] 11111111 → 值为 255
基数数字块 [decimal] 255 → 值为 255

三个积木块返回的值完全相同,只是输入方式不同。

2.3 convert number 积木块(进制转换核心)

这是进制转换最核心的积木块:

convert number: 文本 "255" 从 [base-10] 到 [base-16]
→ 返回文本 "FF"

convert number: 文本 "10" 从 [base-10] 到 [base-2]
→ 返回文本 "1010"

convert number: 文本 "FF" 从 [base-16] 到 [base-10]
→ 返回文本 "255"

关键特性

  • 输入和输出都是文本类型(text),不是数字类型(number)
  • 支持的进制:base-2(二进制)、base-8(八进制)、base-10(十进制)、base-16(十六进制)
  • 转换后的十六进制字母为大写(如 FF,不是 ff

2.4 format as decimal 积木块

将数字格式化为指定小数位数的文本:

format as decimal: 数值 3.14159 到 2 位
→ 返回文本 "3.14"

format as decimal: 数值 255 到 0 位
→ 返回文本 "255"

三、常用进制转换方法

3.1 十进制转十六进制

定义 十进制转十六进制(十进制数)
  返回 convert number: 
    文本(十进制数) 
    从 [base-10] 
    到 [base-16]

示例

输入(十进制) 输出(十六进制)
255 “FF”
16 “10”
10 “A”
0 “0”

3.2 十六进制转十进制

定义 十六进制转十进制(十六进制文本)
  返回 convert number: 
    十六进制文本 
    从 [base-16] 
    到 [base-10]

注意convert number 返回的是文本,如果需要参与数学运算,需要用 number 函数转换:

定义 十六进制文本转数值(十六进制文本)
  返回 convert number: 
    十六进制文本 
    从 [base-16] 
    到 [base-10]
  → 得到文本 "255"
  → 需要时用 number(文本) 转为数字 255

3.3 十进制转二进制

定义 十进制转二进制(十进制数)
  返回 convert number: 
    文本(十进制数) 
    从 [base-10] 
    到 [base-2]

示例

输入(十进制) 输出(二进制)
10 “1010”
255 “11111111”
128 “10000000”

3.4 二进制转十进制

定义 二进制转十进制(二进制文本)
  返回 convert number: 
    二进制文本 
    从 [base-2] 
    到 [base-10]

3.5 十六进制与二进制互转

App Inventor 的 convert number 不直接支持 base-16 到 base-2 的转换,但可以中转

定义 十六进制转二进制(十六进制文本)
  // 方法:先转十进制,再转二进制
  初始化局部变量 十进制文本 = convert number: 十六进制文本 从 [base-16] 到 [base-10]
  返回 convert number: 十进制文本 从 [base-10] 到 [base-2]

3.6 字符串左侧补零

在很多通信协议中,数据需要固定位宽(如 8 位二进制、2 位十六进制),这就需要左侧补零:

定义 左侧补零(原始文本, 目标长度)
  初始化局部变量 补零数 = 目标长度 - 文本长度(原始文本)
  如果 补零数 > 0 则
    返回 join: 重复文本("0", 补零数), 原始文本
  否则
    返回 原始文本

示例

原始文本 目标长度 输出
“FF” 4 “00FF”
“A” 2 “0A”
“1010” 8 “00001010”

完整过程——十进制转 2 位十六进制

定义 十进制转两位十六进制(十进制数)
  初始化局部变量 十六进制文本 = convert number: 文本(十进制数) 从 [base-10] 到 [base-16]
  返回 左侧补零(十六进制文本, 2)

四、位运算积木块

App Inventor 2 内置了三个位运算积木块,它们在处理二进制数据时非常有用。

4.1 Bitwise And(按位与)

Bitwise And: 数值A, 数值B

逐位比较,两个对应位都为 1 时结果位为 1,否则为 0。

  6 = 0110
  3 = 0011
  ----------
AND = 0010 = 2

典型用途:提取特定位、掩码操作。

// 提取低 4 位
Bitwise And: 数值, 0xF      → 保留低 4 位
// 提取高 4 位
Bitwise And: 数值, 0xF0     → 保留高 4 位

4.2 Bitwise Or (Inclusive)(按位或)

Bitwise Or: 数值A, 数值B

逐位比较,任一对应位为 1 时结果位为 1。

  6 = 0110
  3 = 0011
  ----------
 OR = 0111 = 7

典型用途:合并标志位。

// 设置第 0 位为 1
Bitwise Or: 数值, 0x01

4.3 Bitwise Or (Exclusive / XOR)(按位异或)

Bitwise Or (Exclusive): 数值A, 数值B

逐位比较,两个对应位不同时结果位为 1,相同时为 0。

  6 = 0110
  3 = 0011
  ----------
XOR = 0101 = 5

典型用途:数据校验、简单加密、翻转特定位。

4.4 位运算的组合应用:提取字节

将一个 16 位整数拆分为高字节和低字节:

定义 提取高字节(十六位整数)
  返回 Bitwise And: 十六位整数, 0xFF00  // 保留高 8 位
  → 然后 >> 8(右移 8 位,见下文)

注意:App Inventor 2 没有内置的位移(shift)积木块,但可以通过除法和乘法模拟:

  • 右移 n 位 = 除以 2^n 后取 floor
  • 左移 n 位 = 乘以 2^n
定义 右移8位(数值)
  返回 floor(数值 / 256)

定义 提取高字节(十六位整数)
  返回 floor(十六位整数 / 256)

定义 提取低字节(十六位整数)
  返回 Bitwise And: 十六位整数, 0xFF

五、补码(Two’s Complement)计算

5.1 什么是补码

在计算机中,有符号整数使用补码(Two’s Complement)来表示负数。对于一个 N 位有符号整数:

  • 最高位(MSB)为 0:表示正数,值就是其二进制表示
  • 最高位(MSB)为 1:表示负数,值的绝对值 = 按位取反再加 1

以 8 位有符号整数为例:

二进制 无符号值 有符号值(补码)
00000000 0 0
01111111 127 127
10000000 128 -128
11111111 255 -1
11111110 254 -2

5.2 在 App Inventor 2 中计算补码

场景1:将无符号字节转换为有符号值

从串口收到的数据是 0~255 的无符号字节,但某些传感器返回的是有符号温度值(-128~127)。需要将无符号值转为有符号值:

定义 无符号字节转有符号(无符号值)
  如果 无符号值 > 127 则
    返回 无符号值 - 256
  否则
    返回 无符号值

示例

无符号值 有符号值
255 -1
254 -2
128 -128
127 127
0 0

场景2:将有符号值转换为无符号字节(用于发送)

定义 有符号转无符号字节(有符号值)
  如果 有符号值 < 0 则
    返回 有符号值 + 256
  否则
    返回 有符号值

示例

有符号值 无符号字节
-1 255
-128 128
0 0
127 127

场景3:16 位有符号整数(Int16)的补码

定义 无符号16位转有符号(无符号值)
  如果 无符号值 > 32767 则
    返回 无符号值 - 65536
  否则
    返回 无符号值

场景4:求一个数的补码二进制表示

将一个有符号整数转为 N 位二进制补码字符串:

定义 求补码二进制(有符号值, 位数)
  初始化局部变量 无符号值
  如果 有符号值 < 0 则
    设置 无符号值 = 有符号值 + 2^位数
  否则
    设置 无符号值 = 有符号值
  初始化局部变量 二进制文本 = convert number: 文本(无符号值) 从 [base-10] 到 [base-2]
  返回 左侧补零(二进制文本, 位数)

示例

有符号值 位数 补码二进制
5 8 “00000101”
-5 8 “11111011”
-1 8 “11111111”
-128 8 “10000000”
127 8 “01111111”

原理说明

以 -5 的 8 位补码为例:

  1. -5 + 256 = 251
  2. 251 的二进制 = 11111011
  3. 这就是 -5 的 8 位补码表示

六、字节与整数互转

6.1 多字节拼合为整数(解析收到的数据帧)

在串口通信中,经常需要将多个字节拼合成一个 16 位或 32 位整数。

大端序(Big-Endian,高位在前)

定义 两字节大端拼合(高字节, 低字节)
  返回 高字节 * 256 + 低字节

示例:收到字节 0x1A, 0x2B → 结果 = 0x1A * 256 + 0x2B = 6699

小端序(Little-Endian,低位在前)

定义 两字节小端拼合(低字节, 高字节)
  返回 高字节 * 256 + 低字节

示例:收到字节 0x2B, 0x1A → 低字节=0x2B, 高字节=0x1A → 结果 = 0x1A * 256 + 0x2B = 6699

四字节拼合为 32 位整数

定义 四字节大端拼合(字节3, 字节2, 字节1, 字节0)
  // 字节3是最高位, 字节0是最低位
  返回 字节3 * 16777216 + 字节2 * 65536 + 字节1 * 256 + 字节0

其中 16777216 = 2^24,65536 = 2^16

6.2 整数拆分为字节(构建发送数据帧)

定义 整数拆两字节大端(十六位整数)
  初始化局部变量 高字节 = floor(十六位整数 / 256)
  初始化局部变量 低字节 = Bitwise And: 十六位整数, 0xFF
  返回 列表(高字节, 低字节)
定义 整数拆四字节大端(三十二位整数)
  初始化局部变量 字节3 = floor(三十二位整数 / 16777216)
  初始化局部变量 余数 = Bitwise And: 三十二位整数, 0xFFFFFF
  初始化局部变量 字节2 = floor(余数 / 65536)
  设置 余数 = Bitwise And: 余数, 0xFFFF
  初始化局部变量 字节1 = floor(余数 / 256)
  初始化局部变量 字节0 = Bitwise And: 余数, 0xFF
  返回 列表(字节3, 字节2, 字节1, 字节0)

七、浮点数与字节互转

7.1 问题描述

很多传感器(如温度传感器、IMU)返回的数据是 IEEE 754 浮点数,需要将 4 个字节还原为浮点数,或将浮点数转为 4 字节用于发送。

App Inventor 2 没有内置浮点数与字节的互转积木块,但可以通过 WebViewer 执行 JavaScript 来实现。

7.2 使用 WebViewer 进行浮点数转换

步骤1:在 Screen 中添加一个 WebViewer 组件(可以设为不可见)。

步骤2:编写 HTML 文件,包含浮点数转换的 JavaScript 函数:

<!-- float_converter.html -->
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"></head>
<body>
<script>
// 浮点数转4字节(小端序)
function floatToBytes(value) {
  var buf = new ArrayBuffer(4);
  new Float32Array(buf)[0] = value;
  var bytes = new Uint8Array(buf);
  return JSON.stringify([bytes[0], bytes[1], bytes[2], bytes[3]]);
}

// 4字节转浮点数(小端序)
function bytesToFloat(b0, b1, b2, b3) {
  var buf = new ArrayBuffer(4);
  var bytes = new Uint8Array(buf);
  bytes[0] = b0; bytes[1] = b1; bytes[2] = b2; bytes[3] = b3;
  return new Float32Array(buf)[0];
}
</script>
</body>
</html>

步骤3:在 App Inventor 中调用:

当 Button_转换.被点击 时
  调用 WebViewer1.运行JavaScript(
    join("bytesToFloat(", 字节0, ",", 字节1, ",", 字节2, ",", 字节3, ")")
  )

7.3 利用 Web 组件进行转换

另一种方式是通过 Web 组件调用本地 JavaScript:

// 在 WebViewer.WebViewStringChanged 事件中获取结果
当 WebViewer1.WebViewStringChanged 时
  设置 全局浮点结果 = 获取 WebViewer1.WebViewString

八、ASCII 码与文本互转

8.1 文本转 ASCII 码

App Inventor 2 没有直接的 ord() 函数,但可以使用文本积木块组合实现:

定义 文本转ASCII码列表(输入文本)
  初始化局部变量 结果 = 创建空列表
  对于 初始化局部变量 i = 1 到 文本长度(输入文本)
    追加列表项(结果, 
      取字符的Unicode码(
        选择文本(输入文本, i, i)  // 取第 i 个字符
      )
    )
  结束对于
  返回 结果

注意:App Inventor 的文本块中没有直接的 charAtord 积木块,但可以通过以下方式实现:

  • segment(文本, 起始位置, 长度) — 截取子串
  • 对于 ASCII 码转换,可以使用 JavaScript 通过 WebViewer 调用 charCodeAt()

8.2 ASCII 码转文本

使用 characterFromCode 积木块(在文本相关操作中)将 Unicode 码点转为字符。


九、UTF-8 编码与文本转换

9.1 问题场景

通过蓝牙或串口收到 UTF-8 编码的字节流,需要还原为中文文本。

9.2 解决方案

App Inventor 2 内部的文本编码为 UTF-8,所以:

  • 如果使用蓝牙 ReceiveText 方法,App Inventor 会自动处理 UTF-8 解码
  • 如果使用 ReceiveBytesSigned/Unsigned Byte 接收,需要手动处理

对于手动字节流到 UTF-8 文本的转换,推荐使用 WebViewer + JavaScript:

function bytesToUTF8(byteArray) {
  var uint8 = new Uint8Array(byteArray);
  var decoder = new TextDecoder('utf-8');
  return decoder.decode(uint8);
}

十、实战案例:串口通信数据解析

10.1 场景描述

通过蓝牙串口接收传感器数据,协议格式如下:

帧头: 0xAA 0x55
长度: 1字节(数据区字节数)
数据区: 温度(2字节, 有符号, 大端序) + 湿度(2字节, 无符号, 大端序)
校验: 1字节(数据区所有字节异或值)

10.2 数据帧示例

假设收到以下十六进制字节:

AA 55 04 00 C8 01 90 58

解析:

  • AA 55 — 帧头
  • 04 — 数据长度(4字节)
  • 00 C8 — 温度:0x00C8 = 200 → 有符号 = +200(0.1°C单位,即 20.0°C)
  • 01 90 — 湿度:0x0190 = 400(0.1%单位,即 40.0%)
  • 58 — 校验:0x00 ⊕ 0xC8 ⊕ 0x01 ⊕ 0x90 = 0x59… 实际需要验证

10.3 App Inventor 2 解析代码

// 全局变量
定义全局 字节列表 = 创建空列表
定义全局 解析状态 = "等待帧头1"

当 BluetoothClient1.BytesAvailable > 0 时
  设置 字节列表 = 调用 BluetoothClient1.ReceiveUnsignedBytes(-1, 0)
  调用 解析数据帧(字节列表)

定义 解析数据帧(收到的字节列表)
  对于 初始化局部变量 i = 1 到 列表长度(收到的字节列表)
    初始化局部变量 当前字节 = 列表选择项(收到的字节列表, i)
    
    如果 解析状态 = "等待帧头1" 则
      如果 当前字节 = 0xAA 则
        设置 解析状态 = "等待帧头2"
    
    否则 如果 解析状态 = "等待帧头2" 则
      如果 当前字节 = 0x55 则
        设置 解析状态 = "读取长度"
        设置 全局数据缓冲 = 创建空列表
      否则
        设置 解析状态 = "等待帧头1"
    
    否则 如果 解析状态 = "读取长度" 则
      设置 全局数据长度 = 当前字节
      设置 解析状态 = "读取数据"
    
    否则 如果 解析状态 = "读取数据" 则
      追加列表项(全局数据缓冲, 当前字节)
      如果 列表长度(全局数据缓冲) = 全局数据长度 则
        设置 解析状态 = "读取校验"
    
    否则 如果 解析状态 = "读取校验" 则
      初始化局部变量 计算校验 = 0
      对于 初始化局部变量 j = 1 到 列表长度(全局数据缓冲)
        设置 计算校验 = Bitwise Or(Exclusive): 计算校验, 列表选择项(全局数据缓冲, j)
      结束对于
      如果 计算校验 = 当前字节 则
        调用 处理有效数据(全局数据缓冲)
      否则
        // 校验失败,丢弃数据
      设置 解析状态 = "等待帧头1"
  结束对于

10.4 提取温度和湿度值

定义 处理有效数据(数据缓冲)
  // 温度:前2字节,有符号,大端序
  初始化局部变量 温度高字节 = 列表选择项(数据缓冲, 1)
  初始化局部变量 温度低字节 = 列表选择项(数据缓冲, 2)
  初始化局部变量 温度原始值 = 温度高字节 * 256 + 温度低字节
  // 如果是有符号整数,需要判断补码
  初始化局部变量 温度值 = 无符号16位转有符号(温度原始值) / 10.0
  
  // 湿度:后2字节,无符号,大端序
  初始化局部变量 湿度高字节 = 列表选择项(数据缓冲, 3)
  初始化局部变量 湿度低字节 = 列表选择项(数据缓冲, 4)
  初始化局部变量 湿度值 = (湿度高字节 * 256 + 湿度低字节) / 10.0
  
  设置 Label_温度.文本 = join("温度: ", 文本(温度值), "°C")
  设置 Label_湿度.文本 = join("湿度: ", 文本(湿度值), "%")

10.5 发送十六进制命令

定义 发送十六进制命令(十六进制命令文本)
  // 输入如 "AA 55 01 03"
  初始化局部变量 字节文本列表 = split: 十六进制命令文本 at " "
  初始化局部变量 字节数值列表 = 创建空列表
  对于 初始化局部变量 i = 1 到 列表长度(字节文本列表)
    追加列表项(字节数值列表, 
      number( convert number: 列表选择项(字节文本列表, i) 从 [base-16] 到 [base-10] )
    )
  结束对于
  调用 BluetoothClient1.SendBytes(字节数值列表)

十一、常用工具过程汇总

以下是将本文所有工具过程整理在一起,方便直接使用:

左侧补零

定义 左侧补零(原始文本, 目标长度)
  初始化局部变量 当前长度 = 文本长度(原始文本)
  初始化局部变量 结果 = 原始文本
  循环 当 当前长度 < 目标长度
    设置 结果 = join("0", 结果)
    设置 当前长度 = 当前长度 + 1
  返回 结果

十进制转固定位宽十六进制

定义 十进制转固定位十六进制(十进制数, 位宽)
  初始化局部变量 十六进制文本 = convert number: 文本(十进制数) 从 [base-10] 到 [base-16]
  返回 左侧补零(十六进制文本, 位宽)

无符号转有符号

定义 无符号转有符号(无符号值, 位数)
  初始化局部变量 最大正值 = 2^(位数 - 1) - 1
  如果 无符号值 > 最大正值 则
    返回 无符号值 - 2^位数
  否则
    返回 无符号值

异或校验

定义 异或校验(字节列表)
  初始化局部变量 结果 = 0
  对于 初始化局部变量 i = 1 到 列表长度(字节列表)
    设置 结果 = Bitwise Or(Exclusive): 结果, 列表选择项(字节列表, i)
  返回 结果

十二、积木块速查表

需求 使用哪个积木块 所在分类
输入十六进制数 基本数字块 0xFF 或基数数字块 Math
输入二进制数 基本数字块 0b1010 或基数数字块 Math
十进制 ↔ 十六进制 convert number Math
十进制 ↔ 二进制 convert number Math
十六进制 ↔ 二进制 先转十进制再转目标进制(中转法) Math
按位与(掩码) Bitwise And Math
按位或(置位) Bitwise Or Math
按位异或(校验) Bitwise Or (Exclusive) Math
右移 n 位 floor(数值 / 2^n) Math
左移 n 位 数值 * 2^n(用 Bitwise And 截断) Math
补码转有符号 if 值 > 2^(n-1)-1 then 值 - 2^n Math + Control
浮点数 ↔ 字节 WebViewer + JavaScript(IEEE 754) WebViewer
ASCII 码 ↔ 字符 segment + Unicode 操作 Text

参考资料


*文档版本:2026.05 作者:App Inventor 2 中文网 www.fun123.cn*

参考资料与版权声明

原文来源

版权声明

本文档基于 MIT App Inventor 官方文档整理编写,参考 Apache 2.0 授权内容。 本文档由 ai2claw 🐝 编写整理,App Inventor 2 中文网(www.fun123.cn)原创发布,仅供学习参考。

文档反馈