跳转到内容
新建笔记

伺服控制系统架构设计

伺服控制系统架构图
body {
font-family: 'Microsoft YaHei', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
.header {
text-align: center;
color: white;
margin-bottom: 30px;
animation: fadeInDown 0.8s ease-out;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
}
.tabs {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 30px;
animation: fadeIn 1s ease-out;
}
.tab-btn {
padding: 12px 30px;
background: rgba(255, 255, 255, 0.9);
border: none;
border-radius: 50px;
cursor: pointer;
font-size: 16px;
font-weight: bold;
color: #667eea;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}
.tab-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0,0,0,0.15);
}
.tab-btn.active {
background: white;
color: #764ba2;
transform: scale(1.05);
}
.diagram-container {
background: white;
border-radius: 20px;
padding: 40px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
animation: fadeInUp 0.8s ease-out;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
animation: slideIn 0.5s ease-out;
}
svg {
width: 100%;
height: auto;
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));
}
.legend {
margin-top: 30px;
padding: 20px;
background: #f8f9fa;
border-radius: 10px;
border-left: 5px solid #667eea;
}
.legend h3 {
color: #333;
margin-bottom: 15px;
}
.legend-item {
display: inline-flex;
align-items: center;
margin-right: 30px;
margin-bottom: 10px;
}
.legend-color {
width: 30px;
height: 20px;
margin-right: 10px;
border-radius: 3px;
border: 1px solid #ddd;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.pulse {
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.flow {
animation: flow 3s infinite;
}
@keyframes flow {
0% { stroke-dashoffset: 0; }
100% { stroke-dashoffset: -30; }
}
</style>

🎯 伺服控制系统架构设计

基于STM32的实时伺服控制中间件方案

<div class="tabs">
<button class="tab-btn active" onclick="showTab('overview')">系统总览</button>
<button class="tab-btn" onclick="showTab('communication')">通信架构</button>
<button class="tab-btn" onclick="showTab('dataflow')">数据流</button>
<button class="tab-btn" onclick="showTab('realtime')">实时机制</button>
</div>
<div class="diagram-container">
<!-- 系统总览 -->
<div id="overview" class="tab-content active">
<svg viewBox="0 0 1200 700">
<!-- 背景网格 -->
<defs>
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="#e0e0e0" stroke-width="1"/>
</pattern>
<!-- 渐变定义 -->
<linearGradient id="pcGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" />
<stop offset="100%" />
</linearGradient>
<linearGradient id="stm32Grad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" />
<stop offset="100%" />
</linearGradient>
<linearGradient id="servoGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" />
<stop offset="100%" />
</linearGradient>
</defs>
<rect width="1200" height="700" fill="url(#grid)" />
<!-- 上位机 -->
<g transform="translate(100, 100)">
<rect x="0" y="0" width="200" height="150" rx="15" fill="url(#pcGrad)" stroke="#4CAF50" stroke-width="3"/>
<text x="100" y="40" text-anchor="middle" fill="white" font-size="20" font-weight="bold">上位机</text>
<text x="100" y="70" text-anchor="middle" fill="white" font-size="14">控制软件</text>
<text x="100" y="90" text-anchor="middle" fill="white" font-size="12">• 路径规划</text>
<text x="100" y="110" text-anchor="middle" fill="white" font-size="12">• 状态监控</text>
<text x="100" y="130" text-anchor="middle" fill="white" font-size="12">• 参数配置</text>
</g>
<!-- STM32中间件 -->
<g transform="translate(500, 50)">
<rect x="0" y="0" width="300" height="600" rx="15" fill="url(#stm32Grad)" stroke="#2196F3" stroke-width="3"/>
<text x="150" y="30" text-anchor="middle" fill="white" font-size="22" font-weight="bold">STM32 控制器</text>
<!-- 命令处理模块 -->
<rect x="20" y="60" width="260" height="80" rx="10" fill="rgba(255,255,255,0.2)" stroke="white" stroke-width="2"/>
<text x="150" y="85" text-anchor="middle" fill="white" font-size="14" font-weight="bold">命令处理引擎</text>
<text x="150" y="105" text-anchor="middle" fill="white" font-size="12">• 优先级队列管理</text>
<text x="150" y="125" text-anchor="middle" fill="white" font-size="12">• 紧急停止处理</text>
<!-- 通信管理 -->
<rect x="20" y="160" width="260" height="80" rx="10" fill="rgba(255,255,255,0.2)" stroke="white" stroke-width="2"/>
<text x="150" y="185" text-anchor="middle" fill="white" font-size="14" font-weight="bold">通信管理器</text>
<text x="150" y="205" text-anchor="middle" fill="white" font-size="12">• RS232 (上位机)</text>
<text x="150" y="225" text-anchor="middle" fill="white" font-size="12">• Modbus RTU (伺服)</text>
<!-- 状态缓存 -->
<rect x="20" y="260" width="260" height="80" rx="10" fill="rgba(255,255,255,0.2)" stroke="white" stroke-width="2"/>
<text x="150" y="285" text-anchor="middle" fill="white" font-size="14" font-weight="bold">状态缓存系统</text>
<text x="150" y="305" text-anchor="middle" fill="white" font-size="12">• 10ms定时更新</text>
<text x="150" y="325" text-anchor="middle" fill="white" font-size="12">• 实时状态监控</text>
<!-- 安全机制 -->
<rect x="20" y="360" width="260" height="80" rx="10" fill="rgba(255,255,255,0.2)" stroke="white" stroke-width="2"/>
<text x="150" y="385" text-anchor="middle" fill="white" font-size="14" font-weight="bold">安全保护机制</text>
<text x="150" y="405" text-anchor="middle" fill="white" font-size="12">• 看门狗监控</text>
<text x="150" y="425" text-anchor="middle" fill="white" font-size="12">• 异常自动处理</text>
<!-- DMA控制 -->
<rect x="20" y="460" width="260" height="80" rx="10" fill="rgba(255,255,255,0.2)" stroke="white" stroke-width="2"/>
<text x="150" y="485" text-anchor="middle" fill="white" font-size="14" font-weight="bold">DMA传输控制</text>
<text x="150" y="505" text-anchor="middle" fill="white" font-size="12">• 零CPU占用传输</text>
<text x="150" y="525" text-anchor="middle" fill="white" font-size="12">• 双缓冲机制</text>
</g>
<!-- 伺服驱动器 -->
<g transform="translate(900, 100)">
<rect x="0" y="0" width="200" height="150" rx="15" fill="url(#servoGrad)" stroke="#FF9800" stroke-width="3"/>
<text x="100" y="40" text-anchor="middle" fill="white" font-size="20" font-weight="bold">伺服驱动器</text>
<text x="100" y="70" text-anchor="middle" fill="white" font-size="14">Modbus从站</text>
<text x="100" y="90" text-anchor="middle" fill="white" font-size="12">• 位置控制</text>
<text x="100" y="110" text-anchor="middle" fill="white" font-size="12">• 速度控制</text>
<text x="100" y="130" text-anchor="middle" fill="white" font-size="12">• 状态反馈</text>
</g>
<!-- 连接线 -->
<!-- RS232连接 -->
<g>
<path d="M 300 175 L 500 175" stroke="#4CAF50" stroke-width="4" fill="none"
stroke-dasharray="10,5" class="flow"/>
<text x="400" y="165" text-anchor="middle" fill="#4CAF50" font-size="14" font-weight="bold">RS232</text>
<text x="400" y="195" text-anchor="middle" fill="#666" font-size="12">115200bps</text>
</g>
<!-- Modbus连接 -->
<g>
<path d="M 800 175 L 900 175" stroke="#FF9800" stroke-width="4" fill="none"
stroke-dasharray="10,5" class="flow"/>
<text x="850" y="165" text-anchor="middle" fill="#FF9800" font-size="14" font-weight="bold">Modbus RTU</text>
<text x="850" y="195" text-anchor="middle" fill="#666" font-size="12">19200bps</text>
</g>
<!-- 关键特性标注 -->
<g transform="translate(100, 400)">
<rect x="0" y="0" width="1000" height="200" rx="15" fill="rgba(255,255,255,0.95)" stroke="#ddd" stroke-width="2"/>
<text x="500" y="30" text-anchor="middle" fill="#333" font-size="18" font-weight="bold">🚀 系统关键特性</text>
<g transform="translate(50, 60)">
<circle cx="10" cy="10" r="5" fill="#4CAF50"/>
<text x="25" y="15" fill="#333" font-size="14">响应时间 &lt; 5ms</text>
</g>
<g transform="translate(250, 60)">
<circle cx="10" cy="10" r="5" fill="#2196F3"/>
<text x="25" y="15" fill="#333" font-size="14">双队列优先级调度</text>
</g>
<g transform="translate(480, 60)">
<circle cx="10" cy="10" r="5" fill="#FF9800"/>
<text x="25" y="15" fill="#333" font-size="14">DMA零拷贝传输</text>
</g>
<g transform="translate(700, 60)">
<circle cx="10" cy="10" r="5" fill="#9C27B0"/>
<text x="25" y="15" fill="#333" font-size="14">自动故障恢复</text>
</g>
<g transform="translate(50, 100)">
<circle cx="10" cy="10" r="5" fill="#E91E63"/>
<text x="25" y="15" fill="#333" font-size="14">状态缓存10ms更新</text>
</g>
<g transform="translate(250, 100)">
<circle cx="10" cy="10" r="5" fill="#00BCD4"/>
<text x="25" y="15" fill="#333" font-size="14">CRC16数据校验</text>
</g>
<g transform="translate(480, 100)">
<circle cx="10" cy="10" r="5" fill="#795548"/>
<text x="25" y="15" fill="#333" font-size="14">紧急停止0延迟</text>
</g>
<g transform="translate(700, 100)">
<circle cx="10" cy="10" r="5" fill="#607D8B"/>
<text x="25" y="15" fill="#333" font-size="14">报警主动上报</text>
</g>
<text x="50" y="160" fill="#666" font-size="12">• 支持最多32条命令缓冲</text>
<text x="350" y="160" fill="#666" font-size="12">• 批量寄存器读写优化</text>
<text x="650" y="160" fill="#666" font-size="12">• 看门狗超时保护</text>
</g>
</svg>
</div>
<!-- 通信架构 -->
<div id="communication" class="tab-content">
<svg viewBox="0 0 1200 800">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto" markerUnits="strokeWidth">
<path d="M0,0 L0,6 L9,3 z" fill="#333" />
</marker>
</defs>
<!-- OSI模型层次 -->
<text x="600" y="40" text-anchor="middle" fill="#333" font-size="24" font-weight="bold">通信协议栈架构</text>
<!-- 应用层 -->
<g transform="translate(100, 80)">
<rect x="0" y="0" width="1000" height="80" rx="10" fill="#4CAF50" opacity="0.8"/>
<text x="50" y="45" fill="white" font-size="18" font-weight="bold">应用层</text>
<rect x="200" y="15" width="180" height="50" rx="5" fill="white"/>
<text x="290" y="35" text-anchor="middle" fill="#333" font-size="14">上位机控制软件</text>
<text x="290" y="55" text-anchor="middle" fill="#666" font-size="12">命令生成/响应处理</text>
<rect x="450" y="15" width="180" height="50" rx="5" fill="white"/>
<text x="540" y="35" text-anchor="middle" fill="#333" font-size="14">STM32业务逻辑</text>
<text x="540" y="55" text-anchor="middle" fill="#666" font-size="12">命令解析/执行</text>
<rect x="700" y="15" width="180" height="50" rx="5" fill="white"/>
<text x="790" y="35" text-anchor="middle" fill="#333" font-size="14">伺服控制逻辑</text>
<text x="790" y="55" text-anchor="middle" fill="#666" font-size="12">运动控制算法</text>
</g>
<!-- 协议层 -->
<g transform="translate(100, 180)">
<rect x="0" y="0" width="1000" height="80" rx="10" fill="#2196F3" opacity="0.8"/>
<text x="50" y="45" fill="white" font-size="18" font-weight="bold">协议层</text>
<rect x="200" y="15" width="180" height="50" rx="5" fill="white"/>
<text x="290" y="35" text-anchor="middle" fill="#333" font-size="14">自定义协议</text>
<text x="290" y="55" text-anchor="middle" fill="#666" font-size="12">Header+CMD+Data+CRC</text>
<rect x="450" y="15" width="180" height="50" rx="5" fill="white"/>
<text x="540" y="35" text-anchor="middle" fill="#333" font-size="14">协议转换器</text>
<text x="540" y="55" text-anchor="middle" fill="#666" font-size="12">双向协议转换</text>
<rect x="700" y="15" width="180" height="50" rx="5" fill="white"/>
<text x="790" y="35" text-anchor="middle" fill="#333" font-size="14">Modbus协议</text>
<text x="790" y="55" text-anchor="middle" fill="#666" font-size="12">功能码03/06/10</text>
</g>
<!-- 传输层 -->
<g transform="translate(100, 280)">
<rect x="0" y="0" width="1000" height="80" rx="10" fill="#FF9800" opacity="0.8"/>
<text x="50" y="45" fill="white" font-size="18" font-weight="bold">传输层</text>
<rect x="200" y="15" width="180" height="50" rx="5" fill="white"/>
<text x="290" y="35" text-anchor="middle" fill="#333" font-size="14">串口缓冲管理</text>
<text x="290" y="55" text-anchor="middle" fill="#666" font-size="12">环形缓冲区</text>
<rect x="450" y="15" width="180" height="50" rx="5" fill="white"/>
<text x="540" y="35" text-anchor="middle" fill="#333" font-size="14">DMA控制器</text>
<text x="540" y="55" text-anchor="middle" fill="#666" font-size="12">双缓冲/中断管理</text>
<rect x="700" y="15" width="180" height="50" rx="5" fill="white"/>
<text x="790" y="35" text-anchor="middle" fill="#333" font-size="14">RTU帧管理</text>
<text x="790" y="55" text-anchor="middle" fill="#666" font-size="12">3.5字符超时检测</text>
</g>
<!-- 物理层 -->
<g transform="translate(100, 380)">
<rect x="0" y="0" width="1000" height="80" rx="10" fill="#9C27B0" opacity="0.8"/>
<text x="50" y="45" fill="white" font-size="18" font-weight="bold">物理层</text>
<rect x="200" y="15" width="180" height="50" rx="5" fill="white"/>
<text x="290" y="35" text-anchor="middle" fill="#333" font-size="14">RS232接口</text>
<text x="290" y="55" text-anchor="middle" fill="#666" font-size="12">115200bps 8N1</text>
<rect x="450" y="15" width="180" height="50" rx="5" fill="white"/>
<text x="540" y="35" text-anchor="middle" fill="#333" font-size="14">UART1 + UART2</text>
<text x="540" y="55" text-anchor="middle" fill="#666" font-size="12">硬件流控可选</text>
<rect x="700" y="15" width="180" height="50" rx="5" fill="white"/>
<text x="790" y="35" text-anchor="middle" fill="#333" font-size="14">RS485接口</text>
<text x="790" y="55" text-anchor="middle" fill="#666" font-size="12">19200bps RTU</text>
</g>
<!-- 数据包格式展示 -->
<g transform="translate(100, 500)">
<rect x="0" y="0" width="1000" height="250" rx="15" fill="#f5f5f5" stroke="#ddd" stroke-width="2"/>
<text x="500" y="30" text-anchor="middle" fill="#333" font-size="18" font-weight="bold">数据包格式详解</text>
<!-- 上位机协议包 -->
<text x="50" y="70" fill="#333" font-size="14" font-weight="bold">上位机→STM32 命令包:</text>
<g transform="translate(50, 80)">
<rect x="0" y="0" width="80" height="40" fill="#4CAF50" stroke="#333"/>
<text x="40" y="25" text-anchor="middle" fill="white" font-size="12">Header</text>
<text x="40" y="55" text-anchor="middle" fill="#666" font-size="10">0xAA55</text>
<rect x="80" y="0" width="60" height="40" fill="#2196F3" stroke="#333"/>
<text x="110" y="25" text-anchor="middle" fill="white" font-size="12">CMD</text>
<text x="110" y="55" text-anchor="middle" fill="#666" font-size="10">1 Byte</text>
<rect x="140" y="0" width="60" height="40" fill="#FF9800" stroke="#333"/>
<text x="170" y="25" text-anchor="middle" fill="white" font-size="12">Priority</text>
<text x="170" y="55" text-anchor="middle" fill="#666" font-size="10">1 Byte</text>
<rect x="200" y="0" width="80" height="40" fill="#9C27B0" stroke="#333"/>
<text x="240" y="25" text-anchor="middle" fill="white" font-size="12">Sequence</text>
<text x="240" y="55" text-anchor="middle" fill="#666" font-size="10">2 Bytes</text>
<rect x="280" y="0" width="200" height="40" fill="#607D8B" stroke="#333"/>
<text x="380" y="25" text-anchor="middle" fill="white" font-size="12">Data[0-16]</text>
<text x="380" y="55" text-anchor="middle" fill="#666" font-size="10">0-32 Bytes</text>
<rect x="480" y="0" width="80" height="40" fill="#E91E63" stroke="#333"/>
<text x="520" y="25" text-anchor="middle" fill="white" font-size="12">CRC16</text>
<text x="520" y="55" text-anchor="middle" fill="#666" font-size="10">2 Bytes</text>
</g>
<!-- Modbus协议包 -->
<text x="50" y="160" fill="#333" font-size="14" font-weight="bold">STM32→伺服 Modbus包:</text>
<g transform="translate(50, 170)">
<rect x="0" y="0" width="80" height="40" fill="#FF5722" stroke="#333"/>
<text x="40" y="25" text-anchor="middle" fill="white" font-size="12">Address</text>
<text x="40" y="55" text-anchor="middle" fill="#666" font-size="10">1 Byte</text>
<rect x="80" y="0" width="80" height="40" fill="#3F51B5" stroke="#333"/>
<text x="120" y="25" text-anchor="middle" fill="white" font-size="12">Function</text>
<text x="120" y="55" text-anchor="middle" fill="#666" font-size="10">1 Byte</text>
<rect x="160" y="0" width="100" height="40" fill="#009688" stroke="#333"/>
<text x="210" y="25" text-anchor="middle" fill="white" font-size="12">Reg Addr</text>
<text x="210" y="55" text-anchor="middle" fill="#666" font-size="10">2 Bytes</text>
<rect x="260" y="0" width="100" height="40" fill="#CDDC39" stroke="#333"/>
<text x="310" y="25" text-anchor="middle" fill="black" font-size="12">Reg Count</text>
<text x="310" y="55" text-anchor="middle" fill="#666" font-size="10">2 Bytes</text>
<rect x="360" y="0" width="120" height="40" fill="#795548" stroke="#333"/>
<text x="420" y="25" text-anchor="middle" fill="white" font-size="12">Data</text>
<text x="420" y="55" text-anchor="middle" fill="#666" font-size="10">N Bytes</text>
<rect x="480" y="0" width="80" height="40" fill="#FF9800" stroke="#333"/>
<text x="520" y="25" text-anchor="middle" fill="white" font-size="12">CRC16</text>
<text x="520" y="55" text-anchor="middle" fill="#666" font-size="10">2 Bytes</text>
</g>
</g>
</svg>
</div>
<!-- 数据流 -->
<div id="dataflow" class="tab-content">
<svg viewBox="0 0 1200 900">
<defs>
<marker id="arrow2" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto" markerUnits="strokeWidth">
<path d="M0,0 L0,6 L9,3 z" fill="#2196F3" />
</marker>
</defs>
<text x="600" y="40" text-anchor="middle" fill="#333" font-size="24" font-weight="bold">系统数据流向图</text>
<!-- 正常命令流 -->
<g transform="translate(50, 80)">
<rect x="0" y="0" width="500" height="350" rx="10" fill="#E3F2FD" stroke="#2196F3" stroke-width="2"/>
<text x="250" y="30" text-anchor="middle" fill="#1976D2" font-size="18" font-weight="bold">正常命令流</text>
<!-- 流程步骤 -->
<rect x="30" y="50" width="150" height="40" rx="5" fill="#4CAF50"/>
<text x="105" y="75" text-anchor="middle" fill="white" font-size="14">1. 上位机发送命令</text>
<path d="M 105 90 L 105 120" stroke="#333" stroke-width="2" marker-end="url(#arrow2)"/>
<rect x="30" y="130" width="150" height="40" rx="5" fill="#2196F3"/>
<text x="105" y="155" text-anchor="middle" fill="white" font-size="14">2. RS232接收中断</text>
<path d="M 105 170 L 105 200" stroke="#333" stroke-width="2" marker-end="url(#arrow2)"/>
<rect x="30" y="210" width="150" height="40" rx="5" fill="#FF9800"/>
<text x="105" y="235" text-anchor="middle" fill="white" font-size="14">3. 命令入队(优先级)</text>
<path d="M 180 230 L 250 230" stroke="#333" stroke-width="2" marker-end="url(#arrow2)"/>
<rect x="250" y="210" width="150" height="40" rx="5" fill="#9C27B0"/>
<text x="325" y="235" text-anchor="middle" fill="white" font-size="14">4. 命令解析执行</text>
<path d="M 325 250 L 325 280" stroke="#333" stroke-width="2" marker-end="url(#arrow2)"/>
<rect x="250" y="290" width="150" height="40" rx="5" fill="#E91E63"/>
<text x="325" y="315" text-anchor="middle" fill="white" font-size="14">5. Modbus请求</text>
<path d="M 325 330 L 325 360" stroke="#333" stroke-width="2" marker-end="url(#arrow2)"/>
<rect x="250" y="370" width="150" height="40" rx="5" fill="#00BCD4"/>
<text x="325" y="395" text-anchor="middle" fill="white" font-size="14">6. 响应返回上位机</text>
</g>
<!-- 紧急停止流 -->
<g transform="translate(600, 80)">
<rect x="0" y="0" width="500" height="350" rx="10" fill="#FFEBEE" stroke="#F44336" stroke-width="2"/>
<text x="250" y="30" text-anchor="middle" fill="#D32F2F" font-size="18" font-weight="bold">紧急停止流</text>
<rect x="150" y="50" width="200" height="40" rx="5" fill="#F44336"/>
<text x="250" y="75" text-anchor="middle" fill="white" font-size="14">紧急停止命令(Priority=0)</text>
<path d="M 250 90 L 250 120" stroke="#F44336" stroke-width="3" marker-end="url(#arrow2)"/>
<rect x="150" y="130" width="200" height="40" rx="5" fill="#FF5722"/>
<text x="250" y="155" text-anchor="middle" fill="white" font-size="14">直接执行(跳过队列)</text>
<path d="M 250 170 L 250 200" stroke="#F44336" stroke-width="3" marker-end="url(#arrow2)"/>
<rect x="150" y="210" width="200" height="40" rx="5" fill="#FF7043"/>
<text x="250" y="235" text-anchor="middle" fill="white" font-size="14">立即发送停止命令到伺服</text>
<path d="M 250 250 L 250 280" stroke="#F44336" stroke-width="3" marker-end="url(#arrow2)"/>
<rect x="150" y="290" width="200" height="40" rx="5" fill="#FF8A65"/>
<text x="250" y="315" text-anchor="middle" fill="white" font-size="14">清空所有待执行队列</text>
<text x="250" y="370" text-anchor="middle" fill="#F44336" font-size="16" font-weight="bold">⚡ 总耗时 &lt; 1ms</text>
</g>
<!-- 状态更新流 -->
<g transform="translate(50, 480)">
<rect x="0" y="0" width="1100" height="350" rx="10" fill="#F3E5F5" stroke="#9C27B0" stroke-width="2"/>
<text x="550" y="30" text-anchor="middle" fill="#7B1FA2" font-size="18" font-weight="bold">周期性状态更新流 (10ms Timer)</text>
<!-- 轮询序列 -->
<g transform="translate(50, 60)">
<rect x="0" y="0" width="120" height="60" rx="5" fill="#9C27B0"/>
<text x="60" y="25" text-anchor="middle" fill="white" font-size="12">T=0ms</text>
<text x="60" y="45" text-anchor="middle" fill="white" font-size="12">读状态字</text>
<path d="M 120 30 L 180 30" stroke="#9C27B0" stroke-width="2" marker-end="url(#arrow2)"/>
<rect x="180" y="0" width="120" height="60" rx="5" fill="#AB47BC"/>
<text x="240" y="25" text-anchor="middle" fill="white" font-size="12">T=10ms</text>
<text x="240" y="45" text-anchor="middle" fill="white" font-size="12">读报警代码</text>
<path d="M 300 30 L 360 30" stroke="#9C27B0" stroke-width="2" marker-end="url(#arrow2)"/>
<rect x="360" y="0" width="120" height="60" rx="5" fill="#BA68C8"/>
<text x="420" y="25" text-anchor="middle" fill="white" font-size="12">T=20ms</text>
<text x="420" y="45" text-anchor="middle" fill="white" font-size="12">读实际位置</text>
<path d="M 480 30 L 540 30" stroke="#9C27B0" stroke-width="2" marker-end="url(#arrow2)"/>
<rect x="540" y="0" width="120" height="60" rx="5" fill="#CE93D8"/>
<text x="600" y="25" text-anchor="middle" fill="white" font-size="12">T=30ms</text>
<text x="600" y="45" text-anchor="middle" fill="white" font-size="12">读实际速度</text>
<path d="M 660 30 L 720 30" stroke="#9C27B0" stroke-width="2" marker-end="url(#arrow2)"/>
<rect x="720" y="0" width="120" height="60" rx="5" fill="#E1BEE7"/>
<text x="780" y="25" text-anchor="middle" fill="#333" font-size="12">T=40ms</text>
<text x="780" y="45" text-anchor="middle" fill="#333" font-size="12">循环重启</text>
</g>
<!-- 缓存更新 -->
<g transform="translate(200, 150)">
<rect x="0" y="0" width="700" height="100" rx="10" fill="white" stroke="#9C27B0" stroke-width="2"/>
<text x="350" y="30" text-anchor="middle" fill="#9C27B0" font-size="16" font-weight="bold">状态缓存区</text>
<g transform="translate(50, 40)">
<rect x="0" y="0" width="120" height="40" rx="5" fill="#E8EAF6"/>
<text x="60" y="25" text-anchor="middle" fill="#333" font-size="12">status_word</text>
<rect x="140" y="0" width="120" height="40" rx="5" fill="#E8EAF6"/>
<text x="200" y="25" text-anchor="middle" fill="#333" font-size="12">alarm_code</text>
<rect x="280" y="0" width="120" height="40" rx="5" fill="#E8EAF6"/>
<text x="340" y="25" text-anchor="middle" fill="#333" font-size="12">actual_position</text>
<rect x="420" y="0" width="120" height="40" rx="5" fill="#E8EAF6"/>
<text x="480" y="25" text-anchor="middle" fill="#333" font-size="12">actual_speed</text>
</g>
</g>
<!-- 报警通知 -->
<g transform="translate(350, 270)">
<rect x="0" y="0" width="400" height="50" rx="25" fill="#FF5722" class="pulse"/>
<text x="200" y="32" text-anchor="middle" fill="white" font-size="14" font-weight="bold">
⚠️ 检测到报警时,立即推送通知给上位机
</text>
</g>
</g>
</svg>
</div>
<!-- 实时机制 -->
<div id="realtime" class="tab-content">
<svg viewBox="0 0 1200 900">
<text x="600" y="40" text-anchor="middle" fill="#333" font-size="24" font-weight="bold">实时性保证机制</text>
<!-- 中断优先级 -->
<g transform="translate(50, 80)">
<rect x="0" y="0" width="500" height="300" rx="10" fill="#E8F5E9" stroke="#4CAF50" stroke-width="2"/>
<text x="250" y="30" text-anchor="middle" fill="#2E7D32" font-size="18" font-weight="bold">中断优先级配置</text>
<g transform="translate(30, 60)">
<rect x="0" y="0" width="440" height="40" rx="5" fill="#F44336"/>
<text x="20" y="25" fill="white" font-size="14">优先级0: 紧急停止外部中断 (EXTI)</text>
<text x="420" y="25" text-anchor="end" fill="white" font-size="12">最高</text>
</g>
<g transform="translate(30, 110)">
<rect x="0" y="0" width="400" height="40" rx="5" fill="#FF9800"/>
<text x="20" y="25" fill="white" font-size="14">优先级1: UART1 RX DMA (上位机命令)</text>
</g>
<g transform="translate(30, 160)">
<rect x="0" y="0" width="360" height="40" rx="5" fill="#2196F3"/>
<text x="20" y="25" fill="white" font-size="14">优先级2: UART2 RX DMA (Modbus响应)</text>
</g>
<g transform="translate(30, 210)">
<rect x="0" y="0" width="320" height="40" rx="5" fill="#9C27B0"/>
<text x="20" y="25" fill="white" font-size="14">优先级3: TIM3 定时器 (状态更新)</text>
<text x="300" y="25" text-anchor="end" fill="white" font-size="12">最低</text>
</g>
</g>
<!-- DMA配置 -->
<g transform="translate(600, 80)">
<rect x="0" y="0" width="500" height="300" rx="10" fill="#E1F5FE" stroke="#03A9F4" stroke-width="2"/>
<text x="250" y="30" text-anchor="middle" fill="#0277BD" font-size="18" font-weight="bold">DMA优化配置</text>
<g transform="translate(50, 60)">
<rect x="0" y="0" width="400" height="60" rx="5" fill="white" stroke="#03A9F4"/>
<text x="200" y="25" text-anchor="middle" fill="#333" font-size="14" font-weight="bold">UART1 RX DMA (通道4)</text>
<text x="200" y="45" text-anchor="middle" fill="#666" font-size="12">• 循环模式 • 半传输/全传输中断</text>
</g>
<g transform="translate(50, 130)">
<rect x="0" y="0" width="400" height="60" rx="5" fill="white" stroke="#03A9F4"/>
<text x="200" y="25" text-anchor="middle" fill="#333" font-size="14" font-weight="bold">UART2 TX/RX DMA (通道5/6)</text>
<text x="200" y="45" text-anchor="middle" fill="#666" font-size="12">• 正常模式 • 传输完成中断</text>
</g>
<g transform="translate(50, 200)">
<rect x="0" y="0" width="400" height="60" rx="5" fill="white" stroke="#03A9F4"/>
<text x="200" y="25" text-anchor="middle" fill="#333" font-size="14" font-weight="bold">双缓冲机制</text>
<text x="200" y="45" text-anchor="middle" fill="#666" font-size="12">• 乒乓缓冲 • 零拷贝切换</text>
</g>
</g>
<!-- 时序图 -->
<g transform="translate(50, 420)">
<rect x="0" y="0" width="1100" height="400" rx="10" fill="#FFF3E0" stroke="#FF9800" stroke-width="2"/>
<text x="550" y="30" text-anchor="middle" fill="#E65100" font-size="18" font-weight="bold">典型命令执行时序</text>
<!-- 时间轴 -->
<line x1="100" y1="100" x2="1000" y2="100" stroke="#333" stroke-width="2"/>
<!-- 时间刻度 -->
<g transform="translate(100, 100)">
<circle cx="0" cy="0" r="5" fill="#333"/>
<text x="0" y="-10" text-anchor="middle" fill="#333" font-size="12">0ms</text>
<text x="0" y="25" text-anchor="middle" fill="#666" font-size="11">命令接收</text>
<circle cx="150" cy="0" r="5" fill="#4CAF50"/>
<text x="150" y="-10" text-anchor="middle" fill="#333" font-size="12">0.1ms</text>
<text x="150" y="25" text-anchor="middle" fill="#666" font-size="11">DMA传输</text>
<rect x="130" y="40" width="40" height="30" rx="5" fill="#4CAF50" opacity="0.3"/>
<circle cx="300" cy="0" r="5" fill="#2196F3"/>
<text x="300" y="-10" text-anchor="middle" fill="#333" font-size="12">0.5ms</text>
<text x="300" y="25" text-anchor="middle" fill="#666" font-size="11">命令解析</text>
<rect x="280" y="40" width="40" height="30" rx="5" fill="#2196F3" opacity="0.3"/>
<circle cx="450" cy="0" r="5" fill="#FF9800"/>
<text x="450" y="-10" text-anchor="middle" fill="#333" font-size="12">1ms</text>
<text x="450" y="25" text-anchor="middle" fill="#666" font-size="11">Modbus发送</text>
<rect x="430" y="40" width="40" height="30" rx="5" fill="#FF9800" opacity="0.3"/>
<circle cx="600" cy="0" r="5" fill="#9C27B0"/>
<text x="600" y="-10" text-anchor="middle" fill="#333" font-size="12">3ms</text>
<text x="600" y="25" text-anchor="middle" fill="#666" font-size="11">伺服响应</text>
<rect x="580" y="40" width="40" height="30" rx="5" fill="#9C27B0" opacity="0.3"/>
<circle cx="750" cy="0" r="5" fill="#E91E63"/>
<text x="750" y="-10" text-anchor="middle" fill="#333" font-size="12">3.5ms</text>
<text x="750" y="25" text-anchor="middle" fill="#666" font-size="11">结果处理</text>
<rect x="730" y="40" width="40" height="30" rx="5" fill="#E91E63" opacity="0.3"/>
<circle cx="900" cy="0" r="5" fill="#00BCD4"/>
<text x="900" y="-10" text-anchor="middle" fill="#333" font-size="12">4ms</text>
<text x="900" y="25" text-anchor="middle" fill="#666" font-size="11">响应上位机</text>
<rect x="880" y="40" width="40" height="30" rx="5" fill="#00BCD4" opacity="0.3"/>
</g>
<!-- 性能指标 -->
<g transform="translate(100, 250)">
<rect x="0" y="0" width="900" height="120" rx="10" fill="white" stroke="#FF9800"/>
<text x="450" y="30" text-anchor="middle" fill="#FF9800" font-size="16" font-weight="bold">🎯 关键性能指标</text>
<g transform="translate(50, 50)">
<text x="0" y="20" fill="#333" font-size="14">• 命令响应延迟: &lt;5ms (典型值4ms)</text>
<text x="0" y="45" fill="#333" font-size="14">• 紧急停止延迟: &lt;1ms (硬件中断)</text>
<text x="0" y="70" fill="#333" font-size="14">• 状态更新周期: 10ms (可调)</text>
<text x="400" y="20" fill="#333" font-size="14">• DMA传输效率: 100% (零CPU占用)</text>
<text x="400" y="45" fill="#333" font-size="14">• 命令吞吐量: &gt;200条/秒</text>
<text x="400" y="70" fill="#333" font-size="14">• 通信成功率: &gt;99.95%</text>
</g>
</g>
</g>
</svg>
</div>
</div>
<div class="legend">
<h3>📋 系统说明</h3>
<div class="legend-item">
<div class="legend-color"></div>
上位机相关
</div>
<div class="legend-item">
<div class="legend-color"></div>
STM32处理
</div>
<div class="legend-item">
<div class="legend-color"></div>
伺服通信
</div>
<div class="legend-item">
<div class="legend-color"></div>
实时机制
</div>
</div>
</div>
<script>
function showTab(tabName) {
// 隐藏所有标签页
const tabs = document.querySelectorAll('.tab-content');
tabs.forEach(tab => {
tab.classList.remove('active');
});
// 显示选中的标签页
document.getElementById(tabName).classList.add('active');
// 更新按钮状态
const btns = document.querySelectorAll('.tab-btn');
btns.forEach(btn => {
btn.classList.remove('active');
});
event.target.classList.add('active');
}
// 添加动画效果
document.addEventListener('DOMContentLoaded', function() {
// SVG元素渐入效果
const svgElements = document.querySelectorAll('svg rect, svg circle, svg text');
svgElements.forEach((element, index) => {
element.style.opacity = '0';
element.style.animation = `fadeIn 0.5s ease-out ${index * 0.01}s forwards`;
});
});
</script>

根据你的需求,有几种方案可以实现上位机通过单片机控制伺服驱动器。我推荐Modbus透传方案,这是最优雅和实用的解决方案:

推荐方案:Modbus透传 + 仲裁控制

跳转到“推荐方案:Modbus透传 + 仲裁控制”
上位机 <--RS232--> STM32 <--Modbus RTU--> 伺服驱动器

单片机作为Modbus网关,将上位机的Modbus命令透传给伺服驱动器:

// HAL实现示例
typedef enum {
CONTROL_MODE_LOCAL, // 单片机控制
CONTROL_MODE_REMOTE, // 上位机控制
CONTROL_MODE_MIXED // 混合控制
} control_mode_t;
typedef struct {
control_mode_t mode;
uint32_t last_pc_command_time; // 上位机最后命令时间
uint8_t pc_timeout_ms; // 超时时间
} modbus_gateway_t;
// 透传处理函数
void modbus_gateway_process(void) {
uint8_t rs232_buffer[256];
uint8_t modbus_response[256];
// 接收上位机命令
if (HAL_UART_Receive(&huart_rs232, rs232_buffer, sizeof(rs232_buffer), 10) == HAL_OK) {
gateway.last_pc_command_time = HAL_GetTick();
gateway.mode = CONTROL_MODE_REMOTE;
// 验证并转发Modbus命令
if (validate_modbus_frame(rs232_buffer)) {
// 发送到伺服驱动器
HAL_UART_Transmit(&huart_modbus, rs232_buffer, get_frame_length(rs232_buffer), 100);
// 接收伺服响应
if (HAL_UART_Receive(&huart_modbus, modbus_response, sizeof(modbus_response), 100) == HAL_OK) {
// 回传给上位机
HAL_UART_Transmit(&huart_rs232, modbus_response, get_frame_length(modbus_response), 100);
}
}
}
// 检查上位机通信超时
if (HAL_GetTick() - gateway.last_pc_command_time > gateway.pc_timeout_ms) {
gateway.mode = CONTROL_MODE_LOCAL;
}
}
typedef struct {
uint16_t address;
uint16_t local_value;
uint16_t remote_value;
uint8_t priority; // 0=local, 1=remote
} register_control_t;
// 关键寄存器仲裁
register_control_t critical_registers[] = {
{0x60E, 0, 0, 0}, // 使能信号 - 本地优先
{0x61A, 0, 0, 1}, // G-初始角速度 - 远程优先
{0x626, 0, 0, 1}, // C-电子位置 - 远程优先
};
void arbitrate_control(void) {
for (int i = 0; i < sizeof(critical_registers)/sizeof(register_control_t); i++) {
if (gateway.mode == CONTROL_MODE_REMOTE && critical_registers[i].priority == 1) {
// 使用远程值
write_servo_register(critical_registers[i].address, critical_registers[i].remote_value);
} else {
// 使用本地值
write_servo_register(critical_registers[i].address, critical_registers[i].local_value);
}
}
}
// 安全检查函数
HAL_StatusTypeDef validate_modbus_command(uint8_t* frame) {
uint16_t address = (frame[2] << 8) | frame[3];
uint16_t value = (frame[4] << 8) | frame[5];
// 检查关键安全参数
switch(address) {
case 0x60E: // 使能控制
if (get_emergency_stop_status()) {
return HAL_ERROR; // 急停状态禁止使能
}
break;
case 0x61A: // 速度控制
if (value > MAX_SAFE_SPEED) {
return HAL_ERROR; // 超速保护
}
break;
case 0x626: // 位置控制
if (value < MIN_POSITION || value > MAX_POSITION) {
return HAL_ERROR; // 位置限制
}
break;
}
return HAL_OK;
}
// RS232配置 (与上位机通信)
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
// Modbus RTU配置 (与伺服通信)
huart2.Init.BaudRate = 9600; // 根据伺服设定
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_EVEN; // Modbus常用偶校验
  1. 标准化:上位机可以直接使用标准Modbus协议
  2. 灵活性:支持本地/远程/混合控制模式
  3. 安全性:单片机可以实施安全检查和保护
  4. 监控能力:单片机可以监控所有通信
  5. 容错性:上位机断线后自动切换到本地控制

如果需要更复杂的控制,也可以考虑:

  • 自定义协议:上位机发送高级命令,单片机解析后控制伺服
  • 双通道:添加第二个通信接口让上位机直接连接伺服(需要硬件支持)

servo_control.h
#ifndef SERVO_CONTROL_H
#define SERVO_CONTROL_H
#include "main.h"
#include "modbus.h"
// 伺服驱动器寄存器地址定义(根据您的表格)
#define REG_CONTROL_WORD 0x6006 // P6-07 控制字
#define REG_STATUS_WORD 0x6008 // P6-09 状态字
#define REG_TARGET_POSITION 0x60A // P6-11 目标位置
#define REG_TARGET_SPEED 0x60E // P6-15 目标速度
#define REG_ACCELERATION 0x612 // P6-19 加速度
#define REG_DECELERATION 0x614 // P6-21 减速度
#define REG_ALARM_CODE 0x622 // P6-35 报警代码
#define REG_ACTUAL_POSITION 0x63A // P6-59 实际位置
#define REG_ACTUAL_SPEED 0x63C // P6-61 实际速度
// 上位机命令类型
typedef enum {
CMD_EMERGENCY_STOP = 0x01, // 紧急停止(最高优先级)
CMD_START_STOP = 0x02, // 启停控制
CMD_SET_POSITION = 0x03, // 位置设定
CMD_SET_SPEED = 0x04, // 速度设定
CMD_SET_ACCEL = 0x05, // 加减速设定
CMD_READ_STATUS = 0x06, // 读取状态
CMD_READ_ALARM = 0x07, // 读取报警
CMD_CLEAR_ALARM = 0x08, // 清除报警
CMD_READ_ACTUAL_POS = 0x09, // 读取实际位置
CMD_READ_ACTUAL_SPD = 0x0A, // 读取实际速度
CMD_BATCH_READ = 0x0B, // 批量读取
CMD_DIRECT_MODBUS = 0xFF // 直接透传Modbus命令
} CommandType;
// 命令包结构
typedef struct {
uint8_t header[2]; // 0xAA, 0x55
uint8_t cmd_type; // 命令类型
uint8_t priority; // 优先级 (0-最高, 255-最低)
uint16_t sequence; // 序列号
uint16_t reg_addr; // 寄存器地址
uint16_t reg_count; // 寄存器数量
uint16_t data[16]; // 数据区(最多16个字)
uint16_t crc16; // CRC校验
} ServoCommand;
// 响应包结构
typedef struct {
uint8_t header[2]; // 0xBB, 0x66
uint8_t cmd_type; // 命令类型(回显)
uint8_t status; // 执行状态
uint16_t sequence; // 序列号(回显)
uint16_t data_len; // 数据长度
uint16_t data[32]; // 返回数据
uint16_t crc16; // CRC校验
} ServoResponse;
// 伺服状态缓存结构
typedef struct {
uint16_t status_word;
uint16_t alarm_code;
int32_t actual_position;
int16_t actual_speed;
uint16_t control_word;
uint32_t last_update_tick;
uint8_t is_valid;
} ServoStatusCache;
// 命令队列结构
#define CMD_QUEUE_SIZE 32
typedef struct {
ServoCommand commands[CMD_QUEUE_SIZE];
uint8_t head;
uint8_t tail;
uint8_t count;
} CommandQueue;
// 函数声明
void Servo_Init(void);
HAL_StatusTypeDef Servo_ProcessCommand(ServoCommand* cmd, ServoResponse* resp);
void Servo_UpdateStatusCache(void);
HAL_StatusTypeDef Servo_EmergencyStop(void);
void Servo_RS232_RxCallback(uint8_t* data, uint16_t size);
void Servo_MainLoop(void);
#endif
// servo_control.c
#include "servo_control.h"
#include "usart.h"
#include "tim.h"
#include <string.h>
// 全局变量
static ServoStatusCache g_servo_status;
static CommandQueue g_cmd_queue;
static CommandQueue g_priority_queue; // 高优先级队列
static uint8_t g_rs232_rx_buffer[256];
static uint8_t g_rs232_tx_buffer[256];
static ModbusHandle g_modbus_handle;
// 初始化函数
void Servo_Init(void) {
// 初始化命令队列
memset(&g_cmd_queue, 0, sizeof(CommandQueue));
memset(&g_priority_queue, 0, sizeof(CommandQueue));
// 初始化状态缓存
memset(&g_servo_status, 0, sizeof(ServoStatusCache));
// 初始化Modbus
Modbus_Init(&g_modbus_handle, &huart2, 1); // 假设使用UART2,从站地址1
// 启动定时器用于周期性状态更新
HAL_TIM_Base_Start_IT(&htim3); // 10ms周期
}
// 命令入队(支持优先级)
static HAL_StatusTypeDef Enqueue_Command(ServoCommand* cmd) {
CommandQueue* queue;
// 紧急停止命令直接执行
if (cmd->cmd_type == CMD_EMERGENCY_STOP) {
return Servo_EmergencyStop();
}
// 根据优先级选择队列
if (cmd->priority < 10) { // 高优先级阈值
queue = &g_priority_queue;
} else {
queue = &g_cmd_queue;
}
// 检查队列是否已满
if (queue->count >= CMD_QUEUE_SIZE) {
return HAL_ERROR;
}
// 入队
memcpy(&queue->commands[queue->tail], cmd, sizeof(ServoCommand));
queue->tail = (queue->tail + 1) % CMD_QUEUE_SIZE;
queue->count++;
return HAL_OK;
}
// 命令出队并执行
static HAL_StatusTypeDef Dequeue_And_Execute(void) {
CommandQueue* queue;
ServoCommand* cmd;
ServoResponse resp;
// 优先处理高优先级队列
if (g_priority_queue.count > 0) {
queue = &g_priority_queue;
} else if (g_cmd_queue.count > 0) {
queue = &g_cmd_queue;
} else {
return HAL_OK; // 队列为空
}
// 取出命令
cmd = &queue->commands[queue->head];
// 执行命令
HAL_StatusTypeDef result = Servo_ProcessCommand(cmd, &resp);
// 发送响应给上位机
HAL_UART_Transmit_DMA(&huart1, (uint8_t*)&resp, sizeof(resp));
// 出队
queue->head = (queue->head + 1) % CMD_QUEUE_SIZE;
queue->count--;
return result;
}
// 处理具体命令
HAL_StatusTypeDef Servo_ProcessCommand(ServoCommand* cmd, ServoResponse* resp) {
HAL_StatusTypeDef result = HAL_OK;
uint16_t modbus_data[32];
// 初始化响应包
resp->header[0] = 0xBB;
resp->header[1] = 0x66;
resp->cmd_type = cmd->cmd_type;
resp->sequence = cmd->sequence;
resp->status = 0; // 0=成功
switch (cmd->cmd_type) {
case CMD_START_STOP:
// 写入控制字
result = Modbus_WriteRegister(&g_modbus_handle, REG_CONTROL_WORD, cmd->data[0]);
if (result == HAL_OK) {
g_servo_status.control_word = cmd->data[0];
}
break;
case CMD_SET_POSITION:
// 设置目标位置(32位,需要写2个寄存器)
modbus_data[0] = (uint16_t)(cmd->data[0]); // 低16位
modbus_data[1] = (uint16_t)(cmd->data[1]); // 高16位
result = Modbus_WriteMultipleRegisters(&g_modbus_handle, REG_TARGET_POSITION, 2, modbus_data);
break;
case CMD_SET_SPEED:
// 设置目标速度
result = Modbus_WriteRegister(&g_modbus_handle, REG_TARGET_SPEED, cmd->data[0]);
break;
case CMD_SET_ACCEL:
// 设置加速度和减速度
result = Modbus_WriteRegister(&g_modbus_handle, REG_ACCELERATION, cmd->data[0]);
if (result == HAL_OK) {
result = Modbus_WriteRegister(&g_modbus_handle, REG_DECELERATION, cmd->data[1]);
}
break;
case CMD_READ_STATUS:
// 读取状态字
result = Modbus_ReadRegisters(&g_modbus_handle, REG_STATUS_WORD, 1, modbus_data);
if (result == HAL_OK) {
resp->data[0] = modbus_data[0];
resp->data_len = 2;
g_servo_status.status_word = modbus_data[0];
}
break;
case CMD_READ_ALARM:
// 读取报警代码
result = Modbus_ReadRegisters(&g_modbus_handle, REG_ALARM_CODE, 1, modbus_data);
if (result == HAL_OK) {
resp->data[0] = modbus_data[0];
resp->data_len = 2;
g_servo_status.alarm_code = modbus_data[0];
}
break;
case CMD_CLEAR_ALARM:
// 清除报警(写特定值到控制字)
result = Modbus_WriteRegister(&g_modbus_handle, REG_CONTROL_WORD, 0x0080); // 复位位
HAL_Delay(100);
result = Modbus_WriteRegister(&g_modbus_handle, REG_CONTROL_WORD, 0x0000);
break;
case CMD_READ_ACTUAL_POS:
// 读取实际位置(32位)
result = Modbus_ReadRegisters(&g_modbus_handle, REG_ACTUAL_POSITION, 2, modbus_data);
if (result == HAL_OK) {
resp->data[0] = modbus_data[0];
resp->data[1] = modbus_data[1];
resp->data_len = 4;
g_servo_status.actual_position = ((int32_t)modbus_data[1] << 16) | modbus_data[0];
}
break;
case CMD_BATCH_READ:
// 批量读取多个寄存器
result = Modbus_ReadRegisters(&g_modbus_handle, cmd->reg_addr,
cmd->reg_count, resp->data);
if (result == HAL_OK) {
resp->data_len = cmd->reg_count * 2;
}
break;
case CMD_DIRECT_MODBUS:
// 直接透传Modbus命令
if (cmd->data[0] == 0x03) { // 读保持寄存器
result = Modbus_ReadRegisters(&g_modbus_handle, cmd->reg_addr,
cmd->reg_count, resp->data);
resp->data_len = cmd->reg_count * 2;
} else if (cmd->data[0] == 0x10) { // 写多个寄存器
result = Modbus_WriteMultipleRegisters(&g_modbus_handle, cmd->reg_addr,
cmd->reg_count, &cmd->data[1]);
}
break;
default:
result = HAL_ERROR;
resp->status = 0xFF; // 未知命令
break;
}
if (result != HAL_OK) {
resp->status = 0x01; // 执行失败
}
// 计算CRC
resp->crc16 = Calculate_CRC16((uint8_t*)resp, sizeof(ServoResponse) - 2);
return result;
}
// 紧急停止函数
HAL_StatusTypeDef Servo_EmergencyStop(void) {
// 立即发送停止命令到伺服
uint16_t stop_cmd = 0x0000; // 停止位
HAL_StatusTypeDef result = Modbus_WriteRegister(&g_modbus_handle, REG_CONTROL_WORD, stop_cmd);
// 清空所有命令队列
g_cmd_queue.count = 0;
g_cmd_queue.head = 0;
g_cmd_queue.tail = 0;
g_priority_queue.count = 0;
g_priority_queue.head = 0;
g_priority_queue.tail = 0;
return result;
}
// 周期性更新状态缓存(在定时器中断中调用)
void Servo_UpdateStatusCache(void) {
static uint8_t update_index = 0;
uint16_t data[2];
// 轮询更新不同的状态信息
switch (update_index) {
case 0:
// 读取状态字
if (Modbus_ReadRegisters(&g_modbus_handle, REG_STATUS_WORD, 1, data) == HAL_OK) {
g_servo_status.status_word = data[0];
}
break;
case 1:
// 读取报警代码
if (Modbus_ReadRegisters(&g_modbus_handle, REG_ALARM_CODE, 1, data) == HAL_OK) {
g_servo_status.alarm_code = data[0];
// 如果有报警,立即通知上位机
if (data[0] != 0) {
ServoResponse alarm_notify;
alarm_notify.header[0] = 0xCC;
alarm_notify.header[1] = 0x77;
alarm_notify.cmd_type = 0xF0; // 报警通知
alarm_notify.data[0] = data[0];
alarm_notify.data_len = 2;
HAL_UART_Transmit_IT(&huart1, (uint8_t*)&alarm_notify, sizeof(alarm_notify));
}
}
break;
case 2:
// 读取实际位置
if (Modbus_ReadRegisters(&g_modbus_handle, REG_ACTUAL_POSITION, 2, data) == HAL_OK) {
g_servo_status.actual_position = ((int32_t)data[1] << 16) | data[0];
}
break;
case 3:
// 读取实际速度
if (Modbus_ReadRegisters(&g_modbus_handle, REG_ACTUAL_SPEED, 1, data) == HAL_OK) {
g_servo_status.actual_speed = (int16_t)data[0];
}
break;
}
update_index = (update_index + 1) % 4;
g_servo_status.last_update_tick = HAL_GetTick();
g_servo_status.is_valid = 1;
}
// RS232接收回调
void Servo_RS232_RxCallback(uint8_t* data, uint16_t size) {
// 检查数据包完整性
if (size < sizeof(ServoCommand)) {
return;
}
ServoCommand* cmd = (ServoCommand*)data;
// 验证包头
if (cmd->header[0] != 0xAA || cmd->header[1] != 0x55) {
return;
}
// 验证CRC
uint16_t calc_crc = Calculate_CRC16(data, size - 2);
if (calc_crc != cmd->crc16) {
return;
}
// 命令入队
Enqueue_Command(cmd);
}
// 主循环处理函数
void Servo_MainLoop(void) {
static uint32_t last_process_tick = 0;
// 每5ms处理一次命令队列
if (HAL_GetTick() - last_process_tick >= 5) {
last_process_tick = HAL_GetTick();
Dequeue_And_Execute();
}
// 检查Modbus超时
Modbus_CheckTimeout(&g_modbus_handle);
}
// 定时器中断回调(10ms)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM3) {
// 更新状态缓存
Servo_UpdateStatusCache();
}
}
// CRC16计算函数
uint16_t Calculate_CRC16(uint8_t* data, uint16_t length) {
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < length; i++) {
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}

来源:CSDN 原文,首次发布于 2025-09-19。