如何用JavaScript通过BLE发送大数据块?p5.ble.js图片发送异常求助
JavaScript通过BLE发送大数据块的问题排查与修复
核心错误原因
- 二进制数据转字符串的损坏:你用
TextDecoder把图片的二进制数据解码成字符串,但图片数据并非合法的UTF-8文本序列。解码器遇到无法识别的字节时,会自动替换成替换字符�(对应的UTF-8编码就是你看到的239,191,189),直接破坏了原始二进制数据。 - 数组类型不兼容:最初尝试直接发送
img.slice(0,127)失败,是因为img是普通数组,而p5.ble.js的write方法需要接收ArrayBuffer或TypedArray(比如Uint8Array)类型的二进制数据,而非普通数组。 - 分块逻辑的问题:
slice(128,255)的索引范围有误差——slice是左闭右开,这个范围实际只包含127个字节,和第一个块长度不一致;另外用setTimeout控制发送顺序不可靠,容易出现时序问题或外设处理不过来的情况。
修复后的代码示例
首先把存储图片数据的容器改成Uint8Array(二进制数据的标准容器),然后用异步方式分块发送,确保每块发送完成后再发下一块:
let myBLE; let img; function setup() { myBLE = new p5ble(); // 创建写入按钮 const writeButton = createButton('Write'); writeButton.mousePressed(writeToBle); // 用Uint8Array存储15000字节的二进制数据 img = new Uint8Array(15000); for(let i = 0; i < 15000; i++) { img[i] = i; } } async function writeToBle() { // 每块的有效负载大小,根据你的BLE外设MTU调整(这里假设支持127字节) const chunkSize = 127; let currentOffset = 0; const totalLength = img.length; while(currentOffset < totalLength) { // 计算当前块的结束位置,避免超出数组长度 const endOffset = Math.min(currentOffset + chunkSize, totalLength); // 截取当前块的Uint8Array const currentChunk = img.slice(currentOffset, endOffset); // 等待当前块发送完成再继续,确保顺序和可靠性 await myBLE.write(myCharacteristic, currentChunk); // 更新偏移量,准备发送下一块 currentOffset = endOffset; // 可选:添加短延迟,给外设留处理时间 await new Promise(resolve => setTimeout(resolve, 100)); } }
关键说明
- 直接传递
Uint8Array给myBLE.write,绕过字符串转换,保证二进制数据的完整性。 - 使用
async/await替代setTimeout,确保分块发送的顺序和可靠性,避免丢包或乱序。 chunkSize需要根据你的BLE外设支持的MTU调整:BLE的MTU包含ATT层的3字节开销,所以有效负载大小是MTU - 3(比如MTU=130的话,有效负载就是127字节)。
内容的提问来源于stack exchange,提问作者Salahuddin
相关产品推荐
相关产品推荐

