You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修正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(&current_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(&current_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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 04:55:31