feat(gml670-v2): 添加二进制协议定义与 ADS1256 SPI 驱动

- protocol.h: CoP/Encoder/Resistance/Spotter/Heartbeat 帧定义,
  GML670 50kg ADC→kg 标定参数
- ads1256: SPI 命令模式驱动,BUFEN=1 解决高阻抗负载误差,
  3750 SPS 平衡精度与采样率,SELFCAL + 寄存器回读校验

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-30 17:39:05 +08:00
parent 5492a98687
commit 97f0d65783
3 changed files with 375 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
#pragma once
#include <stdint.h>
/* sensor.c 切换通道时需要此寄存器地址 */
#define ADS1256_REG_MUX 0x01
/**
* @brief 初始化 ADS1256:配置 GPIO/SPI,复位芯片,写入寄存器,自校准。
* @return 0 成功,负 errno 失败。
*/
int ads1256_init(void);
/**
* @brief 等待 DRDY 拉低(转换结果可读),带超时保护。
* @param timeout_ms 超时时间(毫秒)。
*/
void ads1256_wait_drdy(uint16_t timeout_ms);
/**
* @brief 向 ADS1256 写单个寄存器。
* @param reg 目标寄存器地址。
* @param val 要写入的值。
*/
void ads1256_write_reg(uint8_t reg, uint8_t val);
/**
* @brief 从 ADS1256 读单个寄存器。
* @param reg 目标寄存器地址。
* @return 寄存器值。
*/
uint8_t ads1256_read_reg(uint8_t reg);
/**
* @brief 发送 SYNC + WAKEUP 命令,触发一次同步采样。
*/
void ads1256_sync_wakeup(void);
/**
* @brief 硬件复位 ADS1256(通过 RESET 引脚),等待复位后自校准完成。
*/
void ads1256_hwreset(void);
/**
* @brief 读取当前 24 位转换结果,符号扩展为 int32_t。
* @return ADC 原始值。
*/
int32_t ads1256_read_data(void);
/**
* @brief 发送单字节命令到 ADS1256。
* @param cmd 命令字。
*/
void ads1256_write_cmd(uint8_t cmd);
+132
View File
@@ -0,0 +1,132 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
/* ─── 帧常量 ─── */
/* 双帧头比单字节魔数更容易在连续字节流里完成包起始判定。 */
#define PROTO_SYNC0 0xAAU
#define PROTO_SYNC1 0x55U
#define PROTO_TYPE_COP 0x01U /* 上行: 压力中心 (CoP) 帧 */
#define PROTO_TYPE_ENCODER 0x02U /* 上行: 电机编码器帧(预留) */
#define PROTO_TYPE_RESISTANCE 0x10U /* 下行: 阻力参数 (K, B, Tau) */
#define PROTO_TYPE_SPOTTER 0x11U /* 下行: Spotter Mode 保护阈值 */
#define PROTO_TYPE_HEARTBEAT 0x20U /* 下行: 心跳包 */
/* CoP flags 位定义 */
#define COP_FLAG_FORCE_VALID 0x01U /* 总力 > 阈值,CoP 坐标有意义 */
/* ─── 板面几何 & 传感器标定 ─── */
/* 传感器到板面中心的半宽、半长 (mm)。 */
#define BOARD_HALF_WIDTH_MM 100.0f
#define BOARD_HALF_LENGTH_MM 100.0f
/*
* ADC → kg 换算推导:
* GML670 50kg: 灵敏度 1.75 mV/V, 激励 5V → 满量程输出 8.75 mV
* ADS1256: PGA=64, VREF=2.5V → 满量程 ±78.125 mV
* 50kg 对应 ADC counts = 8.75 / 78.125 × 8388607 ≈ 939524
* 1 LSB = 50.0 / 939524 ≈ 5.322e-5 kg
* 如实际激励电压或 VREF 不同,按比例修正此系数。
*/
#define SENSOR_EXCITATION_V 5.0f
#define SENSOR_SENSITIVITY_MVV 1.75f
#define SENSOR_RATED_LOAD_KG 50.0f
#define ADS1256_VREF_V 2.5f
#define ADS1256_PGA 64
#define ADC_COUNTS_AT_RATED \
((SENSOR_SENSITIVITY_MVV * SENSOR_EXCITATION_V) / (2.0f * ADS1256_VREF_V * 1000.0f / ADS1256_PGA) * 8388607.0f)
#define ADC_TO_FORCE_SCALE (SENSOR_RATED_LOAD_KG / ADC_COUNTS_AT_RATED)
/* 总重低于此值时 CoP 无意义(除零保护),单位 kg */
#define COP_MIN_FORCE_THRESHOLD 0.5f
/* ─── 上行: CoP 帧 (17 bytes, 50 Hz) ───
*
* [AA 55 01 seq flags cop_x(4) cop_y(4) force(4)]
*/
struct cop_frame_t {
uint8_t sync0; /* = PROTO_SYNC0 */
uint8_t sync1; /* = PROTO_SYNC1 */
uint8_t type; /* = PROTO_TYPE_COP */
uint8_t seq; /* 包序号 0-255 滚动,用于丢包检测 */
uint8_t flags; /* bit0: force_valid */
float cop_x; /* 压力中心 X (mm),板面坐标系 */
float cop_y; /* 压力中心 Y (mm),板面坐标系 */
float force; /* 总重量 (kg) */
} __attribute__((packed));
union cop_pkt_t {
struct cop_frame_t frame;
uint8_t bytes[sizeof(struct cop_frame_t)];
};
/* ─── 上行: 电机编码器帧 (13 bytes, 预留) ───
*
* [AA 55 02 seq flags cable_length(4) velocity(4)]
*/
struct encoder_frame_t {
uint8_t sync0; /* = PROTO_SYNC0 */
uint8_t sync1; /* = PROTO_SYNC1 */
uint8_t type; /* = PROTO_TYPE_ENCODER */
uint8_t seq; /* 包序号 */
uint8_t flags; /* 预留,填 0 */
float cable_length; /* 拉索长度 (mm) */
float velocity; /* 拉索速度 (mm/s) */
} __attribute__((packed));
union encoder_pkt_t {
struct encoder_frame_t frame;
uint8_t bytes[sizeof(struct encoder_frame_t)];
};
/* ─── 下行: 阻力参数帧 (15 bytes) ───
*
* [AA 55 10 K(4) B(4) Tau(4)]
*/
struct resistance_frame_t {
uint8_t sync0; /* = PROTO_SYNC0 */
uint8_t sync1; /* = PROTO_SYNC1 */
uint8_t type; /* = PROTO_TYPE_RESISTANCE */
float K; /* 刚度 (N/m) */
float B; /* 阻尼 (Ns/m) */
float Tau; /* 时间常数 (s) */
} __attribute__((packed));
union resistance_pkt_t {
struct resistance_frame_t frame;
uint8_t bytes[sizeof(struct resistance_frame_t)];
};
/* ─── 下行: Spotter Mode 帧 (8 bytes) ───
*
* [AA 55 11 threshold(4) enable]
*/
struct spotter_frame_t {
uint8_t sync0; /* = PROTO_SYNC0 */
uint8_t sync1; /* = PROTO_SYNC1 */
uint8_t type; /* = PROTO_TYPE_SPOTTER */
float threshold; /* 保护力阈值 (N) */
uint8_t enable; /* 0 = 关闭, 1 = 启用 */
} __attribute__((packed));
union spotter_pkt_t {
struct spotter_frame_t frame;
uint8_t bytes[sizeof(struct spotter_frame_t)];
};
/* ─── 下行: 心跳帧 (4 bytes, ~1 Hz) ───
*
* [AA 55 20 counter]
*/
struct heartbeat_frame_t {
uint8_t sync0; /* = PROTO_SYNC0 */
uint8_t sync1; /* = PROTO_SYNC1 */
uint8_t type; /* = PROTO_TYPE_HEARTBEAT */
uint8_t counter; /* 滚动计数,用于活性检测 */
} __attribute__((packed));
union heartbeat_pkt_t {
struct heartbeat_frame_t frame;
uint8_t bytes[sizeof(struct heartbeat_frame_t)];
};