如何修正int16_t数组打包为uint64_t的错误?NodeJS解包失败
问题
我有一个每行包含6个元素的int16_t数组,定义如下:
const int16_t xzyabc[][6] PROGMEM = { {1, 2, 3, 4, 5, 6}, {7, 8, 9, 10, 11, 12}, };
每个元素均为int16_t类型,我需要将每4个int16_t元素打包到一个uint64_t中。为此编写了Telemetry::loop函数代码,但输出结果异常:
Number: 262147131073 Number: 524295393221 Number: 786443655369
且在NodeJS中解包时失败,请问错误原因是什么?该如何修复?
错误原因与修复方案
核心错误点
- PROGMEM读取错误:数组存储在程序闪存(PROGMEM)中,但打包时直接通过数组下标访问,未使用AVR平台专用的PROGMEM读取函数,导致拿到的是闪存地址而非实际数据,数值完全错乱。
- 位操作与字节序错误:打包
int16_t到uint64_t时,移位位数或顺序处理错误,导致元素在64位值中的存储位置混乱,和NodeJS解包时的字节序不匹配。 - 遍历逻辑错误:每行6个元素,按每4个打包的逻辑可能存在索引计算错误,导致跨行读取或元素遗漏/重复。
修复步骤
1. 正确读取PROGMEM数据
AVR平台下,PROGMEM中的数据不能直接通过普通数组访问,必须用专用函数读取:
#include <avr/pgmspace.h> // 读取PROGMEM中的int16_t元素 int16_t get_prog_int16(const int16_t *addr) { return pgm_read_word(addr); }
2. 正确实现打包逻辑
按小端字节序(和NodeJS默认Buffer处理一致)将4个int16_t拼接为uint64_t,同时处理每行剩余的2个元素:
void Telemetry::loop() { uint8_t total_rows = sizeof(xzyabc) / sizeof(xzyabc[0]); for (uint8_t row = 0; row < total_rows; row++) { const int16_t *current_row = xzyabc[row]; // 打包前4个元素 uint64_t pack1 = 0; for (uint8_t i = 0; i < 4; i++) { int16_t val = get_prog_int16(¤t_row[i]); // 小端模式:第i个元素放在64位的低16*i位 pack1 |= (uint64_t)(uint16_t)val << (i * 16); } Serial.print("Packed (1-4): "); Serial.println((unsigned long long)pack1); // 打包剩余2个元素(补两个0凑满64位) uint64_t pack2 = 0; for (uint8_t i = 4; i < 6; i++) { int16_t val = get_prog_int16(¤t_row[i]); pack2 |= (uint64_t)(uint16_t)val << ((i - 4) * 16); } pack2 |= (uint64_t)0 << 32; pack2 |= (uint64_t)0 << 48; Serial.print("Packed (5-6+0+0): "); Serial.println((unsigned long long)pack2); } }
3. NodeJS端正确解包
确保解包字节序和打包时一致(小端),用Buffer处理:
// 将uint64_t对应的Buffer解包为int16_t数组 function unpackUint64ToInt16(buf) { const result = []; // 小端模式,每2字节读取一个int16 for (let i = 0; i < 8; i += 2) { result.push(buf.readInt16LE(i)); } return result; } // 示例:传入打包后的Buffer,得到原数组元素 // 比如pack1对应的Buffer是Buffer.from([0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00]) // 解包后得到 [1,2,3,4]
验证说明
修复后,第一行前4个元素(1,2,3,4)打包后的uint64_t十进制值应为281479271741441,NodeJS用上述方法解包可正确还原出原数组元素。
内容的提问来源于stack exchange,提问作者Rodrigo
相关产品推荐
相关产品推荐

