使用Web Serial API读取串口RFID读卡器数据遇值未定义问题
Web Serial API读取RFID读卡器数据异常问题
问题现象
- 已成功连接读卡器,但读取数据时
value偶尔返回undefined - 控制台输出的卡号与预期不符:其他场景扫描显示卡号为
1256111915,本地控制台显示为733994570
复现代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Serial Data Reader</title> <style> body { font-family: Arial, sans-serif; } #status { font-size: 16px; } #serial-data { font-size: 18px; font-weight: bold; color: green; } </style> </head> <body> <h1>Serial Data from COM Port</h1> <button id="connectBtn">Connect to Device</button> <p id="status">Not connected</p> <p id="serial-data">Waiting for data...</p> <script> let port; let reader; let writer; let inputDone; let inputStream; let outputStream; const statusElement = document.getElementById('status'); const serialDataElement = document.getElementById('serial-data'); const connectButton = document.getElementById('connectBtn'); // Request permission to access the serial device and open it async function connectToDevice() { try { port = await navigator.serial.requestPort(); // Request the user to select a serial port console.log("Port selected:", port); // Log port information await port.open({ baudRate: 9600 }); // Open the serial port (adjust baud rate if needed) // Setup the input and output streams inputStream = port.readable; outputStream = port.writable; inputDone = inputStream.getReader(); statusElement.textContent = `Connected to ${port.getInfo().usbVendorId}:${port.getInfo().usbProductId}`; // Start reading data from the device readSerialData(); } catch (err) { console.error('Error accessing serial port:', err); statusElement.textContent = 'Error: Could not connect to device'; } } // Read data from the serial port async function readSerialData() { try { // Continuously read data from the device while (true) { const { value, done } = await inputDone.read(); // Read the data if (done) { console.log("Stream done"); break; } // Log the raw data for debugging console.log("Raw data received:", value); // Check if the value is valid, and decode if it's a valid Uint8Array if (value && value.length > 0) { const receivedData = new TextDecoder().decode(value); // Decode the data console.log("Decoded data:", receivedData); // Log the decoded data serialDataElement.textContent = receivedData.trim(); // Show the data in the frontend } else { console.warn("Empty data received"); } } } catch (err) { console.error('Error reading from the serial port:', err); statusElement.textContent = 'Error: Failed to read data'; } } // Set up the button to connect to the device connectButton.addEventListener('click', () => { statusElement.textContent = 'Connecting to device...'; connectToDevice(); }); </script> </body> </html>
相关截图
- 端口选择界面:

- 读卡器数据界面:

解决方案
1. 修复value返回undefined问题
Web Serial API的read()可能因设备空帧、流中断返回空值,优化读取逻辑:
- 使用
TextDecoderStream管道处理流,提升稳定性 - 增加流异常处理和资源释放
修改后的readSerialData函数:
async function readSerialData() { if (!inputStream) return; const textDecoder = new TextDecoderStream(); const readableStreamClosed = inputStream.pipeTo(textDecoder.writable); const reader = textDecoder.readable.getReader(); try { while (true) { const { value, done } = await reader.read(); if (done) { console.log("Stream closed"); break; } if (value?.trim()) { console.log("Received data:", value.trim()); serialDataElement.textContent = value.trim(); } } } catch (err) { console.error('Read error:', err); statusElement.textContent = 'Error: Failed to read data'; } finally { reader.releaseLock(); await readableStreamClosed.catch(() => {}); } }
2. 解决卡号显示不符问题
卡号不一致通常是数据格式/编码转换错误:
- 读卡器可能发送十六进制数据而非ASCII文本,直接解码会出错
- 部分设备存在字节序颠倒、校验位截断等情况
处理步骤:
- 先打印原始十六进制数据,确认格式:
// 替换原代码中的解码逻辑 if (value && value.length > 0) { // 输出原始十六进制数据 const hexString = Array.from(value, byte => byte.toString(16).padStart(2, '0')).join(' '); console.log("Raw hex data:", hexString); // 示例:若为4字节小端数据,转换为十进制卡号 if (value.length === 4) { const cardNumber = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); console.log("Converted card number:", cardNumber); serialDataElement.textContent = cardNumber.toString(); } else { const receivedData = new TextDecoder().decode(value); console.log("Decoded data:", receivedData); serialDataElement.textContent = receivedData.trim(); } }
- 对照读卡器官方协议,过滤起始位、结束位等无效字节后再转换。
额外建议
- 确认读卡器串口参数(波特率、数据位、停止位、奇偶校验)与代码一致,多数设备默认是
9600 8N1,补充完整端口参数:
await port.open({ baudRate: 9600, dataBits: 8, stopBits: 1, parity: 'none' });
内容的提问来源于stack exchange,提问作者Akhil
相关产品推荐
相关产品推荐

