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

React Native向TTGO T-Display通过BLE发送数据乱码问题排查

问题:React Native BLE发送字符串到TTGO T-Display出现乱码

问题描述

通过蓝牙低功耗(BLE)从React Native应用向TTGO T-Display发送字符串(如"John")时,设备接收到的是乱码(如"e&g")。

已尝试方案

测试过不同编码方式和数据类型,问题未解决。

乱码原因分析

  1. 数据格式不匹配:React Native直接传递字符串给BLE写特征值方法时,底层可能将字符串转换为不符合预期的字节格式,Arduino端按默认方式解析就会出现乱码。
  2. 编码不一致:部分数据使用Base64编码发送,但Arduino端未做解码处理,直接显示编码后的字符串导致乱码。
  3. Arduino端未正确处理显示:原代码仅获取了接收值,未实现正确的字符串解析与屏幕显示逻辑。

解决方案

1. React Native端修改:统一按UTF-8字节数组发送数据

BLE传输的是字节流,需确保发送端将字符串转换为标准UTF-8字节数组,避免编码歧义:

async function scanAndConnect(color, medicijnNaam, voornaam, notitie) {
    let connectedDevice = null;

    // 字符串转UTF-8字节数组工具函数
    function stringToUtf8Bytes(str) {
        const encoder = new TextEncoder();
        return encoder.encode(str);
    }

    try {
        const isReady = await prepareBluetooth();
        if (!isReady) {
            console.error("Bluetooth voorbereiding mislukt.");
            return;
        }

        const TTGO_T_DISPLAY_UUID = '4fafc201-1fb5-459e-8fcc-c5c9c331914b';
        const TTGO_T_DISPLAY_Characteristic_UUID = 'beb5483e-36e1-4688-b7f5-ea07361b26a8';

        const scanAndConnectDevice = new Promise((resolve, reject) => {
            manager.startDeviceScan(null, null, async (error, device) => {
                if (error) {
                    console.error(error);
                    reject(error);
                    return;
                }

                if (device.name === 'TTGO_T_Display') {
                    console.log('Apparaat gevonden: ', device.name);

                    try {
                        manager.stopDeviceScan();
                        const isConnected = await device.isConnected();
                        if (isConnected) {
                            console.log('Device already connected.');
                            resolve(device);
                            return;
                        }

                        connectedDevice = await device.connect();
                        console.log('Succesvol verbonden met ', device.name);

                        await connectedDevice.discoverAllServicesAndCharacteristics();
                        resolve(connectedDevice);

                    } catch (err) {
                        console.error('Fout bij verbinden met device:', err);
                        reject(err);
                    }
                }
            });
        });

        const device = await scanAndConnectDevice;

        if (color) {
            const colorRGB = convertToColor(color);
            if (Array.isArray(colorRGB) && colorRGB.length === 3) {
                const [r, g, b] = colorRGB;
                const colorInt = (r << 16) | (g << 8) | b;
                const colorHex = colorInt.toString(16).padStart(6, '0').toUpperCase();

                await device.writeCharacteristicWithResponseForService(
                    TTGO_T_DISPLAY_UUID,
                    TTGO_T_DISPLAY_Characteristic_UUID,
                    stringToUtf8Bytes(colorHex)
                );

                console.log('Kleur verzonden naar TTGO T-display:', colorHex);
            } else {
                console.error('Ongeldige kleurarray:', colorRGB);
            }
        }

        if (voornaam) {
            try {
                console.log('Bezig met verzenden van voornaam:', voornaam);
                await device.writeCharacteristicWithResponseForService(
                    TTGO_T_DISPLAY_UUID,
                    TTGO_T_DISPLAY_Characteristic_UUID,
                    stringToUtf8Bytes(voornaam)
                );
                console.log('Voornaam succesvol verzonden naar TTGO T-display:', voornaam);
            } catch (error) {
                console.error('Fout bij het verzenden van de voornaam:', error);
            }
        }

        if (medicijnNaam) {
            try {
                console.log('Bezig met verzenden van medicijnnaam:', medicijnNaam);
                // 去掉Base64编码,直接传UTF-8字节
                await device.writeCharacteristicWithResponseForService(
                    TTGO_T_DISPLAY_UUID,
                    TTGO_T_DISPLAY_Characteristic_UUID,
                    stringToUtf8Bytes(medicijnNaam)
                );
                console.log('Medicijnnaam succesvol verzonden naar TTGO T-display:', medicijnNaam);
            } catch (error) {
                console.error('Fout bij het verzenden van de medicijnNaam:', error);
            }
        }

        if (notitie) {
            try {
                console.log('Bezig met verzenden van notitie:', notitie);
                // 去掉Base64编码,直接传UTF-8字节
                await device.writeCharacteristicWithResponseForService(
                    TTGO_T_DISPLAY_UUID,
                    TTGO_T_DISPLAY_Characteristic_UUID,
                    stringToUtf8Bytes(notitie)
                );
                console.log('Notitie succesvol verzonden naar TTGO T-display:', notitie);
            } catch (error) {
                console.error('Fout bij het verzenden van de notitie:', error);
            }
        }

    } catch (error) {
        console.warn('Fout tijdens scannen en verbinden:', error);
    } finally {
        if (connectedDevice) {
            try {
                await connectedDevice.cancelConnection();
                console.log('Verbinding geannuleerd.');
            } catch (err) {
                console.error('Fout bij annuleren van de verbinding:', err);
            }
        }
    }
}

scanAndConnect(null, null, "John", null);

2. Arduino端修改:正确解析并显示接收数据

在onWrite回调中,直接解析UTF-8字符串并显示到屏幕,同时添加串口打印方便调试:

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <TFT_eSPI.h>

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

TFT_eSPI tft = TFT_eSPI();
uint16_t currentColor = TFT_BLACK;

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
        Serial.println("Apparaat verbonden");
    }

    void onDisconnect(BLEServer* pServer) {
        Serial.println("Apparaat losgekoppeld");
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
        std::string value = pCharacteristic->getValue();
        if (value.length() > 0) {
            // 串口打印接收数据,调试用
            Serial.print("Ontvangen data: ");
            Serial.println(value.c_str());
            
            // 清空屏幕,设置文本样式并显示字符串
            tft.fillScreen(currentColor);
            tft.setTextColor(TFT_WHITE);
            tft.setTextSize(2);
            tft.setCursor(10, 10);
            tft.print(value.c_str());
        }
    }
};

void setup() {
    Serial.begin(9600);
    tft.begin();
    tft.setRotation(1);
    tft.fillScreen(currentColor);
    tft.setTextColor(TFT_WHITE);
    tft.setTextSize(2);
    tft.setCursor(10,10);
    tft.print("Wachten op data...");

    BLEDevice::init("TTGO_T_Display");
    BLEServer *pServer = BLEDevice::createServer();
    pServer->setCallbacks(new MyServerCallbacks());
    BLEService *pService = pServer->createService(SERVICE_UUID);
    BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_WRITE
                                       );
    pCharacteristic->setCallbacks(new MyCallbacks());
    pService->start();
    BLEAdvertising *pAdvertising = pServer->getAdvertising();
    pAdvertising->start();
}

void loop() {
    // 无需额外操作
}

验证步骤

  1. 上传修改后的Arduino代码到TTGO T-Display,打开串口监视器。
  2. 运行修改后的React Native应用,触发字符串发送。
  3. 查看TTGO屏幕是否正确显示字符串,同时检查串口监视器的接收日志是否和发送内容一致。

内容的提问来源于stack exchange,提问作者simeon hailemariam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:55:56