无垠的广袤
华东师范大学-学术研究/教师
【萤火工场CEM5861G-M11】网页上位机设计
【萤火工场CEM5861G-M11】网页上位机设计
本文介绍了 萤火工场 CEM5861G-M11 24GHz 毫米波雷达模块的串口数据解析,并基于此设计了一款 Web 网页上位机,可通过串口连接模块并实时显示距离数据等信息。
硬件连接
CEM5816G-M11 对外可连接端子为 VCC,GND,Vo,RX,TX,可通过串口显示配置参数,目标状态信息。
CEM5816G-M11 | USB to TTL | Note |
---|---|---|
RXD (R) | TXD | Receive |
TXD (T) | RXD | Transmit |
VCC (V) | 5V or 3.3V | Power |
GND (G) | GND | Ground |
示意图
实物连接
可根据模块管脚定义图,将模块的供电 VCC,接地 GND,串口 TX,串口 RX 与串口板对应管脚连接。
串口数据解析
在完成硬件连接的基础上,打开串口调试助手,自动接收连续发送的数据
图上标注的部分为一条完整的接收信息:55 A5 00 0E 03 81 00 00 01 01 0D 00 00 00 00 00 CF 6A
- 目标ID:第8 byte 0x00
- 运动状态:第9 byte 0x01,检测到运动目标
- 目标距离:第10~11 bytes 0x01 0x0D, 大端格式,即 1D,转换成十进制为 29
- 目标信号强度:第16~17 bytes 0x00 0xCF, 转换成十进制为 207
- 校验和:第18 byte
综上:检测到运动目标,目标距离为 0.29 米,信号强度为 207 .
流程图
网页代码
新建 html 文件,添加如下代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>串口调试器 - 十六进制数据解析</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background: #f0f2f5;
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1000px;
margin: 0 auto;
}
header {
text-align: center;
margin-bottom: 20px;
padding: 15px;
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
color: white;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}
h1 {
font-size: 2rem;
margin-bottom: 5px;
}
.description {
font-size: 1rem;
opacity: 0.9;
}
.main-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
}
@media (max-width: 768px) {
.main-content {
grid-template-columns: 1fr;
}
}
.panel {
background: white;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.control-panel {
grid-column: 1 / -1;
display: flex;
flex-wrap: wrap;
gap: 10px;
align-items: center;
justify-content: space-between;
}
.chart-container {
position: relative;
height: 300px;
width: 100%;
}
button {
padding: 10px 16px;
background: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 0.9rem;
font-weight: 600;
transition: all 0.2s ease;
}
button:hover {
background: #388E3C;
transform: translateY(-2px);
}
button:disabled {
background: #cccccc;
cursor: not-allowed;
transform: none;
}
#connectBtn.connected {
background: #F44336;
}
#connectBtn.connected:hover {
background: #D32F2F;
}
.status {
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
}
.status-indicator {
width: 10px;
height: 10px;
border-radius: 50%;
background: #e0e0e0;
}
.status-indicator.connected {
background: #4CAF50;
box-shadow: 0 0 6px #4CAF50;
}
.data-display {
margin-top: 15px;
padding: 12px;
background: #f9f9f9;
border-radius: 4px;
font-family: 'Courier New', monospace;
height: 200px;
overflow-y: auto;
white-space: pre-wrap;
word-break: break-all;
font-size: 0.9rem;
}
.distance-value {
font-size: 2.2rem;
font-weight: bold;
text-align: center;
color: #2196F3;
margin: 15px 0;
}
.distance-unit {
font-size: 1.2rem;
color: #757575;
}
.panel-title {
font-size: 1.1rem;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #eee;
color: #2c3e50;
font-weight: 600;
}
.instructions {
margin-top: 15px;
padding: 12px;
background: #e3f2fd;
border-radius: 4px;
font-size: 0.85rem;
}
.instructions h3 {
margin-bottom: 8px;
color: #0b7dda;
font-size: 1rem;
}
.instructions ul {
padding-left: 18px;
}
.instructions li {
margin-bottom: 4px;
}
footer {
text-align: center;
margin-top: 25px;
padding: 15px;
color: #666;
font-size: 0.85rem;
}
.error {
color: #F44336;
font-weight: bold;
margin-top: 8px;
font-size: 0.9rem;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>萤火工场 CEM5861G-M11 网页串口调试器</h1>
<p class="description">十六进制数据解析与距离监测</p>
</header>
<div class="main-content">
<div class="panel control-panel">
<div>
<button id="connectBtn">连接串口</button>
<button id="clearBtn">清除数据</button>
</div>
<div class="status">
<div class="status-indicator" id="statusIndicator"></div>
<span id="statusText">未连接</span>
</div>
</div>
<div class="panel">
<h2 class="panel-title">实时数据</h2>
<div class="distance-value">
<span id="distanceValue">--</span>
<span class="distance-unit">厘米</span>
</div>
<div class="data-display" id="rawData">
等待数据输入...
</div>
<div id="errorMsg" class="error"></div>
</div>
<div class="panel">
<h2 class="panel-title">距离变化曲线</h2>
<div class="chart-container">
<canvas id="distanceChart"></canvas>
</div>
</div>
</div>
<footer>
<p>网页串口调试器 © 2023 | 支持Web Serial API的浏览器</p>
</footer>
</div>
<script>
// 全局变量
let port = null;
let reader = null;
let distanceData = [];
let maxDataPoints = 50;
let chart = null;
let dataBuffer = new Uint8Array(0);
// DOM元素
const connectBtn = document.getElementById('connectBtn');
const clearBtn = document.getElementById('clearBtn');
const statusIndicator = document.getElementById('statusIndicator');
const statusText = document.getElementById('statusText');
const rawDataElement = document.getElementById('rawData');
const distanceValueElement = document.getElementById('distanceValue');
const errorMsgElement = document.getElementById('errorMsg');
// 初始化图表
function initChart() {
const ctx = document.getElementById('distanceChart').getContext('2d');
chart = new Chart(ctx, {
type: 'line',
data: {
labels: Array(maxDataPoints).fill(''),
datasets: [{
label: '距离 (厘米)',
data: distanceData,
borderColor: '#2196F3',
backgroundColor: 'rgba(33, 150, 243, 0.1)',
borderWidth: 2,
pointRadius: 3,
fill: true,
tension: 0.2
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
title: { display: true, text: '距离 (厘米)' },
grid: { color: 'rgba(0, 0, 0, 0.05)' }
},
x: {
title: { display: true, text: '时间序列' },
grid: { color: 'rgba(0, 0, 0, 0.05)' }
}
},
animation: { duration: 0 }
}
});
}
// 更新图表
function updateChart(distance) {
distanceData.push(distance);
if (distanceData.length > maxDataPoints) {
distanceData.shift();
}
chart.data.datasets[0].data = distanceData;
chart.update('none');
}
// 连接串口
async function connectToSerial() {
try {
if (!navigator.serial) {
throw new Error('Web Serial API不支持此浏览器。请使用Chrome、Edge或Opera。');
}
port = await navigator.serial.requestPort();
await port.open({ baudRate: 115200 });
reader = port.readable.getReader();
// 更新UI状态
connectBtn.textContent = '断开连接';
connectBtn.classList.add('connected');
statusIndicator.classList.add('connected');
statusText.textContent = '已连接 (115200 bps)';
rawDataElement.textContent = '等待数据...';
dataBuffer = new Uint8Array(0);
errorMsgElement.textContent = "";
// 开始读取数据
readData();
} catch (error) {
errorMsgElement.textContent = '连接错误: ' + error.message;
}
}
// 读取串口数据
async function readData() {
try {
while (true) {
const { value, done } = await reader.read();
if (done) {
reader.releaseLock();
break;
}
// 处理接收到的二进制数据
processBinaryData(value);
}
} catch (error) {
errorMsgElement.textContent = '读取错误: ' + error.message;
disconnectFromSerial();
}
}
// 处理接收到的二进制数据
function processBinaryData(data) {
// 合并到缓冲区
const newBuffer = new Uint8Array(dataBuffer.length + data.length);
newBuffer.set(dataBuffer);
newBuffer.set(data, dataBuffer.length);
dataBuffer = newBuffer;
// 显示十六进制数据
let hexDisplay = "";
for (let i = 0; i < data.length; i++) {
const hex = data[i].toString(16).toUpperCase().padStart(2, '0');
hexDisplay += hex + " ";
}
rawDataElement.textContent += hexDisplay;
// 保持显示的数据量不会过大
if (rawDataElement.textContent.length > 1000) {
rawDataElement.textContent = rawDataElement.textContent.slice(-1000);
}
// 自动滚动到底部
rawDataElement.scrollTop = rawDataElement.scrollHeight;
// 查找特定数据帧 (至少18字节)
if (dataBuffer.length >= 18) {
// 查找帧头 0x55 0xA5
for (let i = 0; i <= dataBuffer.length - 18; i++) {
if (dataBuffer[i] === 0x55 && dataBuffer[i+1] === 0xA5) {
// 提取第10-11位(索引9和10)
const byte10 = dataBuffer[i+9];
const byte11 = dataBuffer[i+10];
// 合并两个字节得到距离值(大端格式)
const distance = (byte10 << 8) | byte11;
// 更新距离显示
distanceValueElement.textContent = distance;
// 更新图表
updateChart(distance);
// 从缓冲区移除已处理的数据
dataBuffer = dataBuffer.slice(i + 18);
return;
}
}
// 如果没有找到完整帧,但缓冲区太大,则清除前面部分数据
if (dataBuffer.length > 100) {
dataBuffer = dataBuffer.slice(dataBuffer.length - 18);
}
}
}
// 断开串口连接
async function disconnectFromSerial() {
if (reader) {
await reader.cancel();
reader = null;
}
if (port) {
await port.close();
port = null;
}
// 更新UI状态
connectBtn.textContent = '连接串口';
connectBtn.classList.remove('connected');
statusIndicator.classList.remove('connected');
statusText.textContent = '未连接';
}
// 清除数据
function clearData() {
rawDataElement.textContent = '';
distanceValueElement.textContent = '--';
distanceData = [];
if (chart) {
chart.data.datasets[0].data = [];
chart.update();
}
dataBuffer = new Uint8Array(0);
errorMsgElement.textContent = "";
}
// 事件监听
connectBtn.addEventListener('click', async () => {
if (port) {
await disconnectFromSerial();
} else {
await connectToSerial();
}
});
clearBtn.addEventListener('click', clearData);
// 初始化图表
window.addEventListener('load', initChart);
</script>
</body>
</html>
保存代码。
效果演示
-
串口工具连接模块和电脑;
-
使用 Edge 浏览器打开该 html 文件;
-
点击
连接串口
按钮,选择目标端口;
- 获取实时距离信息以及演化曲线;
总结
本文介绍了 萤火工场 CEM5861G-M11 24GHz 毫米波雷达模块的串口数据解析,并基于此设计了一款 Web 网页上位机,可通过串口连接模块并实时显示距离数据等信息,为相关产品的开发设计和应用提供了参考。
工程附件
web_uart_debug_distance_simple.zip
版块:
萤火工场
昨天 14:19
全部评论