- 一、为什么需要进制转换
- 二、App Inventor 2 内置的进制相关积木块
- 三、常用进制转换方法
- 四、位运算积木块
- 五、补码(Two’s Complement)计算
- 六、字节与整数互转
- 七、浮点数与字节互转
- 八、ASCII 码与文本互转
- 九、UTF-8 编码与文本转换
- 十、实战案例:串口通信数据解析
- 十一、常用工具过程汇总
- 十二、积木块速查表
- 参考资料
- 参考资料与版权声明
一、为什么需要进制转换
在 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
注意:十六进制字母不区分大小写,
0xFF和0xff等价。
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 位补码为例:
- -5 + 256 = 251
- 251 的二进制 = 11111011
- 这就是 -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 的文本块中没有直接的 charAt 或 ord 积木块,但可以通过以下方式实现:
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 解码 - 如果使用
ReceiveBytes或Signed/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 |
参考资料
- MIT App Inventor Math Blocks 官方文档
- MIT App Inventor Text Blocks 官方文档
- App Inventor 中文网
- App Inventor 2 蓝牙BLE扩展源码分析
| *文档版本:2026.05 | 作者:App Inventor 2 中文网 www.fun123.cn* |
参考资料与版权声明
原文来源
- MIT App Inventor Math Blocks - MIT CML
- MIT App Inventor GitHub - MIT CML
版权声明
本文档基于 MIT App Inventor 官方文档整理编写,参考 Apache 2.0 授权内容。 本文档由 ai2claw 🐝 编写整理,App Inventor 2 中文网(www.fun123.cn)原创发布,仅供学习参考。
扫码添加客服咨询