[STM32C5] 【STM32C5评测】3、二维云平台控制系统

[复制链接]
12|1
lulugl 发表于 2026-9-17 20:35 | 显示全部楼层 |阅读模式
[i=s] 本帖最后由 lulugl 于 2026-9-17 21:17 编辑 [/i]

基于 STM32C5 的 CAN二维云台总线电机控制

本文基于本仓库(STM32C542_CAN)的实际代码,介绍如何用 STM32C5 的 FDCAN外设通过 CAN 总线控制 JC4310 系列电机驱动器(三轴云台场景)。内容涵盖硬件接线、FDCAN 外设配置、JC 通信协议、软件实现和调试排错,可作为入门 CAN 电机控制的实操参考。以及web网页控制。

目录

1. 整体方案

┌─────────────┐  UART   ┌──────────────────┐  CAN  ┌─────────────────┐
│ PC 串口终端  │ ◄─────► │ NUCLEO-C542RC     │  J9  │ 电机驱动器 x N   │
│ (Shell 命令) │  USART2 │ (板载 CAN 收发器)  │ ◄───► │ (JC4310, ID1~3) │
└─────────────┘         └──────────────────┘       └─────────────────┘
  • 电脑上通过串口终端输入命令(pos 90speed 60 等);
  • STM32 把命令翻译成 JC 协议的 CAN 帧发给电机驱动器;
  • 驱动器回复执行结果和实时反馈(位置/速度/电流),STM32 解析后打印。

代码分层:

文件 职责
main.c 系统初始化、FDCAN 位时序覆盖为 1 Mbps、主循环
generated/hal/mx_fdcan1.c CubeMX2 生成的 FDCAN1 外设初始化
jc4310.c/.h JC 协议层:寄存器读写、PV/PVT 运动、同步问答
shell.c/.h UART 命令行:解析命令、调用协议层、打印反馈

2. 硬件准备

NUCLEO-C542RC 板载 CAN FD 收发器,已在板上连接到 FDCAN1 的
PB8(RX)/PB9(TX),无需外接收发器。CAN 总线通过板上的 J9 免螺丝
按压端子
引出,插上 JP9 跳帽 即可接入板载 120 Ω 终端电阻(R29)
(详见 ST 用户手册 UM3615)。

项目 说明
收发器 板载 CAN FD 收发器(FDCAN1 PB8/PB9 已内部连接)
总线接口 J9 端子接 CANH / CANL,并与电机驱动器共地
终端电阻 总线两端各一个 120 Ω;板端插上 JP9 跳帽即接入板载 R29,另一端在最后一台电机处
波特率 1 Mbps(JC 电机默认值)
电机 ID 出厂需用调试工具设置,三轴云台一般设为 1/2/3

接线示意:

NUCLEO-C542RC                  J9
┌────────────────────┐  CANH ─────┬──────┬──────┬────── CANH
│ FDCAN1 ── 板载收发器 │            ▼      ▼      ▼
│ (JP9 跳帽 = 120Ω)  │  CANL ──── 电机1  电机2  电机3 ── 120Ω
└────────────────────┘  GND  ──── 共地 ────────────────

3. CAN / FDCAN 基础知识

  • CAN 2.0A 标准帧:11 位标识符(ID),数据场 0~8 字节。本项目全部
    使用标准帧、DLC 固定 8。
  • ID 即优先级:总线仲裁时 ID 越小优先级越高;ID 也用来寻址,
    JC 协议里一台电机占一对 ID(主机发 0x600+id,驱动器回 0x580+id)。
  • 多主结构:总线上任何节点都可以主动发送;多个节点同时发送靠仲裁
    决定谁先,不像 UART/SPI 有主从片选。
  • 错误处理硬件化:发送需要有节点 ACK,否则控制器自动重发;错误
    计数器超阈值会进入 error passive / bus-off。STM32 的 FDCAN 外设可以
    读出这些状态(见 canstat 命令)。
  • FDCAN:STM32C5 的 CAN 控制器,兼容经典 CAN 2.0 和 CAN FD。本项目
    只用经典 CAN 模式(电机不支持 FD),因此数据位时序不用配置。

4. STM32C5 FDCAN 配置

4.1 CubeMX2 生成的基础配置

image.png

generated/hal/mx_fdcan1.c 中的 mx_fdcan1_init():

  • 内核时钟源:PCLK1(经 RCC 配置为 144 MHz),时钟分频 1;
  • 帧格式:HAL_FDCAN_FRAME_FORMAT_CLASSIC_CAN(经典 CAN);
  • 工作模式:NORMAL;自动重发使能;
  • 发送模式:TX FIFO(先请求先发);
  • 不配置验收过滤器,改用全局过滤器把所有标准帧路由到 RX FIFO0
    (HAL_FDCAN_NO_MATCH_TO_RX_FIFO_0),由软件按 ID 过滤——调试阶段
    这样最灵活,可以收到总线上所有帧;
  • 生成时按 500 kbps 配置(不满足 JC 电机的 1 Mbps,见下节覆盖)。

