磁铁、舵机、网页控制、通信协议

This commit is contained in:
kirl committed 2026-07-29 21:11:16 +08:00
1 parent 230ad1254a
commit 40ee976236
17 files changed
+1879 -32

No files matched your search

+233
View File
@@ -0,0 +1,233 @@
/**
* @file protocol.h
* @brief EDC 通讯协议 — I2C / UART 双通道, Cycle 收发, CRC16 校验
*
* 顶层概念:
* Point = { x, y, angle_x10 }
* Fragment = { source: Point, target: Point }
* Cycle = { cycle_id, frag_count (2~4), fragments[] }
*
* 帧格式 (大端序):
* ┌──────┬──────┬──────┬──────┬───────────────────┬──────────┐
* │ SOF1 │ SOF2 │ CMD │ LEN │ DATA (N bytes) │ CRC16 │
* │ 0xAA │ 0x55 │ 1B │ 1B │ variable │ 2B (LE) │
* └──────┴──────┴──────┴──────┴───────────────────┴──────────┘
* ◄──────── CRC 计算范围 (CMD + LEN + DATA) ─────────►
*
* Cycle 数据帧 DATA 区:
* cycle_id(2B, BE) + frag_count(1B, 2~4) + fragments(N × 12B)
*
* Fragment (12B, 大端):
* src.x(2B) src.y(2B) src.angle(2B) dst.x(2B) dst.y(2B) dst.angle(2B)
*
* 交互流程:
* MPU ──[CYCLE_DATA]──► MCU (I2C + UART 冗余下发)
* MCU ──[CYCLE_DONE]──► MPU (UART 上报完成, 含 cycle_id)
* MCU ──[CYCLE_REQ]───► MPU (UART 请求下一 Cycle)
*/
#ifndef EDC_PROTOCOL_H
#define EDC_PROTOCOL_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "driver/gpio.h"
#include "driver/uart.h"
#include "driver/i2c_slave.h"
#ifdef __cplusplus
extern "C" {
#endif
/* ================================================================
* 协议常量
* ================================================================ */
#define EDC_PROTO_SOF1 0xAA
#define EDC_PROTO_SOF2 0x55
#define EDC_PROTO_FRAME_MAX 80 /* 最大帧长: 2+1+1+3+4*12+2 = 57 < 80 */
#define EDC_PROTO_FRAME_MIN 6 /* SOF(2) + CMD(1) + LEN(1) + CRC(2) */
#define EDC_FRAG_MIN 2 /* 每 Cycle 最少 fragment 数 */
#define EDC_FRAG_MAX 4 /* 每 Cycle 最多 fragment 数 */
#define EDC_FRAG_BYTES 12 /* 单个 fragment 字节数 (3×uint16×2) */
/* ---- I2C 默认 ---- */
#define EDC_I2C_PORT_DEFAULT 0
#define EDC_I2C_SLAVE_ADDR 0x2A
#define EDC_I2C_SDA_DEFAULT GPIO_NUM_2
#define EDC_I2C_SCL_DEFAULT GPIO_NUM_3
#define EDC_I2C_BUF_SIZE 256
/* ---- UART 默认 ---- */
#define EDC_UART_PORT_DEFAULT UART_NUM_0
#define EDC_UART_BAUDRATE 115200
#define EDC_UART_RX_DEFAULT GPIO_NUM_9
#define EDC_UART_TX_DEFAULT GPIO_NUM_8
#define EDC_UART_BUF_SIZE 512
/* ================================================================
* 命令字
* ================================================================ */
typedef enum {
EDC_CMD_CYCLE_DATA = 0x01, /* MPU → MCU: 下发 Cycle 数据 */
EDC_CMD_CYCLE_DONE = 0x02, /* MCU → MPU: Cycle 执行完成 */
EDC_CMD_CYCLE_REQUEST = 0x03, /* MCU → MPU: 请求下一个 Cycle */
EDC_CMD_ACK = 0x80, /* 通用应答 */
EDC_CMD_NACK = 0xFF, /* 错误 */
} edc_cmd_t;
/* ================================================================
* 数据结构
* ================================================================ */
/** 单个坐标点 (source 或 target) */
typedef struct {
uint16_t x;
uint16_t y;
uint16_t angle_x10; /* 角度 × 10, 如 450 = 45.0° */
} edc_point_t;
/** 一个运动片段: 从 source 移动到 target */
typedef struct {
edc_point_t source;
edc_point_t target;
} edc_fragment_t;
/** 一个 Cycle: 包含 2~4 个 fragment */
typedef struct {
uint16_t cycle_id;
uint8_t frag_count; /* 实际 fragment 数 (2~4) */
edc_fragment_t fragments[EDC_FRAG_MAX];
uint32_t timestamp_ms; /* 本地时间戳 (不随帧传输) */
} edc_cycle_t;
/** 帧来源通道 */
typedef enum {
EDC_CH_NONE = 0,
EDC_CH_I2C = 1,
EDC_CH_UART = 2,
} edc_channel_t;
/** 每通道统计 */
typedef struct {
uint32_t cycles_ok;
uint32_t cycles_err;
uint32_t bytes_total;
} edc_channel_stat_t;
/** 统一收发统计 */
typedef struct {
edc_channel_stat_t i2c;
edc_channel_stat_t uart;
edc_channel_t last_channel;
uint32_t last_tick;
uint32_t done_sent; /* 已发送 DONE 次数 */
uint32_t request_sent; /* 已发送 REQUEST 次数 */
} edc_proto_stat_t;
/** 帧解析状态 */
typedef enum {
EDC_PARSE_OK = 0,
EDC_PARSE_WAITING = 1,
EDC_PARSE_CRC_ERR = -1,
EDC_PARSE_LEN_ERR = -2,
EDC_PARSE_SOF_ERR = -3,
EDC_PARSE_CMD_ERR = -4,
} edc_parse_result_t;
/** 帧解析上下文 (逐字节喂入) */
typedef struct {
uint8_t buf[EDC_PROTO_FRAME_MAX];
uint8_t len;
uint8_t idx;
edc_parse_result_t state;
} edc_frame_ctx_t;
/* ================================================================
* 配置
* ================================================================ */
typedef struct {
bool i2c_enable;
int i2c_port;
uint16_t i2c_addr;
gpio_num_t i2c_sda;
gpio_num_t i2c_scl;
bool uart_enable;
uart_port_t uart_port;
int uart_baudrate;
gpio_num_t uart_rx;
gpio_num_t uart_tx;
} edc_proto_config_t;
/* ================================================================
* CRC16 / 组帧 / 逐字节解析 (底层)
* ================================================================ */
uint16_t edc_crc16(const uint8_t *data, size_t len);
/** 将 Cycle 序列化为协议字节流 (含帧头与 CRC) */
int edc_cycle_pack(const edc_cycle_t *cycle, uint8_t *out);
/** 逐字节解析器 (与旧版兼容, 内部使用 edc_cycle_parse_byte) */
edc_parse_result_t edc_cycle_parse_byte(edc_frame_ctx_t *ctx, uint8_t byte,
edc_cycle_t *cycle);
/** 从完整缓冲区一次性解析 Cycle */
edc_parse_result_t edc_cycle_parse_buf(const uint8_t *data, size_t len,
edc_cycle_t *cycle);
/* ================================================================
* 统一收发器 API (I2C 从机 + UART 双向)
* ================================================================ */
/**
* @brief 初始化协议栈 (I2C 从机 + UART)
* @param cfg 传 NULL 使用默认值
*/
void edc_proto_init(const edc_proto_config_t *cfg);
/**
* @brief 轮询双通道接收 + 返回最新 Cycle (非阻塞)
* @return >0: 有新 Cycle; 0: 无; <0: 错误
*/
int edc_proto_poll(edc_cycle_t *cycle);
/**
* @brief 发送 CYCLE_DONE (通过 UART)
* @param cycle_id 已完成的 Cycle ID
*/
void edc_proto_send_done(uint16_t cycle_id);
/**
* @brief 发送 CYCLE_REQUEST (通过 UART)
*/
void edc_proto_send_request(void);
/**
* @brief 获取统计信息
*/
void edc_proto_get_stats(edc_proto_stat_t *stat);
/* ---- FreeRTOS 任务 + 回调 ---- */
void edc_proto_task(void *pvParam);
/**
* @brief Cycle 回调 (弱符号, 用户实现)
* @param cycle 已校验的有效 Cycle
* @param ch 来源通道
*/
void edc_proto_on_cycle(const edc_cycle_t *cycle, edc_channel_t ch);
#ifdef __cplusplus
}
#endif
#endif /* EDC_PROTOCOL_H */