前言
引入
本人的大一年度项目设计的网页中有串口通信的需求,在初步设计时非常想当然的认为这是可以在后端实现的,编写程序时突然反应过来,后端在服务器上怎么与串口通信(QAO)。多次与同伴,指导老师讨论无果,某天突然柳暗花明在Github发现了一个项目:Curtion/Web-SerialPort
项目在线体验:https://curtion.github.io/Web-SerialPort/
网页如图:
在这里我接了Arduino试验(烧了一个小程序进去,收到“1”LED就会闪烁),发现可行。
实现原理
怎么实现的呢?由这个项目发现了一个可以从前端与串口通信的Api:串行 - Web API 接口
Api文档介绍说:
Web 串行 API 为网站提供了一种从串行设备读取和写入串行设备的方法。这些设备可以通过串行端口连接,也可以是模拟串行端口的 USB 或蓝牙设备。
研究了一下确定可行就开始试验(Api有一些缺陷导致某些浏览器对某些方法不兼容,但是交项目是够用了🥲,Api后续大概也会完善兼容性)
代码实现
介绍
整理了一下需求,项目主要需要实现两个串口通信功能和两个辅助功能
检测串口设备
发送文本到串口
测试串口通信是否正常
上传txt文件发送到串口
下面编写一个简单的代码实现
(这里测试功能用发送“1”来代替)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Serial Port Example</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 50px;
text-align: center;
}
button {
margin: 10px;
padding: 10px 20px;
font-size: 16px;
}
#status {
margin-top: 20px;
font-size: 18px;
color: green;
}
#error {
margin-top: 20px;
font-size: 18px;
color: red;
}
#fileInput {
display: none;
}
</style>
</head>
<body>
<h1>Serial Port Example</h1>
<button id="detectButton">检测设备</button>
<button id="sendCommandButton">发送命令 "1"</button>
<button id="uploadButton">上传TXT文件</button>
<button id="sendFileButton">发送TXT文件内容</button>
<input type="file" id="fileInput" accept=".txt">
<div id="status"></div>
<div id="error"></div>
<script>
let port;
let fileContent = '';
document.getElementById('detectButton').addEventListener('click', async () => {
try {
port = await navigator.serial.requestPort();
await port.open({ baudRate: 9600 });
showStatus("成功啦");
} catch (err) {
showError("抱歉失败了", err);
}
});
document.getElementById('sendCommandButton').addEventListener('click', async () => {
try {
if (!port) {
throw new Error("没有检测到设备");
}
const writer = port.writable.getWriter();
await writer.write(new TextEncoder().encode('1'));
writer.releaseLock();
showStatus("成功啦");
} catch (err) {
showError("抱歉失败了", err);
}
});
document.getElementById('uploadButton').addEventListener('click', () => {
document.getElementById('fileInput').click();
});
document.getElementById('fileInput').addEventListener('change', (event) => {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = function(e) {
fileContent = e.target.result;
showStatus("文件上传成功");
};
reader.onerror = function(e) {
showError("文件读取失败", e);
};
reader.readAsText(file);
});
document.getElementById('sendFileButton').addEventListener('click', async () => {
try {
if (!port) {
throw new Error("没有检测到设备");
}
if (!fileContent) {
throw new Error("没有上传文件");
}
const writer = port.writable.getWriter();
await writer.write(new TextEncoder().encode(fileContent));
writer.releaseLock();
showStatus("成功啦");
} catch (err) {
showError("抱歉失败了", err);
}
});
function showStatus(message) {
document.getElementById('status').textContent = message;
document.getElementById('error').textContent = '';
}
function showError(message, error) {
document.getElementById('status').textContent = '';
document.getElementById('error').textContent = `${message}: ${error.message}`;
}
</script>
</body>
</html>
效果
界面如图(在Edge和Google浏览器上经测试功能正常):