4.2 位时序:覆盖为 1 Mbps

CAN 的波特率由"位时序"决定:每个位时间由若干时间量子(tq)组成,

波特率 = 内核时钟 / (prescaler × (1 + seg1 + seg2))


`main.c` 在 `HAL_FDCAN_Start()` 之前用 `HAL_FDCAN_SetNominalBitTiming()`
覆盖为 1 Mbps:

```c
hal_fdcan_nominal_bit_timing_t bit_timing;
bit_timing.nominal_prescaler  = 1;
bit_timing.nominal_time_seg1  = 115;
bit_timing.nominal_time_seg2  = 28;
bit_timing.nominal_jump_width = 28;

验算:144 MHz / (1 × (1 + 115 + 28)) = 144 MHz / 144 = 1 MHz

采样点:(1 + 115) / 144 = 80.6 %(常用推荐区间 75%~87.5%)。

驱动包 stm32c5xx_drivers/utils/ 里还提供了一个 fdcan_timing
辅助工具,可根据目标波特率自动算位时序参数。

4.3 启动顺序

mx_fdcan1_init();                        // 外设 + GPIO 初始化(500 kbps 配置)
HAL_FDCAN_SetNominalBitTiming(...);      // 空闲状态下覆盖为 1 Mbps
HAL_FDCAN_Start(hfdcan1);                // 上线
JC4310_Init(hfdcan1);                    // 协议层绑定句柄

5. JC4310 CAN 通信协议

依据《JC 系列 CAN 通信说明》V2.4。要点:

项目 说明
帧格式 CAN 2.0A 标准帧,DLC 固定 8
主机发送 ID 0x600 + 电机ID
驱动器回复 ID 0x580 + 电机ID
字节序 大端(高位字节在前)

5.1 命令字(数据第 0 字节)

命令字 含义 帧格式
0x4B 读 16 位寄存器 4B regH regL 00 00 00 00 00,回复回显命令字,值在 data[4..5]
0x43 读 32 位寄存器 43 regH regL 00 00 00 00 00,回复值在 data[4..7]
0x2B 写 16 位寄存器 2B regH regL 00 valH valL 00 00
0x23 写 32 位寄存器 23 regH regL 00 val(b3..b0)
0x24 PV 运动 24 pos(b3..b0) speed(b1..b0) 00
0x25 PVT 运动 25 pos(b3..b0) speed(b1..b0) torque%
0x2A 写命令的统一回复 2A pos(b2..b0) speed(b1..b0) current(b1..b0)

5.2 常用寄存器

地址 含义 位宽 缩放
0x0004 母线电压 16 ÷10 → V
0x0005 电流 16 ÷100 → A
0x0006 实际速度 32 ÷100 → rpm
0x0008 实际位置 32 ÷100 → deg
0x000A 驱动器温度 16 ÷10 → °C
0x000B 电机温度 16 ÷10 → °C
0x000C 错误码 32 原始值
0x0020 力矩设定 16 ×100 → 0.01 Nm
0x0021 速度设定 32 ×100 → 0.01 rpm
0x0023 / 0x0025 绝对/相对位置设定 32 ×100 → 0.01 deg
0x0027 低速模式速度设定 16 ×100
0x0060 控制模式(0~5) 16
0x00A0 / 0x00A2 退出/进入闭环 16 写 1
0x00A3~0x00A7 擦除/保存/重启/设原点/临时原点 16 写 1

控制模式:0 力矩,1 速度,2 位置梯形轨迹,3 位置平滑滤波,
4 位置直接,5 低速大扭矩。

5.3 统一回复的巧妙设计

所有命令的回复都是 0x2A + 实时反馈(24 位位置 + 16 位速度 +
16 位电流)。也就是说每发一条运动指令,顺手就能拿到最新状态,不需要
额外轮询。协议层用 jc_parse_feedback() 统一解析。

6. 软件实现

6.1 同步问答模型

协议层(jc4310.c)采用"发一帧、等回复"的同步模型,核心是三个内部
函数:

jc_send()        // 组帧入 TX FIFO,最多等 20 ms 空位(等不到 = 无人 ACK)
jc_wait_reply()  // 轮询 RX FIFO0,只认 0x580+id 且首字节匹配的回复,
                 // 100 ms 超时;其他帧丢弃
jc_parse_feedback() // 解析 0x2A 回复里的位置/速度/电流

所有上层 API(JC4310_SetSpeed()JC4310_ReadPosition() …)都是
这两个原语的组合,结构非常规整:

hal_status_t JC4310_SetSpeed(uint8_t id, float speed_rpm, jc4310_feedback_t *fb)
{
  return jc_write32(id, JC4310_REG_SPEED_SET, jc_round(speed_rpm * 100.0f), fb);
}

6.2 值得注意的实现细节

  1. 24 位有符号位置需要符号扩展(jc4310.c:137):
    回复中位置是 3 字节大端有符号数,拼成 32 位后要检查 bit23,
    为 1 时高 8 位补 0xFF,否则负角度会被解析成巨大的正数。

  2. 超时分级:

    • 发送等待 TX FIFO 空位:20 ms(超时通常意味着没人 ACK → 总线没接好);
    • 等回复:100 ms;
    • 重启/设原点这类慢命令:500 ms。
      有超时兜底,shell ***不会死等。
  3. 收发无过滤器:硬件全局过滤器把全部标准帧送进 FIFO0,软件在
    jc_wait_reply() 里按 ID + 命令字过滤。好处是 sniff/probe
    调试命令可以直接看到总线上的所有流量。

  4. 浮点缩放:电机侧全部用定点(×100 或 ×10),MCU 侧收发时做
    float ↔ 定点的换算,jc_round() 不依赖 libm 完成四舍五入。

6.3 调用示例

jc4310_feedback_t fb;

JC4310_EnterClosedLoop(1, &fb);          // 1 号电机上闭环
JC4310_SetMode(1, JC4310_MODE_SPEED, &fb);
JC4310_SetSpeed(1, 60.0f, &fb);          // 60 rpm
printf("pos=%.2f deg, current=%.2f A\r\n", fb.pos_deg, fb.current_a);

7. 操作演示(UART Shell)

固件在 USART2(ST-Link 虚拟串口)上跑一个行命令 shell,提示符
jc<N> 中的 N 是当前目标电机 ID。

典型流程(1 号电机速度模式):

jc1> id 1            # 选择 1 号电机(TX 0x601 / RX 0x581)
jc1> enable          # 上闭环
jc1> mode 1          # 速度模式
jc1> speed 60        # 60 rpm 运转
OK
  pos=1234.56 deg, speed=59.98 rpm, current=0.31 A
jc1> status          # 电压/电流/速度/位置/温度/错误码 一次全读
jc1> speed 0         # 停
jc1> disable         # 退出闭环

位置/PV/PVT 运动:

jc1> mode 2          # 位置梯形轨迹模式
jc1> pos 90          # 绝对位置 90°
jc1> rpos -90        # 相对转回
jc1> pv 180 60       # 位置 180°、速度 60 rpm
jc1> pvt 180 60 50   # 再加 50% 力矩限制

完整命令说明见 shell_usage.md

除串口终端外,也可以用网页控制台 web/jc4310_console.html(Chrome /
Edge 打开,基于 Web Serial API 直连 ST-Link 虚拟串口):把 enable、
mode、speed、pos、pv/pvt 等命令做成按钮和滑块,自动轮询 status
并以仪表盘显示位置/速度/电流,适合演示和分享给不熟悉命令行的人。

8. 调试与排错

8.1 内置调试命令

命令 作用
canstat 读 FDCAN 控制器状态:activity、LEC(最近协议错误)、error passive、bus-off、TX/RX 错误计数器、FIFO 水位
probe 发一帧读电压请求,然后 dump 收到的所有帧并标出匹配的回复;能区分"根本没 ACK"(发送失败)和"ACK 了但不回答"(ID/协议不对)
sniff [ms] 总线监听,打印指定时间内收到的所有帧(默认 2 秒)
raw <b0..b7> 发原始 8 字节帧并打印回复,用来验证协议手册上的任意命令

canstat 输出示例(正常状态):

jc1> canstat
  activity      = sync
  last error    = none
  error passive = 0
  bus off       = 0
  tx/rx errors  = 0 / 0
  tx fifo free  = 3
  rx fifo fill  = 0

出现异常时还会附带一行诊断提示,例如 bus-off 时提示检查收发器/
终端电阻/波特率,ACK error(LEC=3)时提示"帧发出去了但没人 ACK"。

9. 网页远程控制

我在pc端上制作了一个web网络控制台:

image.png

这样就可以通过pc方便的控制云平台的各种方式运行。

MessageRing 发表于 2026-9-18 13:48 | 显示全部楼层
JC协议解析要仔细检查,可能存在时序问题,检查FDCAN的BTR寄存器配置。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

225

主题

947

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部
0