diff --git a/.gitignore b/.gitignore index dd872f7..cbb4a3e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ build/ # IDE files .idea/ .vscode/ -.trae/ *.swp *.swo *~ diff --git a/.trae/skills/create-project/SKILL.md b/.trae/skills/create-project/SKILL.md new file mode 100644 index 0000000..1aa406f --- /dev/null +++ b/.trae/skills/create-project/SKILL.md @@ -0,0 +1,434 @@ +*** + +name: "create-project" +description: "创建和配置嵌入式工程项目,按照标准目录结构生成驱动代码和配置文件。调用时机:当需要创建嵌入式工程项目、生成驱动代码、配置硬件外设或设计通讯协议时。" +version: 1.1.0 +-------------- + +# PROJECT Configuration Skill + +该技能用于创建和配置嵌入式工程项目,按照标准化的工程目录结构生成完整的工程代码,包括硬件驱动、通讯协议、配置文件等,并确保工程的可编译性和可维护性。 + +## 调用时机 + +在以下情况下必须调用此技能: + +- 需要创建新的嵌入式工程项目时 +- 需要生成硬件外设驱动代码(ADC、UART、I2C、SPI、PWM、Timer、GPIO、RTC、DMA等)时 +- 需要设计通讯协议并实现协议解析代码时 +- 需要配置工程编译环境(CMake、Makefile)时 +- 需要按照标准化目录结构组织工程文件时 +- 需要生成可执行文件并验证工程正确性时 +- 需要参考reference文档进行驱动设计和协议设计时 + +## 工作流程 + +1. 根据输入的项目名称和选择的芯片,创建工程目录 +2. 严格按照工程目录结构创建目录和文件 +3. 下载相应的编译和调试工具链,包括编译器、调试器、库文件,生成对应的下载flash脚本等 +4. 配置编译环境,包括设置编译器、设置调试器等 +5. 生成驱动代码,驱动外部设备,每一种驱动都单独生成一个源文件和一个头文件 +6. 编译工程,生成可执行文件,并烧录到单片机中 + +## 技能内容 + +1. **工程目录结构**: + +### 目录结构规范 + +工程必须严格按照以下目录结构创建,确保一致性和可维护性: + +``` +ProjectName/ +├── .trae/skills/ # Trae技能目录 +│ ├── create-project/ # 创建工程技能(必须存在) +│ │ ├── SKILL.md # 技能文档 +│ │ ├── scripts/ # 可选:存放可执行脚本 +│ │ ├── references/ # 必须:存放供AI参考的文档(通讯协议、原理图等) +│ │ └── assets/ # 可选:存放静态资源文件 +│ ├── download-tools/ # 下载工具链技能 +│ └── download-lib/ # 下载库技能 +├── app/ # 应用层源代码 +│ ├── main.c # 主程序(必须包含main函数) +│ ├── main.h # 主程序头文件 +│ └── tasks/ # 任务文件目录 +│ ├── work_task.c # 工作任务文件 +│ ├── work_task.h # 工作任务头文件 +│ ├── monitor_task.c # 监控任务文件 +│ └── monitor_task.h # 监控任务头文件 +├── bsp/ # 板级支持包 +│ ├── common_types.h # 通用类型定义(必须包含ret_code_t等) +│ ├── hardware_init.h # 硬件初始化头文件 +│ ├── hardware_init.c # 硬件初始化源文件(必须包含DMA时钟使能等) +│ └── device/ # 外部芯片设备文件目录 +│ │ ├── eeprom/ # EEPROM驱动头文件目录 +│ │ │ ├── eeprom_driver.h # EEPROM驱动头文件 +│ │ │ └── eeprom_driver.c # EEPROM驱动源文件 +│ │ ├── key/ # KEY驱动头文件目录 +│ │ │ ├── key_driver.h # KEY驱动头文件 +│ │ │ └── key_driver.c # KEY驱动源文件 +│ │ ├── led/ # LED驱动头文件目录 +│ │ │ ├── led_driver.h # LED驱动头文件 +│ │ │ └── led_driver.c # LED驱动源文件 +├── doc/ # 文档目录 +├── drv/ # 单片机外设驱动层源代码 +│ ├── system/ # 系统驱动(如系统时钟、中断、中断服务函数等) +│ │ ├── system_driver.h # 系统驱动头文件 +│ │ └── system_driver.c # 系统驱动源文件 +│ ├── adc/ # ADC驱动(每个驱动单独目录) +│ │ ├── adc_driver.h # ADC驱动头文件 +│ │ └── adc_driver.c # ADC驱动源文件 +│ ├── i2c/ # I2C驱动(必须支持DMA FIFO) +│ │ ├── i2c_driver.h # I2C驱动头文件 +│ │ └── i2c_driver.c # I2C驱动源文件 +│ ├── uart/ # UART驱动(必须支持DMA FIFO) +│ │ ├── uart_driver.h # UART驱动头文件 +│ │ └── uart_driver.c # UART驱动源文件 +│ └── timer/ # 定时器驱动(必须支持DMA FIFO) +│ │ ├── timer_driver.h # 定时器驱动头文件 +│ │ └── timer_driver.c # 定时器驱动源文件 +├── libs/ # 库文件 +│ ├── common/ # 通用库(将数据解析等通用功能封装在此库中) +│ ├── CMSIS/ # CMSIS库(芯片供应商提供) +│ ├── algorithm/ # 算法库 +│ └── thirdparty/ # 第三方库(如GD32F4xx库) +├── config/ # 配置文件 +│ └── config.h # 系统配置文件(必须包含DEBUG_ENABLED等) +├── tools/ # 工具文件目录 +│ ├── gcc/ # GCC工具 +│ ├── stlink/ # ST-LINK工具 +│ ├── openocd/ # OpenOCD工具 +│ ├── jlink/ # J-LINK工具 +│ ├── cmake/ # CMake工具 +│ ├── python/ # Python工具 +│ ├── makefile/ # Makefile工具 +│ ├── ninja/ # Ninja工具 +│ └── flash.sh # 烧录脚本文件 +├── tests/ # 测试文件目录 +├── build/ # 构建目录(临时文件,不提交到版本控制) +│ ├── CMakeCache.txt # CMake缓存 +│ ├── CMakeFiles/ # CMake生成文件 +│ └── ProjectName.elf # 生成的可执行文件 +├── CMakeLists.txt # 主CMakeLists.txt文件(必须存在) +└── README.md # 项目说明文档 +``` + +### 文件命名规范 + +- **头文件**:使用`.h`扩展名,命名格式:`<模块名>_driver.h` 或 `<模块名>.h` +- **源文件**:使用`.c`扩展名,命名格式:`<模块名>_driver.c` 或 `<模块名>.c` +- **测试文件**:使用`test_`前缀,命名格式:`test_<模块名>.c` +- **配置文件**:使用`config.h`或`<模块名>_config.h`格式 + +### 编码规范 + +- **文件编码**:所有源文件和头文件必须使用UTF-8编码 +- **代码风格**:使用统一的代码缩进(4个空格) +- **注释规范**:所有关键函数和结构体必须有中文注释说明 +- **函数命名**:使用小写字母和下划线,如`uart_init()`, `uart_set_data()` + +### 目录创建要求 + +1. **必须严格按照上述结构创建目录**,不得随意更改 +2. **references目录必须包含完整的设计文档**(通讯协议、原理图等) +3. **每个驱动必须有独立的.h和.c文件**,不得合并 +4. **build目录为临时目录**,不应提交到版本控制系统 +5. **所有文件路径必须使用正斜杠(/)分隔**,确保跨平台兼容性 + +## 工程参数配置 +1. 工程编译生成的过程文件全部放到build目录下 +2. 优先使用系统工具编译,如果不存在,那么使用tools目录下的工具进行编译 +3. 如果tools目录下的工具也不存在,那么下载调用DOWNLOAD-TOOLS技能进行下载 +4. 保持工程目录干净,不要过多文件,只保留必要的文件 +5. 设备注册:ADC、UART设备成功注册到系统 +6. 接口一致性:所有设备遵循统一的操作接口 +7. 扩展性:新设备可通过注册机制轻松添加 +8. 兼容性:与现有驱动代码完全兼容 + +## 协议设计指导 + +### 协议设计原则 + +协议设计必须严格遵循以下原则,确保通信的可靠性和可维护性: + +1. **参考文档优先**:必须首先读取并分析`references/`目录中的通讯协议文档(.md、.docx、.xml、.pdf格式) +2. **帧格式标准化**:协议帧必须包含帧头、设备ID、帧序号、数据长度、数据域、校验和等必要字段 +3. **校验机制**:根据文档要求实现校验机制(CRC16、简单求和校验等) +4. **错误处理**:实现完整的错误检测和恢复机制 + +### 标准协议帧格式 + +基于常见的嵌入式通信协议,推荐使用以下标准帧格式: + +```c +// 标准协议帧结构 +typedef struct { + uint8_t header_high; // 帧头高字节(如0xEB) + uint8_t header_low; // 帧头低字节(如0x90) + uint8_t device_id; // 设备ID(0x0A, 0x0B, 0x10等) + uint8_t frame_seq; // 帧序号(每发送一帧加一) + uint8_t data_length; // 数据长度(0-255) + uint8_t data[32]; // 数据域(最大32字节) + uint8_t checksum; // 校验和(简单求和校验) +} standard_protocol_frame_t; +``` + +### 协议实现要求 + +1. **帧头定义**:帧头必须与参考文档一致(如0xEB 0x90),不得随意更改 +2. **设备ID枚举**:必须定义清晰的设备ID枚举,区分不同协议类型: + ```c + typedef enum { + PROTOCOL_ID_CONTROL_CMD = 0x0A, // 控制命令协议 + PROTOCOL_ID_ANGLE_CTRL = 0x0B, // 角度控制协议 + PROTOCOL_ID_DATA_ACQ = 0x10 // 数据采集协议 + } protocol_id_t; + ``` +3. **校验函数**:实现与文档要求一致的校验函数 +4. **帧构建函数**:提供完整的帧构建和解析函数 +5. **数据转换**:正确处理字节序和数据格式转换(如浮点数转换) + +### 伺服控制协议规范 + +对于伺服控制应用,必须遵循以下规范: + +1. **角度控制协议**:使用浮点数表示角度,支持正负角度范围 +2. **数据采集协议**:包含AD采样值、温度、状态等信息 +3. **控制命令协议**:支持开关控制、模式切换等命令 +4. **实时性要求**:根据文档要求确定通信频率(如50Hz、400Hz) + +### 协议测试验证 + +1. **单元测试**:为每个协议函数编写测试用例 +2. **集成测试**:测试完整的协议通信流程 +3. **边界测试**:测试最大/最小数据长度、异常帧处理 +4. **性能测试**:验证协议处理速度和内存使用 + +## 工具链配置 + +1. 优先使用tools目录下的工具链进行编译 +2. 如果tools目录下的工具链也不存在,那么下载调用DOWNLOAD-TOOLS技能进行下载 + +## 硬件外设配置与代码生成规范 + +### 驱动代码生成原则 + +1. **独立文件原则**:每个外设驱动必须有独立的`.h`头文件和`.c`源文件 +2. **统一接口原则**:所有驱动遵循统一的函数接口规范 +3. **模块化设计**:驱动代码应高度模块化,便于测试和维护 +4. **错误处理**:所有函数必须返回标准的错误代码(`ret_code_t`) + +### 驱动文件结构 + +每个驱动目录必须包含以下文件: + +``` +drv// +├── _driver.h # 驱动头文件 +├── _driver.c # 驱动源文件 +└── _config.h # 驱动配置头文件 +``` + +### 标准驱动接口函数 + +每个驱动必须实现以下标准函数接口(根据外设类型选择实现): + +```c +// 初始化函数 +ret_code_t _init(void); + +// 反初始化函数 +ret_code_t _deinit(void); + +// 读数据函数 +ret_code_t _read(uint8_t *data, uint16_t length); + +// 写数据函数 +ret_code_t _write(const uint8_t *data, uint16_t length); + +// 控制函数 +ret_code_t _control(uint32_t cmd, void *param); + +// 设置函数 +ret_code_t _set(uint32_t param, uint32_t value); + +// 获取函数 +ret_code_t _get(uint32_t param, uint32_t *value); +``` + +### 驱动注册机制 + +必须实现驱动注册机制,支持动态添加和移除驱动: + +```c +// 设备注册结构体 +typedef struct { + uint8_t device_id; // 设备ID + const char *device_name; // 设备名称 + ret_code_t (*init_func)(void); // 初始化函数指针 + ret_code_t (*deinit_func)(void); // 反初始化函数指针 + ret_code_t (*read_func)(uint8_t*, uint16_t); // 读函数指针 + ret_code_t (*write_func)(const uint8_t*, uint16_t); // 写函数指针 +} device_driver_t; + +// 设备注册函数 +ret_code_t register_device(const device_driver_t *driver); +``` + +### 驱动特殊要求 + +对于所有驱动,必须满足以下特殊要求: + +1. **DMA FIFO支持**:必须实现DMA+中断的FIFO缓冲区系统 +2. **可配置缓冲区**:支持可配置的接收缓冲区大小 +3. **错误检测**:实现溢出、帧错误、奇偶校验错误检测 +4. **波特率自适应**:支持动态波特率配置 + +示例驱动结构: +```c +// 驱动 FIFO缓冲区结构 +typedef struct { + uint8_t buffer[UART_RX_BUFFER_SIZE]; + volatile uint16_t read_index; + volatile uint16_t write_index; + bool overflow; +} driver_fifo_t; + +// DMA初始化函数 +ret_code_t driver_dma_init(void); + + + +### ADC驱动特殊要求 + +1. **多通道支持**:支持多通道ADC采样 +2. **采样率配置**:可配置采样率和采样精度 +3. **数据滤波**:实现数据滤波算法(如移动平均) +4. **校准功能**:支持ADC校准和偏移校正 + +### PWM驱动特殊要求 + +1. **多通道支持**:支持多通道PWM输出 +2. **频率可调**:支持动态频率和占空比调整 +3. **死区控制**:支持死区时间配置(对于电机控制) +4. **同步输出**:支持多通道同步输出 + +### 驱动配置管理 + +1. **配置分离**:驱动配置与实现代码分离 +2. **默认配置**:提供合理的默认配置值 +3. **运行时配置**:支持运行时动态配置 +4. **配置验证**:配置参数合法性验证 + +### 代码质量要求 + +1. **注释规范**:所有关键函数必须有中文注释 +2. **错误处理**:全面的错误检查和返回 +3. **资源管理**:正确的资源申请和释放 +4. **线程安全**:考虑多任务环境下的线程安全性 +5. **性能优化**:关键路径代码性能优化 + +## 测试与验证配置 + +### 测试文件组织 + +1. **测试目录结构**:所有测试文件必须放在`tests/`目录下 +2. **命名规范**:测试文件必须以`test_`开头,如`test_uart.c`、`test_servo.c` +3. **测试分类**: + - 单元测试:测试单个函数或模块 + - 集成测试:测试多个模块的协同工作 + - 系统测试:测试整个系统功能 +4. **测试覆盖率**:关键模块测试覆盖率应达到80%以上 + +### 单元测试要求 + +1. **测试框架**:使用Ceedling或类似框架进行单元测试 +2. **测试用例**:每个关键函数必须有对应的测试用例 +3. **边界测试**:必须测试边界条件和异常情况 +4. **Mock对象**:使用Mock对象模拟硬件依赖 +5. **测试报告**:生成详细的测试报告和覆盖率报告 + +### 集成测试要求 + +1. **模块组合测试**:测试多个驱动模块的协同工作 +2. **协议通信测试**:测试完整的协议通信流程 +3. **硬件接口测试**:测试与真实硬件的接口(如有条件) +4. **性能测试**:测试系统性能指标(响应时间、吞吐量等) + +### 编译验证要求 + +1. **编译成功**:工程必须能够成功编译,生成可执行文件 +2. **零警告**:编译时应尽可能消除所有警告(特殊警告除外) +3. **代码规范检查**:使用静态代码分析工具检查代码规范 +4. **内存检查**:检查内存泄漏和缓冲区溢出问题 + +### 功能验证要求 + +1. **基本功能验证**:验证所有驱动的基本功能正常工作 +2. **协议验证**:验证通讯协议的正确性和可靠性 +3. **性能验证**:验证系统性能满足设计要求 +4. **稳定性验证**:长时间运行测试,验证系统稳定性 + +### 自动化测试流程 + +必须建立自动化测试流程,包括以下步骤: + +1. **代码编译**:自动编译工程,检查编译错误 +2. **单元测试**:自动运行所有单元测试 +3. **集成测试**:自动运行集成测试 +4. **静态分析**:自动运行静态代码分析 +5. **测试报告**:自动生成测试报告 + +### 测试用例示例 + +```c +// UART驱动测试用例示例 +void test_uart_init(void) { + ret_code_t ret = uart_init(); + TEST_ASSERT_EQUAL(RET_OK, ret); +} + +void test_uart_receive_fifo(void) { + // 测试FIFO缓冲区功能 + uint8_t test_data[] = {0xEB, 0x90, 0x0A, 0x01, 0x02, 0xAA, 0xBB, 0x3C}; + + // 模拟接收数据 + for (int i = 0; i < sizeof(test_data); i++) { + uart_fifo_write(test_data[i]); + } + + // 验证数据读取 + for (int i = 0; i < sizeof(test_data); i++) { + uint8_t data; + bool success = uart_fifo_read(&data); + TEST_ASSERT_TRUE(success); + TEST_ASSERT_EQUAL(test_data[i], data); + } +} + +// 伺服协议测试用例示例 +void test_servo_protocol_frame(void) { + servo_protocol_frame_t frame; + ret_code_t ret = servo_build_angle_ctrl_frame(1, 45.0f, 44.5f, &frame); + TEST_ASSERT_EQUAL(RET_OK, ret); + TEST_ASSERT_EQUAL(0xEB, frame.header_high); + TEST_ASSERT_EQUAL(0x90, frame.header_low); + TEST_ASSERT_EQUAL(0x0B, frame.device_id); +} +``` + +### 验证通过标准 + +工程必须满足以下标准才能视为验证通过: + +1. **编译通过**:无编译错误,警告控制在合理范围内 +2. **测试通过**:所有单元测试和集成测试通过 +3. **功能正常**:基本功能验证通过 +4. **性能达标**:性能指标满足设计要求 +5. **文档完整**:所有文档和注释完整准确 + +## 配置文件 + +1. 系统配置文件在CONFIG目录下的config.h文件中 +2. 系统配置文件中包含了系统参数的定义,如时钟频率、外设时钟频率等 + diff --git a/.trae/skills/create-project/references/PinConfig.md b/.trae/skills/create-project/references/PinConfig.md new file mode 100644 index 0000000..a3553a4 --- /dev/null +++ b/.trae/skills/create-project/references/PinConfig.md @@ -0,0 +1,49 @@ +# 单片机配置 +PY32MD530H28U7TR + +## 引脚配置表 + +| 引脚 | 功能 | 备注 | +|------|---- |---- | +| PA7 | LO1 | ͨ通道1低侧栅极驱动器输出 | +| PB0 | LO2 | ͨ通道2低侧栅极驱动器输出 | +| PB1 | LO3 | ͨ通道3低侧栅极驱动器输出 | +| PF3 | HO1 | ͨ通道1高侧栅极驱动器输出 | +| PF1 | HO2 | ͨ通道2高侧栅极驱动器输出 | +| PF0 | HO3 | ͨ通道3高侧栅极驱动器输出 | +| PA13 | SWDIO | ͨ调试数据引脚 | +| PA14 | SWCLK | ͨ调试时钟引脚 | +| PA9 | USART1_TXD | ͨUSART1发送引脚 | +| PA10 | USART1_RXD | ͨUSART1接收引脚 | +| PA3 | USART1_CTL | ͨUSART1控制引脚(RS485读、写) | +| PA0 | UART1_TX | ͨUART1发送引脚 | +| PA1 | UART1_RXD | ͨUART1接收引脚 | +| PA4 | LPUART1_TX | ͨLPUART1发送引脚 | +| PA2 | LPUART1_RXD | ͨLPUART1接收引脚 | +| PA12 | I2C_SDA | ͨI2C数据引脚 | +| PA11 | I2C_SCL | ͨI2C时钟引脚 | +| PA8 | DI_MAX | ͨ数字输入最大端点 | +| PB2 | DI_MIN | ͨ数字输入最小端点 | +| PA6 | LED | LED灯引脚 | +| PB5 | ID_1 | ͨ通道ID1输入 | +| PB6 | ID_2 | ͨ通道ID2输入 | +| PB7 | ID_3 | ͨ通道ID3输入 | +| PB8 | ID_4 | ͨ通道ID4输入 | +| PA15 | PGA2_INN | PGA通道2反向输入端 | +| PB3 | PGA2_INP | PGA通道2同向输入端 | + +## 外部器件 +| 外部器件 | 使用功能 | 备注 | +|------|---- |---- | +| EEPROM 24LC02 | I2C | 存储器 | +| AS5600 | I2C | 角度传感器 | +| ID指示器 | ID | 板子ID输入 | +| 电流采集 | PGA | 功率放大器 | +| 到位开关 | DI | 到位开关输入端 | +| debug串口 | UART | 调试串口 | +| 485串口 | USART1 | 485串口 | +| 备份串口 | LPUART1 | 备份串口 | +| LED灯 | LED | 板子LED灯 | +| NMOS驱动 | TIMER1 | NMOS驱动器 | + + diff --git a/.trae/skills/create-project/references/command.md b/.trae/skills/create-project/references/command.md new file mode 100644 index 0000000..2355f9f --- /dev/null +++ b/.trae/skills/create-project/references/command.md @@ -0,0 +1,157 @@ +# 指令说明 + +## Modbus 通讯参数 + +| 参数 | 值 | +|------|-----| +| 物理层 | RS485 半双工 | +| 串口 | UART1 (USART1) | +| 波特率 | 115200 | +| 数据位 | 8 | +| 校验位 | 无 | +| 停止位 | 1 | +| 主站地址 | `0xFE` | +| 从站地址 | `0x40 + ID`,ID 由 4 个 GPIO 引脚组合(范围 0~15),见 ID 指示器定义 | +| 协议 | Modbus RTU | + +## Modbus 功能码 + +| 功能 | 码值 | 说明 | +|------|------|------| +| 读保持寄存器 | `0x03` | 读取 1~125 个连续寄存器 | +| 写单个寄存器 | `0x06` | 写入 1 个寄存器 | + +## 寄存器映射 + +| 地址 | 名称 | 读写 | 数据类型 | 说明 | +|------|------|------|----------|------| +| `0x0000` | MOTOR_CURRENT | R | uint16 | 电机电流值 | +| `0x0001` | MOTOR_POSITION | R | int16 | 当前位置(步数) | +| `0x0002` | MOTOR_TARGET | R/W | int16 | 目标位置(步数) | +| `0x0003` | MOTOR_SPEED | R | uint16 | 当前速度 | +| `0x0004` | MOTOR_STATE | R | uint16 | 步进电机状态(0=空闲,1=加速,2=匀速,3=减速,4=停止,5=标定中) | +| `0x0005` | AS5600_ANGLE | R | uint16 | AS5600 角度值(0.1°精度,0~3599) | +| `0x0006` | AS5600_RAW | R | uint16 | AS5600 原始值 | +| `0x0007` | DI_MAX_STATE | R | uint16 | 最大值到位开关(0=未触发,1=触发) | +| `0x0008` | DI_MIN_STATE | R | uint16 | 最小值到位开关(0=未触发,1=触发) | +| `0x0009` | CALIBRATED_STEPS | R | uint16 | 标定的总步数 | +| `0x000A` | ORIGIN_STEPS | R | int16 | 原点步数(最小值位置) | +| `0x000B` | MAX_STEPS | R | int16 | 最大步数(最大值位置) | +| `0x000C` | IS_CALIBRATED | R | uint16 | 是否已标定(0=未标定,1=已标定) | +| `0x000D` | IS_DI_MAX_INSTALLED | R | uint16 | DI_MAX 是否安装(0=未安装,1=已安装) | +| `0x000E` | MODBUS_SLAVE_ADDR | R | uint16 | 当前 Modbus 从站地址(如 0x40~0x4F) | +| `0x000F` | DEVICE_ID | R | uint16 | 设备 ID(0~15) | +| `0x0020` | MOTOR_POSITION_H | R | int16 | 当前位置高 16 位 | +| `0x0021` | MOTOR_TARGET_H | R/W | int16 | 目标位置高 16 位 | +| `0x0022` | CALIBRATED_STEPS_H | R | uint16 | 标定总步数高 16 位 | +| `0x0023` | ORIGIN_STEPS_H | R | int16 | 原点步数高 16 位 | +| `0x0024` | MAX_STEPS_H | R | int16 | 最大步数高 16 位 | +| `0x0042` | CMD | W | uint16 | 指令寄存器(写入指令码触发动作) | +| `0x0043` | STATUS | R | uint16 | 整机状态(读寄存器) | +| `0x0044` | ANGLE_TARGET | R/W | uint16 | 角度目标值(单位 0.1°,范围 0~3600) | + +注:32 位数据(如位置、步数)拆分到两个 16 位寄存器中: +- 低 16 位在主地址(如 `0x0001`) +- 高 16 位在主地址 + 0x0020(如 `0x0021`) +- 读写时需分别操作两个寄存器。 + +## 指令码(CMD 寄存器 0x0042) + +写入 `0x0042` 寄存器触发动作,写完后硬件自动清零: + +| 指令码 | 名称 | 说明 | +|--------|------|------| +| `0x0001` | GO_MAX | 运行到最大值位置 | +| `0x0002` | GO_MIN | 运行到最小值位置(原点) | +| `0x0003` | STOP | 立即停止运行 | +| `0x0004` | GO_POSITION | 运行到指定步数(需先写入 MOTOR_TARGET) | +| `0x0005` | GO_ANGLE | 运行到指定角度(需先写入 ANGLE_TARGET) | +| `0x0006` | CALIBRATE | 开始标定 | +| `0x0007` | CALIB_END | 结束标定 | +| `0x0008` | READ_STATUS | 读取当前状态(读 STATUS 寄存器即可) | + +## 整机状态(STATUS 寄存器 0x0043) + +读取 `0x0043` 寄存器获取整机运行状态: + +| 状态码 | 名称 | 说明 | +|--------|------|------| +| `0x0000` | IDLE | 待机模式,等待指令 | +| `0x0001` | RUNNING | 正在运行(移动到目标位置中) | +| `0x0002` | CALIB | 正在标定 | +| `0x0003` | STOPPED | 已停止(执行停止指令后) | +| `0x0004` | ERROR | 错误状态 | + +## 通信示例 + +### 读当前位置 +``` +请求: FE 03 00 01 00 01 CRC_LO CRC_HI +响应: 40+ID 03 02 POS_HI POS_LO CRC_LO CRC_HI +``` + +### 读整机状态 +``` +请求: FE 03 00 43 00 01 CRC_LO CRC_HI +响应: 40+ID 03 02 00 01 CRC_LO CRC_HI <- 状态 = RUNNING +``` + +### 运行到最大值 +``` +请求: FE 06 00 42 00 01 CRC_LO CRC_HI +响应: 40+ID 06 00 42 00 01 CRC_LO CRC_HI +``` + +### 运行到指定步数(1000 步) +``` +请求: FE 06 00 02 03 E8 CRC_LO CRC_HI <- 写 MOTOR_TARGET = 1000 +响应: 40+ID 06 00 02 03 E8 CRC_LO CRC_HI +请求: FE 06 00 42 00 04 CRC_LO CRC_HI <- 写 CMD = GO_POSITION +响应: 40+ID 06 00 42 00 04 CRC_LO CRC_HI +``` + +### 运行到指定角度(45.0°) +``` +请求: FE 06 00 44 01 C2 CRC_LO CRC_HI <- 写 ANGLE_TARGET = 450(45.0°) +响应: 40+ID 06 00 44 01 C2 CRC_LO CRC_HI +请求: FE 06 00 42 00 05 CRC_LO CRC_HI <- 写 CMD = GO_ANGLE +响应: 40+ID 06 00 42 00 05 CRC_LO CRC_HI +``` + +### 读取多个寄存器(当前位置+速度+状态) +``` +请求: FE 03 00 01 00 04 CRC_LO CRC_HI +响应: 40+ID 03 08 POS_HI POS_LO TGT_HI TGT_LO SPD_HI SPD_LO STA_HI STA_LO CRC_LO CRC_HI +``` + +### 标定流程 +``` +请求: FE 06 00 42 00 06 CRC_LO CRC_HI <- 开始标定 +响应: 40+ID 06 00 42 00 06 CRC_LO CRC_HI +(标定执行中...) +请求: FE 03 00 43 00 01 CRC_LO CRC_HI <- 查询状态 +响应: 40+ID 03 02 00 02 CRC_LO CRC_HI <- 状态 = CALIB +... +请求: FE 06 00 42 00 07 CRC_LO CRC_HI <- 结束标定 +响应: 40+ID 06 00 42 00 07 CRC_LO CRC_HI +``` + +### 停止运行 +``` +请求: FE 06 00 42 00 03 CRC_LO CRC_HI +响应: 40+ID 06 00 42 00 03 CRC_LO CRC_HI +``` + +## 从站地址计算 + +设备 ID 由 4 个 GPIO 引脚 (PB5~PB8) 读取: + +| PB8 | PB7 | PB6 | PB5 | ID | 从站地址 | +|-----|-----|-----|-----|----|----------| +| 0 | 0 | 0 | 0 | 0 | `0x40` | +| 0 | 0 | 0 | 1 | 1 | `0x41` | +| 0 | 0 | 1 | 0 | 2 | `0x42` | +| ... | ... | ... | ... | ... | ... | +| 1 | 1 | 1 | 1 | 15 | `0x4F` | + +从站地址计算公式:`0x40 + ID` diff --git a/.trae/skills/create-project/references/function.md b/.trae/skills/create-project/references/function.md new file mode 100644 index 0000000..4b29c4c --- /dev/null +++ b/.trae/skills/create-project/references/function.md @@ -0,0 +1,68 @@ +# 功能描述 +此文件用于描述每个设备功能以及运行逻辑 + +## DEBUG串口 +使用的是UART1,波特率为115200,数据位8位,无校验位,1个停止位 +使用printf进行打印,需要构建一个log功能,格式如下: +``` +log_out("DEBUG: %s\n", "hello world"); +log_out("INFO: %d\n", 123); +``` + + +## 2相四线步进电机驱动 +使用的是TIM1, + +### 正常运行功能 +步进电机驱动使用S型加减速算法,根据DI_MIN和DI_MAX两个输入,根据当前位置和目标位置计算出步数,然后根据步数进行步进电机的运行。 +如果DI_MAX不装配,那么使用原点开关和标定的步数进行计算导轨长度,到达最大值时,必须停止。 + +### 标定功能 +使用标定功能时,如果最小和最大开关安装,那么运行到最小和最大开关触发,几下运行步数,如果DI_MAX不安装,那么根据原点开关和标定的步数来标定最大值。标定值认为输入。 + +## LED驱动 +使用高低电平控制LED亮灭,高电平LED灭,低电平亮 + +## RS485串口接口 +使用UART1,波特率为115200,数据位8位,无校验位,1个停止位 +使用modbus协议,从站地址为0x40+ID,ID为读取四个ID引脚组成的值,每个ID引脚为0或1,组成一个8位的值。主站地址为0xfe。 + +一个共有这几个指令,去到最大值,去到最小值,停止运行,去到指令步数,去到指定角度,开始标定,结束标定 + +## ID指示器 +使用的是GPIO引脚,根据ID引脚的值,来组合成当前的ID。 + +## AS5600角度传感器 +使用I2C1,地址为 0x36,数据位8位,无校验位,1个停止位 +读取角度数字后,需要根据角度数字进行转换,转换为角度值。存储到系统数据总线中便于其他逻辑使用 + + +## AT24C02存储器 +使用I2C1,地址为0x00,数据位8位,无校验位,1个停止位 +使用I2C协议,从站地址为0x50,主站地址为0x00 + +## 功率放大器 +使用的PGA功能,输入总电流,通过转换,使用内部ADC读取采样值,然后转换成电流值。存储到系统数据总线中便于其他逻辑使用。 + +## 输入开关 +采集数据后存到系统数据总线中,便于其他逻辑使用。 +DI_MIN是最小值到位开关,当导轨运行到原点时会触发,这个开关是必须装配,可以作为参考点。 +使用DI_MAX是最大值到位开关,当导轨运行到最大值时会触发,也有可能不装这个开关,需要根据原点和步进电机运行步数来标定最大值。 + +DI_MIN和DI_MAX输入逻辑为高电平有效。 + + +## 整机逻辑 + +系统初始化完成后,进入待机模式,等待RS485串口发来的指令。 +如果收到最大指令,运行到最大值,然后停下,继续等待下一步指令, +如果收到最小指令,运行到最小值,然后停下,继续等待下一步指令, +如果收到停止指令,停止运行,继续等待下一步指令, +如果收到指定步数,或者指定角度指令,根据指令进行运行,然后停下,继续等待下一步指令。 +如果收到读取当前状态的指令,返回当前位置,最大,最小或者某个特定的位置。 + + + + + + diff --git a/.trae/skills/download-lib/SKILL.md b/.trae/skills/download-lib/SKILL.md new file mode 100644 index 0000000..fad7d24 --- /dev/null +++ b/.trae/skills/download-lib/SKILL.md @@ -0,0 +1,633 @@ +*** +name: "download-lib" +description: "下载嵌入式开发所需的库文件(STM32/GD32/CH32等)。在创建新工程、更新库版本、切换芯片平台或需要确保团队库版本一致时调用此技能。" +version: 1.1.0 +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + +# DOWNLOAD-LIB 技能 + +该技能用于自动化下载嵌入式开发所需的硬件库文件,支持多种微控制器平台,并提供完整的工程集成方案。 + +## 技能概述 + +`download-lib` 技能是一个嵌入式开发辅助工具,专门用于管理和下载微控制器硬件外设库。它解决了嵌入式开发中常见的库文件管理问题: +- 不同芯片平台的库文件获取 +- 库版本管理和一致性 +- 工程集成自动化 +- 团队协作中的库同步 + +## 功能特点 + +### 支持的平台 +- **STM32系列**:STM32F0/F1/F2/F3/F4/F7/H7等全系列 +- **GD32系列**:GD32F1/F2/F3/F4/F5等全系列 +- **CH32系列**:CH32V/V3/F1/F2等全系列 +- **其他ARM Cortex-M系列MCU** + +### 核心功能 +1. **智能下载**:自动识别芯片型号并下载对应的库文件 +2. **版本管理**:支持特定版本、最新版本和版本锁定 +3. **完整性校验**:下载后验证文件完整性(MD5/SHA256) +4. **工程集成**:自动更新构建系统(CMake/Makefile) +5. **离线支持**:支持本地缓存和离线安装模式 + +## 调用时机 + +在以下情况下调用此技能: + +### 1. 新工程创建 +- 创建基于STM32/GD32/CH32的新嵌入式项目时 +- 需要快速建立工程框架和依赖库时 + +### 2. 库版本更新 +- 需要更新现有工程的外设库到新版本时 +- 修复已知bug或使用新特性时 + +### 3. 平台迁移 +- 项目从一种MCU迁移到另一种MCU时 +- 需要同时支持多种芯片平台时 + +### 4. 团队协作 +- 确保团队成员使用相同的库版本时 +- 新成员快速搭建开发环境时 + +### 5. 离线开发准备 +- 准备离线开发环境,预先下载所有依赖库 +- 为无网络环境准备开发包时 + +## 工作流程 + +### 完整工作流程 +```mermaid +graph TD + A[用户请求下载库文件] --> B{芯片类型选择} + B --> C[STM32] + B --> D[GD32] + B --> E[CH32] + C --> F[选择具体系列] + D --> F + E --> F + F --> G[选择版本号] + G --> H[选择下载源] + H --> I[执行下载] + I --> J[完整性校验] + J --> K[工程集成] + K --> L[生成报告] + L --> M[完成] +``` + +### 详细步骤 + +#### 步骤1:参数收集 +1. **芯片类型**:用户选择目标芯片平台(STM32/GD32/CH32) +2. **芯片系列**:指定具体芯片系列(如GD32F450、STM32F407等) +3. **库版本**:选择库版本号(如v1.0.0、latest等) +4. **下载源**:选择下载来源(官方GitHub、厂商网站、镜像站等) +5. **目标目录**:指定库文件存放位置(默认:`项目根目录/libs/`) + +#### 步骤2:库文件下载 +1. **源地址解析**:根据芯片类型和版本构建下载URL + - STM32:`https://github.com/STMicroelectronics/STM32CubeF4` + - GD32:`https://github.com/GigaDevice/GD32F4xx_Standard_Peripheral_Lib` + - CH32:`https://github.com/openwch/ch32`(示例) +2. **下载方式**: + - Git clone(推荐,支持版本管理) + - 直接下载ZIP包 + - 使用wget/curl命令行工具 +3. **进度显示**:实时显示下载进度和状态 + +#### 步骤3:文件处理 +1. **解压与整理**:如有需要,解压文件并整理目录结构 +2. **文件筛选**:只保留必要的库文件,移除示例、文档等非必需文件 +3. **目录规范化**:按照标准目录结构组织文件 + ``` + libs/ + ├── CMSIS/ # ARM CMSIS核心库 + ├── thirdparty/ + │ └── GD32F4xx/ # 具体芯片的外设库 + │ ├── Include/ + │ ├── Source/ + │ └── README.md + └── version.txt # 版本信息文件 + ``` + +#### 步骤4:完整性校验 +1. **哈希校验**:计算下载文件的MD5或SHA256值 +2. **大小验证**:检查文件大小是否符合预期 +3. **结构验证**:验证目录结构是否完整 +4. **关键文件检查**:确保核心头文件和源文件存在 + +#### 步骤5:工程集成 +1. **构建系统更新**: + - **CMake**:更新`CMakeLists.txt`,添加库文件路径 + - **Makefile**:更新编译规则和包含路径 + - **Keil/IAR**:生成对应的工程文件(可选) +2. **头文件路径配置**:自动添加必要的头文件搜索路径 +3. **依赖关系配置**:设置库文件之间的依赖关系 + +#### 步骤6:报告生成 +1. **下载摘要**:显示下载的文件数量、大小和时间 +2. **版本信息**:记录下载的库版本和芯片信息 +3. **集成状态**:显示工程集成是否成功 +4. **问题提示**:如有问题,提供解决方案建议 + +## 参数定义 + +### 输入参数 +```yaml +# 必选参数 +chip_type: # 芯片类型 + type: enum + values: [stm32, gd32, ch32, other] + required: true + +chip_series: # 芯片系列 + type: string + examples: ["GD32F450", "STM32F407", "CH32V307"] + required: true + +# 可选参数 +library_version: # 库版本 + type: string + default: "latest" + examples: ["v1.0.0", "v2.1.3", "latest"] + +download_source: # 下载源 + type: enum + values: [github, official, custom] + default: "github" + +target_directory: # 目标目录 + type: string + default: "./libs/" + +skip_integration: # 跳过工程集成 + type: boolean + default: false + +offline_mode: # 离线模式 + type: boolean + default: false + description: "从本地缓存安装,无需网络" +``` + +### 输出结果 +```yaml +success: true/false +message: "操作结果描述" +downloaded_files: + count: 42 + total_size: "15.7MB" + duration: "45秒" +library_info: + name: "GD32F4xx Standard Peripheral Library" + version: "v1.0.0" + chip: "GD32F450VG" + release_date: "2023-06-15" +integration_status: + cmake_updated: true + include_paths_added: ["libs/thirdparty/GD32F4xx/Include"] + source_files_added: ["libs/thirdparty/GD32F4xx/Source/*.c"] +``` + +## 示例和模板 + +### 示例1:下载GD32F4xx库 +```bash +# 通过技能调用下载GD32F4xx最新版本 +download-lib --chip-type gd32 --chip-series GD32F450 --version latest +``` + +**执行结果**: +``` +✅ 开始下载GD32F4xx库... +📦 下载源:https://github.com/GigaDevice/GD32F4xx_Standard_Peripheral_Lib +🔍 选择版本:latest (v1.0.0) +⬇️ 下载中:15.7MB [██████████] 100% +✅ 下载完成:42个文件,耗时45秒 +🔒 完整性校验:通过(SHA256匹配) +📁 文件组织:libs/thirdparty/GD32F4xx/ +🛠️ 工程集成:CMakeLists.txt已更新 +📊 报告生成:download_report_20250409_142356.json +🎉 完成!GD32F450库已就绪。 +``` + +### 示例2:下载特定版本的STM32库 +```bash +# 下载STM32F4xx v1.27.0版本 +download-lib \ + --chip-type stm32 \ + --chip-series STM32F407 \ + --version v1.27.0 \ + --target-directory ./vendor/stm32 \ + --skip-integration +``` + +### 示例3:离线模式(从缓存安装) +```bash +# 从本地缓存安装,无需网络连接 +download-lib \ + --chip-type gd32 \ + --chip-series GD32F450 \ + --offline-mode \ + --cache-directory ~/.cache/embedded-libs +``` + +### 模板1:Bash下载脚本 +```bash +#!/bin/bash +# download_library.sh - 库文件下载脚本模板 + +set -e # 出错时退出 + +# 配置参数 +CHIP_TYPE=${1:-gd32} +CHIP_SERIES=${2:-GD32F450} +VERSION=${3:-latest} +TARGET_DIR=${4:-./libs} +CACHE_DIR="${HOME}/.cache/embedded-libs" + +# 下载URL映射 +declare -A LIBRARY_URLS=( + ["gd32"]="https://github.com/GigaDevice/GD32F4xx_Standard_Peripheral_Lib" + ["stm32_f4"]="https://github.com/STMicroelectronics/STM32CubeF4" + ["ch32_v"]="https://github.com/openwch/ch32" +) + +# 获取下载URL +get_download_url() { + local chip=$1 + local series=$2 + + case $chip in + "gd32") + echo "${LIBRARY_URLS[gd32]}" + ;; + "stm32") + # 根据系列选择具体的STM32库 + if [[ $series == STM32F4* ]]; then + echo "${LIBRARY_URLS[stm32_f4]}" + else + echo "错误:不支持的STM32系列: $series" >&2 + exit 1 + fi + ;; + *) + echo "错误:不支持的芯片类型: $chip" >&2 + exit 1 + ;; + esac +} + +# 主函数 +main() { + echo "🔍 芯片: $CHIP_TYPE $CHIP_SERIES" + echo "📦 版本: $VERSION" + + # 创建目标目录 + mkdir -p "$TARGET_DIR" + + # 获取下载URL + DOWNLOAD_URL=$(get_download_url "$CHIP_TYPE" "$CHIP_SERIES") + echo "🌐 下载源: $DOWNLOAD_URL" + + # 执行下载 + if [[ "$VERSION" == "latest" ]]; then + git clone --depth 1 "$DOWNLOAD_URL" "${TARGET_DIR}/temp" + else + git clone --branch "$VERSION" --depth 1 "$DOWNLOAD_URL" "${TARGET_DIR}/temp" + fi + + # 整理文件 + organize_files + + # 清理临时文件 + rm -rf "${TARGET_DIR}/temp" + + echo "✅ 下载完成" +} + +# 文件整理函数 +organize_files() { + local temp_dir="${TARGET_DIR}/temp" + + # GD32库的特殊处理 + if [[ "$CHIP_TYPE" == "gd32" ]]; then + # 复制必要的文件 + mkdir -p "${TARGET_DIR}/thirdparty/GD32F4xx" + cp -r "${temp_dir}/Firmware/GD32F4xx_standard_peripheral/Include" \ + "${TARGET_DIR}/thirdparty/GD32F4xx/" + cp -r "${temp_dir}/Firmware/GD32F4xx_standard_peripheral/Source" \ + "${TARGET_DIR}/thirdparty/GD32F4xx/" + fi + + # 添加其他芯片类型的处理逻辑... +} + +# 执行主函数 +main "$@" +``` + +### 模板2:CMake集成配置 +```cmake +# CMakeLists.txt - 库集成模板 +cmake_minimum_required(VERSION 3.16) + +# 检测库文件是否存在 +macro(check_required_library lib_name lib_path) + if(NOT EXISTS ${lib_path}) + message(WARNING "缺少库文件: ${lib_name}") + message(STATUS "请运行: download-lib --chip-type gd32 --chip-series GD32F450") + set(${lib_name}_FOUND FALSE) + else() + set(${lib_name}_FOUND TRUE) + message(STATUS "找到库: ${lib_name}") + endif() +endmacro() + +# 检查GD32库 +check_required_library(GD32F4XX_LIB "${CMAKE_SOURCE_DIR}/libs/thirdparty/GD32F4xx") + +if(GD32F4XX_LIB_FOUND) + # 添加包含路径 + include_directories( + ${CMAKE_SOURCE_DIR}/libs/thirdparty/GD32F4xx/Include + ${CMAKE_SOURCE_DIR}/libs/CMSIS/Core/Include + ${CMAKE_SOURCE_DIR}/libs/CMSIS/GD/GD32F4xx/Include + ) + + # 添加源文件 + file(GLOB GD32_SOURCES + ${CMAKE_SOURCE_DIR}/libs/thirdparty/GD32F4xx/Source/*.c + ) + + # 添加到工程源文件列表 + list(APPEND PROJECT_SOURCES ${GD32_SOURCES}) +endif() + +# 类似的,可以添加其他库的检查 +``` + +### 模板3:Python下载脚本 +```python +#!/usr/bin/env python3 +# download_lib.py - Python版本库下载器 + +import os +import sys +import requests +import hashlib +import zipfile +import json +from pathlib import Path + +class LibraryDownloader: + """库文件下载器""" + + def __init__(self, chip_type, chip_series, version="latest"): + self.chip_type = chip_type + self.chip_series = chip_series + self.version = version + self.base_urls = { + "gd32": "https://api.github.com/repos/GigaDevice/GD32F4xx_Standard_Peripheral_Lib", + "stm32": "https://api.github.com/repos/STMicroelectronics/STM32CubeF4", + } + + def download(self, target_dir="libs"): + """执行下载""" + print(f"下载 {self.chip_type} {self.chip_series} 库...") + + # 获取下载信息 + download_info = self.get_download_info() + + # 创建目标目录 + target_path = Path(target_dir) + target_path.mkdir(parents=True, exist_ok=True) + + # 下载文件 + self.download_file(download_info['url'], target_path) + + # 验证完整性 + if self.verify_integrity(target_path, download_info.get('checksum')): + print("✅ 完整性验证通过") + else: + print("⚠️ 完整性验证失败") + + # 生成版本文件 + self.generate_version_file(target_path, download_info) + + return True + + def get_download_info(self): + """获取下载信息""" + # 这里实现具体的API调用逻辑 + # 返回包含url、version、checksum等信息的字典 + pass + + # 其他方法实现... + +if __name__ == "__main__": + # 使用示例 + downloader = LibraryDownloader("gd32", "GD32F450", "latest") + downloader.download() +``` + +## 错误处理 + +### 常见错误及解决方案 + +#### 错误1:网络连接失败 +``` +❌ 错误:无法连接到下载服务器 +``` +**可能原因**: +- 网络连接问题 +- 下载源URL变更 +- 防火墙或代理限制 + +**解决方案**: +1. 检查网络连接 +2. 使用镜像源:`--download-source mirror` +3. 离线模式:`--offline-mode --cache-dir /path/to/cache` +4. 手动下载并指定本地路径 + +#### 错误2:版本不存在 +``` +❌ 错误:版本 v2.5.0 不存在 +``` +**可能原因**: +- 版本号输入错误 +- 该版本已被删除 +- 芯片系列不支持该版本 + +**解决方案**: +1. 查看可用版本:`download-lib --list-versions gd32 GD32F450` +2. 使用最新版本:`--version latest` +3. 指定正确的版本格式 + +#### 错误3:磁盘空间不足 +``` +❌ 错误:磁盘空间不足,需要 200MB,可用 50MB +``` +**解决方案**: +1. 清理磁盘空间 +2. 指定其他存储位置:`--target-directory /mnt/external/libs` +3. 仅下载必要文件:`--minimal`(只下载核心库文件) + +#### 错误4:权限不足 +``` +❌ 错误:无法创建目录 /usr/local/libs,权限被拒绝 +``` +**解决方案**: +1. 使用用户目录:`--target-directory ~/projects/libs` +2. 使用sudo权限(谨慎) +3. 更改目录权限 + +### 错误恢复机制 + +#### 断点续传 +```bash +# 支持断点续传 +download-lib --resume --partial-dir ./download-tmp +``` + +#### 完整性恢复 +```bash +# 如果下载中断,可以恢复完整性检查 +download-lib --verify-only --repair +``` + +## 最佳实践 + +### 1. 版本锁定 +```bash +# 在生产环境中使用固定版本 +download-lib --chip-type gd32 --chip-series GD32F450 --version v1.0.0 +``` + +### 2. 团队一致性 +```bash +# 创建版本锁定文件 +download-lib --generate-lockfile > library-lock.json + +# 其他成员使用锁文件恢复 +download-lib --from-lockfile library-lock.json +``` + +### 3. CI/CD集成 +```yaml +# .gitlab-ci.yml 示例 +stages: + - setup + +setup_libraries: + stage: setup + script: + - download-lib --chip-type gd32 --chip-series GD32F450 --version latest + - download-lib --chip-type stm32 --chip-series STM32F103 --version v1.8.0 + artifacts: + paths: + - libs/ + expire_in: 30 days +``` + +### 4. 离线开发环境 +```bash +# 在可联网环境中准备离线包 +download-lib --chip-type gd32 --chip-series GD32F450 --bundle --output gd32-bundle.tar.gz + +# 在离线环境中安装 +download-lib --install-bundle gd32-bundle.tar.gz +``` + +## 扩展功能 + +### 插件系统 +支持通过插件扩展新的芯片平台: + +```bash +# 注册新的芯片支持 +download-lib --register-chip \ + --name AT32 \ + --url-template "https://github.com/ArteryTek/AT32F4xx_Library" \ + --file-structure "Firmware/AT32F4xx_standard_peripheral" +``` + +### 自定义下载源 +```bash +# 使用自定义的下载源 +download-lib \ + --chip-type gd32 \ + --download-source custom \ + --custom-url "http://internal-mirror.company.com/gd32-libs" +``` + +### 批量操作 +```bash +# 批量下载多个库 +download-lib --batch libraries.json +``` + +**libraries.json**: +```json +{ + "libraries": [ + { + "chip_type": "gd32", + "chip_series": "GD32F450", + "version": "latest" + }, + { + "chip_type": "stm32", + "chip_series": "STM32F103", + "version": "v1.8.0" + } + ] +} +``` + +## 与当前工程的集成示例 + +### ServoTest工程集成 +对于您的`ServoTest`工程(基于GD32F450VG),技能可以: + +1. **确保库版本一致**: + ```bash + # 检查当前库版本 + download-lib --check-version --chip-type gd32 --chip-series GD32F450 + + # 更新到指定版本 + download-lib --chip-type gd32 --chip-series GD32F450 --version v1.0.0 + ``` + +2. **多平台支持**: + ```bash + # 如果需要支持STM32作为备选平台 + download-lib --chip-type stm32 --chip-series STM32F407 --target-directory ./libs/stm32-backup + ``` + +3. **依赖管理**: + ```bash + # 生成依赖报告 + download-lib --dependencies --output deps.html + ``` + +## 更新日志 + +### v1.1.0 (2024-04-09) +- 完全重写技能文档 +- 添加详细的工作流程和参数定义 +- 提供多个示例脚本和模板 +- 完善错误处理和最佳实践 +- 添加与ServoTest工程的集成示例 + +### v1.0.0 (初始版本) +- 基础技能框架 +- 支持STM32/GD32/CH32芯片 +- 基本的下载功能 + +--- + +**技能维护者**:嵌入式系统开发团队 +**最后更新**:2024-04-09 +**技能状态**:✅ 生产就绪 \ No newline at end of file diff --git a/.trae/skills/download-tools/SKILL.md b/.trae/skills/download-tools/SKILL.md new file mode 100644 index 0000000..64b3f50 --- /dev/null +++ b/.trae/skills/download-tools/SKILL.md @@ -0,0 +1,718 @@ +*** + +name: "download-tools" +description: "嵌入式开发工具链下载和管理技能" +version: "2.0.0" +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +# 嵌入式开发工具链下载和管理技能 + +## 概述 + +`download-tools` 技能是一个专业的嵌入式开发工具链管理工具,专门用于自动化下载、安装、配置和验证嵌入式开发所需的各种工具链。作为 OpenClaw 集成专家,我深知稳定可靠的开发环境对于嵌入式项目成功至关重要。本技能提供跨平台支持,确保开发工具的一致性和可重复性。 + +## 核心特性 + +### 1. 多平台支持 +- **Windows**: 支持原生 PowerShell、CMD 和 Git Bash +- **Linux**: 支持 Ubuntu、Debian、Fedora、Arch 等主流发行版 +- **macOS**: 支持 Intel 和 Apple Silicon 架构 + +### 2. 工具链覆盖 +- **编译工具链**: ARM GCC、RISC-V GCC、Xtensa GCC、Clang +- **调试工具**: J-Link、OpenOCD、ST-Link、pyOCD +- **烧录工具**: esptool、STM32CubeProgrammer、GD32AllInOne +- **串口工具**: minicom、screen、putty、serial terminal +- **构建系统**: CMake、Make、Ninja、Meson +- **开发环境**: Python 环境、VS Code 扩展、Eclipse 插件 + +### 3. 智能管理 +- **版本锁定**: 确保工具版本一致性 +- **依赖解析**: 自动处理工具依赖关系 +- **完整性校验**: 下载后验证工具完整性 +- **环境配置**: 自动配置 PATH 和环境变量 +- **离线支持**: 支持离线安装和本地缓存 + +## 工作流程 + +```mermaid +flowchart TD + A[开始工具链管理] --> B{选择操作模式} + B --> C[安装模式] + B --> D[更新模式] + B --> E[验证模式] + B --> F[清理模式] + + C --> C1[检查系统兼容性] + C1 --> C2[解析工具依赖] + C2 --> C3[下载工具文件] + C3 --> C4[安装和配置] + C4 --> C5[验证安装结果] + C5 --> G[完成] + + D --> D1[检查可用更新] + D1 --> D2[备份当前版本] + D2 --> D3[下载新版本] + D3 --> D4[更新配置] + D4 --> C5 + + E --> E1[检查工具状态] + E1 --> E2[验证版本兼容性] + E2 --> E3[测试基本功能] + E3 --> E4[生成验证报告] + E4 --> G + + F --> F1[清理临时文件] + F1 --> F2[卸载旧版本] + F2 --> F3[恢复环境配置] + F3 --> G +``` + +## 参数定义 + +### YAML 配置格式 + +```yaml +# tools-config.yaml +version: "2.0.0" +platform: "auto" # auto, windows, linux, macos + +tools: + # 编译工具链 + arm_gcc: + enabled: true + version: "12.3.rel1" + variant: "arm-none-eabi" + sources: + windows: "https://developer.arm.com/-/media/Files/downloads/gnu/12.3.rel1/binrel/arm-gnu-toolchain-12.3.rel1-mingw-w64-i686-arm-none-eabi.zip" + linux: "https://developer.arm.com/-/media/Files/downloads/gnu/12.3.rel1/binrel/arm-gnu-toolchain-12.3.rel1-x86_64-arm-none-eabi.tar.xz" + macos: "https://developer.arm.com/-/media/Files/downloads/gnu/12.3.rel1/binrel/arm-gnu-toolchain-12.3.rel1-darwin-x86_64-arm-none-eabi.tar.xz" + install_path: "${TOOLS_DIR}/gcc-arm" + env_vars: + PATH: "${install_path}/bin" + ARM_GCC_PATH: "${install_path}" + verification: + command: "arm-none-eabi-gcc --version" + expected_output: "12.3.1" + + # 调试工具 + jlink: + enabled: true + version: "v7.96" + sources: + windows: "https://www.segger.com/downloads/jlink/JLink_Windows_V796.exe" + linux: "https://www.segger.com/downloads/jlink/JLink_Linux_V796_x86_64.deb" + macos: "https://www.segger.com/downloads/jlink/JLink_MacOSX_V796.pkg" + install_path: "${TOOLS_DIR}/jlink" + env_vars: + PATH: "${install_path}" + verification: + command: "JLinkExe --version" + + # 构建工具 + cmake: + enabled: true + version: "3.28.3" + sources: + windows: "https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-windows-x86_64.zip" + linux: "https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-linux-x86_64.tar.gz" + macos: "https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-macos-universal.tar.gz" + install_path: "${TOOLS_DIR}/cmake" + env_vars: + PATH: "${install_path}/bin" + + # Python 环境 + python: + enabled: true + version: "3.11.0" + packages: + - "pyserial==3.5" + - "pyocd==0.36.0" + - "esptool==4.6.2" + - "cmsis-pack-manager==0.5.1" + install_path: "${TOOLS_DIR}/python" + env_vars: + PATH: "${install_path}/Scripts:${install_path}/bin" + PYTHONPATH: "${install_path}/Lib/site-packages" + +# 配置选项 +config: + download_timeout: 300 # 秒 + retry_count: 3 + verify_ssl: true + offline_mode: false + cache_dir: "${HOME}/.cache/embedded-tools" + tools_dir: "${PROJECT_ROOT}/tools" + +# 芯片特定配置 +chip_profiles: + gd32: + required_tools: ["arm_gcc", "cmake", "python"] + recommended_tools: ["jlink", "openocd"] + + stm32: + required_tools: ["arm_gcc", "cmake", "python", "stlink"] + recommended_tools: ["stm32cubeprogrammer"] + + ch32: + required_tools: ["riscv_gcc", "cmake", "python"] + recommended_tools: ["wch-link", "openocd"] +``` + +### 命令行参数 + +```bash +# 基本用法 +download-tools --config tools-config.yaml +download-tools --profile gd32 --install-path ./tools + +# 特定操作 +download-tools --install arm_gcc cmake python +download-tools --update --tools jlink openocd +download-tools --verify --report-format json +download-tools --clean --keep-versions 3 + +# 配置选项 +download-tools --offline --cache-dir ./local-cache +download-tools --platform windows --arch x86_64 +download-tools --timeout 600 --retry 5 + +# 信息查询 +download-tools --list-available +download-tools --check-updates +download-tools --version-info +``` + +## 工具配置详情 + +### 1. ARM GCC 工具链 +- **官方源**: Arm Developer 网站 +- **镜像源**: 清华大学 TUNA、中科大 USTC +- **版本策略**: 支持 LTS 版本和最新版本 +- **架构支持**: arm-none-eabi、arm-eabi、aarch64-none-elf + +### 2. J-Link 调试工具 +- **许可证管理**: 自动处理个人/商业许可证 +- **驱动安装**: 自动安装 USB 驱动程序 +- **配置生成**: 自动生成 J-Link 配置文件 +- **脚本支持**: 集成 J-Link 脚本功能 + +### 3. OpenOCD +- **芯片支持**: STM32、GD32、ESP32、RISC-V +- **接口支持**: J-Link、ST-Link、CMSIS-DAP、FTDI +- **配置模板**: 预定义目标板配置文件 +- **服务管理**: 系统服务/守护进程配置 + +### 4. ST-Link +- **工具集**: ST-Link CLI、ST-Link Server、STM32CubeProgrammer +- **固件更新**: 自动检测和更新 ST-Link 固件 +- **多平台**: Windows、Linux、macOS 统一接口 + +### 5. Python 环境 +- **虚拟环境**: 自动创建隔离的 Python 环境 +- **包管理**: 自动安装嵌入式开发相关包 +- **路径隔离**: 避免与系统 Python 冲突 +- **版本兼容**: 确保与工具链的兼容性 + +## 平台特定实现 + +### Windows 实现 +```powershell +# PowerShell 实现示例 +function Install-ArmGcc { + param( + [string]$Version = "12.3.rel1", + [string]$InstallPath = "$env:USERPROFILE\.embedded-tools\gcc-arm" + ) + + # 下载和安装逻辑 + $url = "https://developer.arm.com/-/media/Files/downloads/gnu/$Version/binrel/arm-gnu-toolchain-$Version-mingw-w64-i686-arm-none-eabi.zip" + $tempFile = "$env:TEMP\arm-gcc-$Version.zip" + + # 下载 + Invoke-WebRequest -Uri $url -OutFile $tempFile + + # 解压 + Expand-Archive -Path $tempFile -DestinationPath $InstallPath -Force + + # 环境配置 + $binPath = "$InstallPath\bin" + $currentPath = [Environment]::GetEnvironmentVariable("PATH", "User") + if ($currentPath -notlike "*$binPath*") { + [Environment]::SetEnvironmentVariable("PATH", "$binPath;$currentPath", "User") + } + + # 验证 + & "$binPath\arm-none-eabi-gcc.exe" --version +} +``` + +### Linux 实现 +```bash +#!/bin/bash +# Bash 实现示例 +install_arm_gcc() { + local version="${1:-12.3.rel1}" + local install_path="${2:-$HOME/.embedded-tools/gcc-arm}" + + # 检测架构 + local arch=$(uname -m) + local url="" + + case $arch in + x86_64) + url="https://developer.arm.com/-/media/Files/downloads/gnu/$version/binrel/arm-gnu-toolchain-$version-x86_64-arm-none-eabi.tar.xz" + ;; + aarch64) + url="https://developer.arm.com/-/media/Files/downloads/gnu/$version/binrel/arm-gnu-toolchain-$version-aarch64-arm-none-eabi.tar.xz" + ;; + *) + echo "Unsupported architecture: $arch" + return 1 + ;; + esac + + # 下载和安装 + mkdir -p "$install_path" + wget -q "$url" -O /tmp/arm-gcc.tar.xz + tar -xf /tmp/arm-gcc.tar.xz -C "$install_path" --strip-components=1 + + # 环境配置 + echo "export PATH=\"$install_path/bin:\$PATH\"" >> ~/.bashrc + echo "export ARM_GCC_PATH=\"$install_path\"" >> ~/.bashrc + + # 验证 + "$install_path/bin/arm-none-eabi-gcc" --version +} +``` + +### macOS 实现 +```bash +#!/bin/bash +# macOS 实现示例 +install_arm_gcc_macos() { + local version="${1:-12.3.rel1}" + local install_path="${2:-$HOME/Library/EmbeddedTools/gcc-arm}" + + # 检测芯片架构 + local chip=$(uname -m) + local url="" + + if [[ "$chip" == "arm64" ]]; then + url="https://developer.arm.com/-/media/Files/downloads/gnu/$version/binrel/arm-gnu-toolchain-$version-darwin-arm64-arm-none-eabi.tar.xz" + else + url="https://developer.arm.com/-/media/Files/downloads/gnu/$version/binrel/arm-gnu-toolchain-$version-darwin-x86_64-arm-none-eabi.tar.xz" + fi + + # 使用 Homebrew 风格安装 + mkdir -p "$install_path" + curl -L "$url" | tar -xJ -C "$install_path" --strip-components=1 + + # 环境配置 + echo "export PATH=\"$install_path/bin:\$PATH\"" >> ~/.zshrc + echo "export ARM_GCC_PATH=\"$install_path\"" >> ~/.zshrc + + # 验证 + "$install_path/bin/arm-none-eabi-gcc" --version +} +``` + +## 安装验证 + +### 验证脚本示例 +```python +#!/usr/bin/env python3 +# verification.py +import subprocess +import sys +import json +from pathlib import Path + +def verify_tool(tool_name, command, expected_output=None): + print(f"验证工具: {tool_name}") + print(f"命令: {command}") + + try: + result = subprocess.run( + command, + shell=True, + capture_output=True, + text=True, + timeout=30 + ) + + if result.returncode == 0: + print(f"✓ {tool_name} 验证成功") + + if expected_output: + if expected_output in result.stdout: + print(f"✓ 版本匹配: {expected_output}") + else: + print(f"✗ 版本不匹配") + print(f" 期望: {expected_output}") + print(f" 实际: {result.stdout[:100]}...") + return False + return True + else: + print(f"✗ {tool_name} 验证失败") + print(f" 错误: {result.stderr}") + return False + + except subprocess.TimeoutExpired: + print(f"✗ {tool_name} 验证超时") + return False + except Exception as e: + print(f"✗ {tool_name} 验证异常: {e}") + return False + +def main(): + verification_spec = { + "arm_gcc": { + "command": "arm-none-eabi-gcc --version", + "expected": "12.3.1" + }, + "cmake": { + "command": "cmake --version", + "expected": "3.28" + }, + "python": { + "command": "python --version", + "expected": "Python 3.11" + }, + "jlink": { + "command": "JLinkExe --version", + "expected": None # 不检查具体版本 + } + } + + results = {} + for tool, spec in verification_spec.items(): + success = verify_tool(tool, spec["command"], spec.get("expected")) + results[tool] = "PASS" if success else "FAIL" + + # 生成报告 + report = { + "timestamp": datetime.datetime.now().isoformat(), + "platform": sys.platform, + "results": results + } + + report_file = Path("tools_verification_report.json") + with open(report_file, "w") as f: + json.dump(report, f, indent=2) + + print(f"\n验证报告已保存: {report_file}") + + if all(status == "PASS" for status in results.values()): + print("✅ 所有工具验证通过") + return 0 + else: + print("❌ 部分工具验证失败") + return 1 + +if __name__ == "__main__": + import datetime + sys.exit(main()) +``` + +## 错误处理和故障排除 + +### 常见错误及解决方案 + +#### 1. 下载失败 +```yaml +错误: "下载超时或网络连接失败" +解决方案: + - 检查网络连接 + - 使用 --offline 模式(如果已有缓存) + - 更换下载源(--source mirror) + - 增加超时时间(--timeout 600) + - 使用代理服务器 +``` + +#### 2. 安装权限问题 +```yaml +错误: "权限被拒绝" 或 "需要管理员权限" +解决方案: + - Windows: 以管理员身份运行 + - Linux/macOS: 使用 sudo 或修改安装路径到用户目录 + - 使用 --install-path 指定用户可写目录 +``` + +#### 3. 版本兼容性问题 +```yaml +错误: "工具版本不兼容" +解决方案: + - 使用 --version 指定兼容版本 + - 查看版本兼容性矩阵 + - 更新相关依赖工具 + - 使用虚拟环境隔离 +``` + +#### 4. 环境配置问题 +```yaml +错误: "命令未找到" 或 "PATH 配置错误" +解决方案: + - 重新运行环境配置(--configure-env) + - 手动添加工具路径到 PATH + - 重启终端或 IDE + - 检查 shell 配置文件(.bashrc, .zshrc) +``` + +### 调试模式 +```bash +# 启用详细日志 +download-tools --verbose --debug --log-file install.log + +# 仅模拟运行 +download-tools --dry-run --config tools-config.yaml + +# 生成诊断报告 +download-tools --diagnose --output diagnose.json +``` + +## 集成示例 + +### 与 CMake 集成 +```cmake +# CMakeLists.txt 中的工具检查 +find_program(ARM_GCC arm-none-eabi-gcc) +if(NOT ARM_GCC) + message(WARNING "ARM GCC 工具链未找到") + message(STATUS "运行以下命令安装:") + message(STATUS " download-tools --install arm_gcc") + message(STATUS "或使用系统包管理器:") + message(STATUS " # Ubuntu/Debian") + message(STATUS " sudo apt-get install gcc-arm-none-eabi") + message(STATUS " # macOS") + message(STATUS " brew install arm-none-eabi-gcc") +endif() + +find_program(CMAKE_EXE cmake) +if(NOT CMAKE_EXE) + message(WARNING "CMake 未找到") + message(STATUS "运行以下命令安装:") + message(STATUS " download-tools --install cmake") +endif() + +# 自定义目标:安装开发工具 +add_custom_target(install-tools + COMMAND download-tools --profile ${PROJECT_CHIP} --install-path ${CMAKE_SOURCE_DIR}/tools + COMMENT "安装嵌入式开发工具链" +) +``` + +### 与 CI/CD 集成 +```yaml +# .github/workflows/build.yml +name: Embedded Build + +on: [push, pull_request] + +jobs: + setup-tools: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Embedded Tools + run: | + download-tools --profile stm32 \ + --install-path ./tools \ + --cache-dir ./cache \ + --no-interactive + + - name: Verify Installation + run: | + download-tools --verify --report-format github + + - name: Build Project + run: | + source ./tools/env.sh + cmake -B build -S . + cmake --build build + + - name: Upload Tools Cache + uses: actions/cache@v3 + with: + path: ./cache + key: ${{ runner.os }}-embedded-tools-${{ hashFiles('tools-config.yaml') }} +``` + +### 与 VS Code 集成 +```json +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Install Development Tools", + "type": "shell", + "command": "download-tools", + "args": [ + "--profile", + "gd32", + "--install-path", + "${workspaceFolder}/.vscode/tools", + "--quiet" + ], + "problemMatcher": [] + }, + { + "label": "Setup Environment", + "type": "shell", + "command": "${workspaceFolder}/.vscode/tools/env.bat", + "windows": { + "command": "${workspaceFolder}/.vscode/tools/env.bat" + }, + "linux": { + "command": "source ${workspaceFolder}/.vscode/tools/env.sh" + }, + "macos": { + "command": "source ${workspaceFolder}/.vscode/tools/env.sh" + } + } + ], + "settings": { + "terminal.integrated.env.windows": { + "PATH": "${workspaceFolder}/.vscode/tools/gcc-arm/bin;${env:PATH}" + }, + "terminal.integrated.env.linux": { + "PATH": "${workspaceFolder}/.vscode/tools/gcc-arm/bin:${env:PATH}" + }, + "terminal.integrated.env.osx": { + "PATH": "${workspaceFolder}/.vscode/tools/gcc-arm/bin:${env:PATH}" + } + } +} +``` + +## 维护指南 + +### 版本管理策略 +1. **LTS 版本**: 生产环境使用长期支持版本 +2. **最新版本**: 开发环境可尝试最新功能 +3. **版本锁定**: 通过配置文件锁定特定版本 +4. **平滑升级**: 支持渐进式版本升级 + +### 配置文件更新 +```bash +# 检查配置更新 +download-tools --check-config-updates + +# 应用配置更新 +download-tools --update-config --backup + +# 迁移旧配置 +download-tools --migrate-config --from-version 1.0.0 +``` + +### 缓存管理 +```bash +# 清理缓存 +download-tools --clean-cache --keep-versions 3 + +# 导出缓存(用于离线安装) +download-tools --export-cache ./offline-cache.tar.gz + +# 导入缓存 +download-tools --import-cache ./offline-cache.tar.gz +``` + +### 性能优化 +1. **并行下载**: 支持多工具并行下载 +2. **断点续传**: 支持下载中断后恢复 +3. **增量更新**: 仅下载变化的文件 +4. **本地镜像**: 支持搭建本地工具镜像服务器 + +## 安全考虑 + +### 安全最佳实践 +1. **完整性验证**: 所有下载文件必须进行 SHA256 校验 +2. **来源验证**: 优先使用官方源和可信镜像 +3. **权限最小化**: 工具安装使用最小必要权限 +4. **隔离运行**: 高风险工具在沙箱或容器中运行 +5. **审计日志**: 记录所有安装和配置操作 + +### 安全配置示例 +```yaml +security: + checksum_verification: true + allowed_sources: + - "https://developer.arm.com" + - "https://github.com/Kitware/CMake/releases" + - "https://www.segger.com/downloads/jlink" + forbidden_sources: + - "http://" # 禁止非加密连接 + require_signed: false # 未来可启用签名验证 + sandbox_mode: true # 在隔离环境中运行安装脚本 +``` + +## 扩展开发 + +### 添加新工具支持 +```python +# 新工具插件示例 +from download_tools.core import ToolPlugin + +class NewToolPlugin(ToolPlugin): + name = "new_tool" + description = "新工具支持插件" + + def get_download_url(self, platform, version): + # 返回平台特定的下载URL + urls = { + "windows": f"https://example.com/new-tool-{version}-windows.zip", + "linux": f"https://example.com/new-tool-{version}-linux.tar.gz", + "macos": f"https://example.com/new-tool-{version}-macos.pkg" + } + return urls.get(platform) + + def install(self, install_path, downloaded_file): + # 实现安装逻辑 + import shutil + import zipfile + + if downloaded_file.endswith('.zip'): + with zipfile.ZipFile(downloaded_file, 'r') as zip_ref: + zip_ref.extractall(install_path) + elif downloaded_file.endswith('.tar.gz'): + import tarfile + with tarfile.open(downloaded_file, 'r:gz') as tar_ref: + tar_ref.extractall(install_path) + + # 设置执行权限(Linux/macOS) + if platform.system() != "Windows": + bin_file = os.path.join(install_path, "bin", "new-tool") + os.chmod(bin_file, 0o755) + + def verify(self, install_path): + # 实现验证逻辑 + import subprocess + result = subprocess.run( + [os.path.join(install_path, "bin", "new-tool"), "--version"], + capture_output=True, + text=True + ) + return result.returncode == 0 + +# 注册插件 +ToolRegistry.register(NewToolPlugin()) +``` + +## 总结 + +`download-tools` 技能为嵌入式开发提供了一套完整的工具链管理解决方案。通过自动化工具下载、安装、配置和验证,显著提高了开发环境的搭建效率和一致性。无论是个人开发者还是团队协作,都能从中受益: + +1. **一致性**: 确保团队成员使用相同的工具版本 +2. **可重复性**: 开发环境可以快速重建和复制 +3. **可维护性**: 工具更新和迁移更加容易 +4. **安全性**: 通过验证和审计保障工具安全 +5. **生产力**: 减少环境配置时间,专注开发工作 + +作为 OpenClaw 集成专家,我强烈推荐在嵌入式项目中采用此技能管理开发工具链,这将为项目的长期维护和团队协作奠定坚实基础。 + +--- + +*最后更新: 2024-01-15* +*版本: 2.0.0* +*作者: OpenClaw 集成专家团队* \ No newline at end of file diff --git a/.trae/skills/gen_font/SKILL.md b/.trae/skills/gen_font/SKILL.md new file mode 100644 index 0000000..a51694f --- /dev/null +++ b/.trae/skills/gen_font/SKILL.md @@ -0,0 +1,117 @@ +--- +name: "gen_font" +description: "Generates LVGL CJK bitmap fonts for the LCD UI. Invoke when user needs to add new Chinese characters to the display or regenerate font files." +--- + +# Generate CJK Font for LVGL + +This skill generates custom LVGL bitmap fonts for Chinese/Japanese/Korean (CJK) character display on the 800x480 LCD. The project uses SimHei (黑体) as source and produces 4 font sizes (16, 20, 40, 60px) with 4bpp. + +## Prerequisites + +- **lv_font_conv** installed globally via npm: + ```bash + npm install -g lv_font_conv + ``` + Installed at: `C:\Users\gxms0\AppData\Roaming\npm\lv_font_conv.cmd` + +- **Source font**: `vue/vue3/src/assets/fonts/simhei.ttf`(黑体) + +- **Python 3** with `fonttools` and `Pillow` (for alternative generation methods) + +## Font Files + +| Size | Output File | Usage in UI | +|:----:|-------------|-------------| +| 16px | `app/tasks/custom_cjk_16.c` | Labels, subtitles, unit text | +| 20px | `app/tasks/custom_cjk_20.c` | Unit labels, medium text | +| 40px | `app/tasks/custom_cjk_40.c` | Large weight/count display | +| 60px | `app/tasks/custom_cjk_60.c` | Button text, status text | + +## How to Add New Characters + +### Step 1: Find Unicode values + +Use Python to get Unicode codepoints: +```python +chars = "工序称重折纸打包封包加热" +for ch in chars: + print(f"0x{ord(ch):04X} # {ch}") +``` + +### Step 2: Edit codepoint list + +Open `regen_font_new.py` and add new hex values to the `codes` list in sorted order: + +```python +codes = [ + 0x2B, 0x2D, 0x2E, # ... existing codes + 0x4E2D, 0x4F4D, # ... CJK characters + 0x52A0, # 加 - newly added + 0x5C01, # 封 - newly added + 0x70ED, # 热 - newly added +] +``` + +### Step 3: Regenerate all font sizes + +```bash +cd D:\20_AI\LSPi +python3 regen_font_new.py +``` + +This regenerates all 4 sizes (16, 20, 40, 60px) at once. + +### Step 4: Rebuild + +```bash +cmake --build build_new +``` + +## Character Set + +Current codepoints in the project: + +**Symbols (ASCII):** `+` `-` `.` `/` `0-9` (14 chars) + +**CJK Characters (50 chars):** +中 位 值 停 出 克 前 加 动 包 卡 压 名 启 品 复 定 实 封 工 已 序 当 态 总 成 打 折 按 数 斗 料 时 止 点 热 片 状 称 累 纸 缩 行 计 设 运 进 重 量 钮 + +Total: **64 characters** + +## LVGL Integration + +Each font file generates with its own enable macro. Include in source code: + +```c +// Declare the font (in any file that uses it) +LV_FONT_DECLARE(custom_cjk_16); +LV_FONT_DECLARE(custom_cjk_20); +LV_FONT_DECLARE(custom_cjk_40); +LV_FONT_DECLARE(custom_cjk_60); + +// Apply to label +lv_obj_set_style_text_font(my_label, &custom_cjk_16, 0); +``` + +## Build System + +The font `.c` files are automatically picked up by CMake via: + +```cmake +file(GLOB_RECURSE APP_SOURCES app/*.c app/*.cpp ...) +``` + +When adding new font files, re-run cmake to refresh the file list: +```bash +cmake -S . -B build_new +``` + +## Alternative Generation Methods + +The project also has alternative font generators for reference: + +- `gen_font.py` - Uses Pillow to render and pack bitmap data +- `gen_lvgl_font.py` - Uses fontTools directly +- `diag_font.py` - Diagnostic tool to inspect font coverage +- `check_fonts.py` - Verify which characters are included diff --git a/.trae/skills/packer-ui/SKILL.md b/.trae/skills/packer-ui/SKILL.md new file mode 100644 index 0000000..18688b6 --- /dev/null +++ b/.trae/skills/packer-ui/SKILL.md @@ -0,0 +1,385 @@ +--- +name: "packer-ui" +description: "包装机界面(packer_ui)设计规范与开发指南。包括布局尺寸、颜色体系、字体使用和后续开发指导。适用于800x480 LCD上的LVGL界面。" +--- + +# Packer UI Design Guide + +## 1. 布局总览 + +屏幕分辨率为 **800x480**,整体划分为左右两栏: + +``` ++--------------------------------------------------------------+ +| +--------------------------+ +--------------------------+ | +| | 状态卡片 (左) | | 启动按钮 (右) | | +| | x=10, y=10 | | x=580, y=10 | | +| | w=560, h=330 | | w=210, h=330 | | +| | | | | | +| | +----------+----------+ | | "启动" | | +| | | 当前重量 | 总包数 | | | | | +| | | | | | | | | +| | | 0.0 | 0 | | | | | +| | | | | | | | | +| | | 称重斗.. | 累计成品 | | | | | +| | +----------+----------+ | | | | +| | 工序 进料 | o 已停止 | | | | +| +--------------------------+ +--------------------------+ | +| +--------------------------+ +--------------------------+ | +| | 目标重量卡片 (左下) | | 复位按钮 (右下) | | +| | x=10, y=350 | | x=580, y=350 | | +| | w=560, h=120 | | w=210, h=120 | | +| | | | | | +| | 设计重量 190.0 克/包 | | 复位 | | +| | o(-) o(+) | | | | +| +--------------------------+ +--------------------------+ | ++--------------------------------------------------------------+ +``` + +## 2. 容器与位置参数 + +### 2.1 顶层容器 + +| 控件 | 创建函数 | x | y | w | h | 圆角 | 背景色 | +|------|---------|---|---|---|---|------|--------| +| packer_scr | lv_obj_create | - | - | 800 | 480 | - | COLOR_BG | +| card_status | lv_obj_create | 10 | 10 | 560 | 330 | 20 | COLOR_CARD | +| card_target | lv_obj_create | 10 | 350 | 560 | 120 | 20 | COLOR_CARD_TARGET | +| btn_start | lv_btn_create | 580 | 10 | 210 | 330 | 20 | COLOR_BTN_START | +| btn_reset | lv_btn_create | 580 | 350 | 210 | 120 | 20 | COLOR_BTN_DARK | +| btn_minus | lv_btn_create | 331 | 30 | 60 | 60 | 30 | COLOR_BTN_ADJ | +| btn_plus | lv_btn_create | 463 | 30 | 60 | 60 | 30 | COLOR_BTN_ADJ | + +### 2.2 状态卡片内部分布 + +card_status (560x330) 被垂直分割线分成左右两半: + +**左半区 -- 当前重量 (宽度 281px)** + +| 控件 | 文本 | 父级x偏移 | 父级y偏移 | 宽 | 高 | 字体 | 颜色 | +|------|------|----------|----------|-----|-----|------|------| +| w_title | "当前重量" | 0 | 14 | 281 | 28 | custom_cjk_20 | COLOR_GREEN | +| label_current_weight | "0.0" | 0 | 90 | 281 | 84 | custom_cjk_60 | COLOR_TEXT_MAIN | +| w_sub | "称重斗实时值" | 0 | 200 | 281 | 20 | custom_cjk_16 | 0x6f9181 | + +**右半区 -- 总包数 (宽度 278px)** + +| 控件 | 文本 | 父级x偏移 | 父级y偏移 | 宽 | 高 | 字体 | 颜色 | +|------|------|----------|----------|-----|-----|------|------| +| c_title | "总包数" | 282 | 14 | 278 | 30 | custom_cjk_20 | COLOR_GREEN | +| label_pack_count | "0" | 282 | 90 | 278 | 84 | custom_cjk_60 | COLOR_TEXT_MAIN | +| c_sub | "累计成品" | 282 | 200 | 278 | 20 | custom_cjk_16 | 0x6f9181 | + +**分割线** + +| 控件 | 位置(x,y) | 尺寸(w,h) | 颜色 | +|------|----------|----------|------| +| horizontal_line | (40, 240) | (480, 1) | COLOR_BORDER | +| vertical_line | (280, 20) | (1, 290) | COLOR_BORDER | + +**状态指示** + +| 控件 | 文本 | 父级x偏移 | 父级y偏移 | 宽 | 高 | 圆角 | 颜色 | +|------|------|----------|----------|-----|-----|------|------| +| status_dot | - | 330 | 270 | 34 | 35 | 17(圆形) | COLOR_GREEN | +| label_status | "已停止" | 420 | 280 | - | - | - | COLOR_TEXT_MAIN, font 20px | + +**工序状态 (左下, 分割线下方)** + +标题 "工序" 位于 x=50, y=270, 使用 font 20px, COLOR_GREEN。 +当前工序名称紧跟在标题右侧, 使用 font 20px, COLOR_TEXT_MAIN: + +| 控件 | 文本(初始) | x | y | 字体 | 颜色 | +|-----|-----------|----|----|------|------| +| proc_title | "工序" | 50 | 270 | custom_cjk_20 | COLOR_GREEN | +| label_step | "进料" | 120 | 270 | custom_cjk_20 | COLOR_TEXT_MAIN | + +通过 `current_step` (0~5) 索引 `step_name[]` 数组动态切换显示的工序: +```c +static const char *step_name[] = {"进料", "称重", "压缩", "打包", "封包", "出料"}; +if (current_step < 6) + lv_label_set_text(label_step, step_name[current_step]); +``` + +### 2.3 目标重量卡内部布局 + +card_target (560x120) 从左到右: + +| 控件 | 文本 | 父级x偏移 | 父级y偏移 | 宽/尺寸 | 高 | 字体 | 颜色 | +|------|------|----------|----------|---------|-----|------|------| +| t_title | "设计重量" | 0 | 50 | 90 | 120 | custom_cjk_20 | COLOR_GREEN | +| label_target_val | "190.0" | 100 | 30 | 150 | 120 | custom_cjk_60 | COLOR_TEXT_MAIN | +| t_unit | "克/包" | 240 | 50 | - | - | custom_cjk_20 | 0x6f9181 | +| btn_minus | "-" | 331 | 30 | 60x60 | - | custom_cjk_60 | COLOR_TEXT_MAIN | +| btn_plus | "+" | 463 | 30 | 60x60 | - | custom_cjk_40 | COLOR_TEXT_MAIN | + +> btn_minus 字符"-"用 font 60px, btn_plus 字符"+"用 font 40px, 视觉上调整到大小接近。 + +## 3. 颜色体系 + +### 3.1 颜色常量定义 + +```c +COLOR_BG = 0x161b22 // 深色背景(深蓝黑) +COLOR_CARD = 0x000000 // 卡片背景(纯黑) +COLOR_CARD_TARGET = 0x080a0e // 目标重量卡片(近乎纯黑) +COLOR_BORDER = 0x30363d // 分割线颜色(暗灰) +COLOR_TEXT_MAIN = 0xffffff // 主文字(纯白) +COLOR_TEXT_SEC = 0x9ab3a5 // 次要文字(薄荷灰) +COLOR_BTN_START = 0x06990c // 启动按钮背景(绿色) +COLOR_BTN_DARK = 0x000000 // 复位按钮背景(纯黑) +COLOR_BTN_ADJ = 0x1e3c28 // 加减按钮背景(深绿) +COLOR_GREEN = 0x06990c // 状态灯/绿色指示(绿色) +COLOR_RED = 0x990B06 // 红色(深红) +COLOR_ADJ_ICON = 0xc4c4c4 // 调节图标辅助色(浅灰) +``` + +### 3.2 辅助颜色(直接硬编码) + +| 用途 | 颜色值 | 说明 | +|------|--------|------| +| w_sub / c_sub 文字 | 0x6f9181 | 副标题, 茶绿色 | +| t_unit "克/包" | 0x6f9181 | 单位标签, 茶绿色 | + +### 3.3 状态灯逻辑 + +状态灯(status_dot)是一个 34x35 的圆形, 通过背景色切换运行/停止: + +| 状态 | 圆点颜色 | 圆点值 | 文字颜色 | +|------|---------|--------|---------| +| 运行中 | COLOR_GREEN | 0x06990c | COLOR_TEXT_MAIN | +| 已停止 | COLOR_RED | 0x990B06 | COLOR_TEXT_MAIN | + +状态灯右侧显示文字 label_status, 内容对应切换: "运行中" / "已停止", 文字始终为白色 (COLOR_TEXT_MAIN)。 + +## 4. 字体系统 + +### 4.1 字体规格 + +使用 SimHei(黑体)生成的 LVGL 位图字体, 4bpp 抗锯齿: + +| 大小 | 字体变量 | 适用场景 | +|:----:|----------|----------| +| 16px | custom_cjk_16 | 副标题, 辅助说明文字 | +| 20px | custom_cjk_20 | 区域标题, 标签, 单位 | +| 40px | custom_cjk_40 | 按钮文字, 部分符号(+) | +| 60px | custom_cjk_60 | 数值显示, 大字符号(-) | + +### 4.2 字体声明 + +```c +LV_FONT_DECLARE(custom_cjk_16); +LV_FONT_DECLARE(custom_cjk_20); +LV_FONT_DECLARE(custom_cjk_40); +LV_FONT_DECLARE(custom_cjk_60); +``` + +## 5. 按钮样式规则 + +所有按钮统一移除阴影, 轮廓, 边框: + +```c +// 每个按钮创建后必须执行的样式 +lv_obj_set_style_shadow_width(btn, 0, 0); +lv_obj_set_style_shadow_opa(btn, LV_OPA_0, 0); +lv_obj_set_style_outline_width(btn, 0, 0); +lv_obj_set_style_outline_opa(btn, LV_OPA_0, 0); +lv_obj_set_style_border_width(btn, 0, 0); +lv_obj_set_style_border_side(btn, LV_BORDER_SIDE_NONE, 0); +``` + +按钮样式差异(仅背景色和圆角不同): + +| 按钮 | 圆角 | 背景色 | 文字颜色 | 字体 | +|------|------|--------|---------|------| +| btn_start | 20 | COLOR_BTN_START (绿) | COLOR_TEXT_MAIN (白) | custom_cjk_40 | +| btn_reset | 20 | COLOR_BTN_DARK (黑) | COLOR_TEXT_SEC (灰绿) | custom_cjk_40 | +| btn_minus | 30 | COLOR_BTN_ADJ (深绿) | COLOR_TEXT_MAIN (白) | custom_cjk_60 | +| btn_plus | 30 | COLOR_BTN_ADJ (深绿) | COLOR_TEXT_MAIN (白) | custom_cjk_40 | + +## 6. 卡片通用样式 + +所有卡片(create_card)默认属性: + +```c +lv_obj_set_style_border_width(card, 0, 0); // 无边框 +lv_obj_clear_flag(card, LV_OBJ_FLAG_SCROLLABLE); // 不可滚动 +// 圆角在 create_card 的参数中传入 +// 背景色在 create_card 的参数中传入 +``` + +状态卡片和目标重量卡片额外设置: + +```c +lv_obj_set_style_pad_hor(card, 0, LV_PART_MAIN); +lv_obj_set_style_pad_ver(card, 0, LV_PART_MAIN); +lv_obj_set_style_outline_width(card, 0, LV_PART_MAIN); +lv_obj_set_style_border_width(card, 0, LV_PART_MAIN); +``` + +## 7. 回调函数 + +| 回调 | 绑定的控件 | 触发事件 | 行为 | +|------|-----------|---------|------| +| start_cb | btn_start | LV_EVENT_CLICKED | 设置 is_running=true, 清零 current_weight, 更新显示 | +| reset_cb | btn_reset | LV_EVENT_CLICKED | 设置 is_running=false, 清零 weight 和 pack_count, 更新显示 | +| minus_cb | btn_minus | LV_EVENT_CLICKED | 运行中忽略, 否则 target_weight -= 10 (下限 10), 更新显示 | +| plus_cb | btn_plus | LV_EVENT_CLICKED | 运行中忽略, 否则 target_weight += 10 (上限 2000), 更新显示 | + +## 8. 核心数据结构 + +```c +// 控件指针(文件内 static) +static lv_obj_t *label_target_val; // 目标重量值标签 +static lv_obj_t *label_current_weight; // 当前重量值标签 +static lv_obj_t *label_pack_count; // 总包数值标签 +static lv_obj_t *label_status; // 状态文字标签 +static lv_obj_t *status_dot; // 状态指示圆点 +static lv_obj_t *label_step; // 当前工序标签(进料/称重/压缩/打包/封包/出料) + +// 状态变量(volatile, 可能被中断/任务修改) +static volatile bool is_running = false; // 运行状态 +static volatile uint8_t current_step = 0; // 当前工序索引(0~5) +static volatile uint32_t target_weight = 190; // 目标重量 (单位: 0.1g) +static volatile uint32_t current_weight = 230; // 当前重量 (单位: 0.1g) +static volatile uint32_t pack_count = 2340; // 总包数 +``` + +## 9. update_display() 刷新规则 + +每次状态变更后调用 `update_display()`: + +```c +static void update_display(void) +{ + char tmp[32]; + // 1. 刷新当前重量(保留一位小数) + snprintf(tmp, sizeof(tmp), "%lu.%lu", + (unsigned long)(current_weight / 10), + (unsigned long)(current_weight % 10)); + lv_label_set_text(label_current_weight, tmp); + + // 2. 刷新总包数(整数) + snprintf(tmp, sizeof(tmp), "%lu", (unsigned long)pack_count); + lv_label_set_text(label_pack_count, tmp); + + // 3. 刷新状态灯颜色 + lv_obj_set_style_bg_color(status_dot, + is_running ? COLOR_GREEN : COLOR_RED, 0); + + // 4. 刷新状态文字 + lv_label_set_text(label_status, is_running ? "运行中" : "已停止"); +} +``` + +> `update_display()` 由外部任务循环调用, 也由 start_cb/reset_cb 等回调触发。 + +## 10. 后续开发指南 + +### 10.1 新增控件原则 + +- **所有坐标都以 800x480 为基准**, 不要超出范围 +- **使用 `create_card()` 辅助函数**创建新的卡片容器, 统一无边框无滚动 +- **新按钮必须执行 "无边框三部曲"**: shadow=0, outline=0, border=0 +- **新文字标签必须指定字体**, 不要依赖默认字体(默认字体不含中文) + +### 10.2 颜色使用 + +- **标题一律用 COLOR_GREEN**, 内容/数值一律用 **COLOR_TEXT_MAIN** (白色) +- **优先使用已定义的 COLOR_xxx 常量**, 不要随意硬编码新颜色 +- 如需新增颜色: 在 `set_colors()` 中添加新常量, 不要在代码中直接写 `lv_color_hex()` +- 副标题文字绿色调使用 `0x6f9181`, 与 COLOR_TEXT_SEC (0x9ab3a5) 区分 +- COLOR_TEXT_SEC 目前仅用于复位按钮文字(白色改为后已不再使用, 保留以备后续) + +### 10.3 字体使用 + +- **标题/说明**: custom_cjk_20 +- **数值**: custom_cjk_60 +- **辅助文字**: custom_cjk_16 +- **按钮**: custom_cjk_40 +- 如需新增汉字: 使用 [gen_font](../gen_font/SKILL.md) 技能重新生成字体 + +### 10.4 添加新页面 + +如需添加新页面(如设置页, 历史记录页), 建议步骤: + +1. 新建 `xxx_ui.cpp` / `xxx_ui.h`(参考 packer_ui 结构) +2. 遵循相同的卡片布局风格: 深色背景, 圆角卡片, 绿黑配色 +3. 在新文件的 `xxx_ui_create()` 中完成创建 +4. 在 `lv_scr_load()` 切换页面时, 先用 `lv_obj_del()` 删除旧页面控件(可选) +5. 在 `main.cpp` 或任务流程中调用新页面的 create 函数 + +### 10.5 动画与过渡 + +当前界面为静态布局, 如需添加过渡效果: + +```c +// 示例: 按钮按下缩放动画 +lv_anim_t a; +lv_anim_init(&a); +lv_anim_set_var(&a, btn); +lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_scale); +lv_anim_set_values(&a, 256, 280); // LV_IMG_ZOOM_NONE=256 +lv_anim_set_time(&a, 100); +lv_anim_start(&a); +``` + +### 10.6 国际化和单位 + +- 所有 UI 文字为中文硬编码 +- 重量显示格式: `"190.0"`(一位小数), 重量内部以 0.1g 为单位存储 +- 如需支持多语言, 建议将所有字符串抽取到常量表中 + +### 10.7 触摸事件 + +当前按钮使用 `LV_EVENT_CLICKED` 事件, 如需区分按下/释放: + +```c +lv_obj_add_event_cb(btn, my_cb, LV_EVENT_PRESSED, NULL); +lv_obj_add_event_cb(btn, my_cb, LV_EVENT_RELEASED, NULL); + +static void my_cb(lv_event_t *e) +{ + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_PRESSED) { + // 按下时改变按钮样式 + } else if (code == LV_EVENT_RELEASED) { + // 释放时恢复 + } +} +``` + +### 10.8 键盘/物理按键支持 + +LVGL 默认支持键盘焦点导航。焦点指示器为按钮的 outline 样式。如需自定义焦点样式: + +```c +// 自定义焦点时的边框颜色 +lv_obj_set_style_outline_color(btn, lv_color_hex(0x58a6ff), LV_STATE_FOCUSED); +lv_obj_set_style_outline_width(btn, 2, LV_STATE_FOCUSED); +``` + +## 11. 文件位置 + +| 文件 | 路径 | +|------|------| +| UI 源码 | [app/tasks/packer_ui.cpp](file:///d:/20_AI/LSPi/app/tasks/packer_ui.cpp) | +| UI 头文件 | [app/tasks/packer_ui.h](file:///d:/20_AI/LSPi/app/tasks/packer_ui.h) | +| 调试日志 | [app/tasks/debug_log.h](file:///d:/20_AI/LSPi/app/tasks/debug_log.h) | +| 字体生成脚本 | [regen_font_new.py](file:///d:/20_AI/LSPi/regen_font_new.py) | + + +## 12. 界面逻辑 + +1. 当前重量数值跟随着称称重变化 +2. 总包数数值跟包装好的包数变化 +3. 状态灯颜色跟运行状态变化 +4. 状态文字跟运行状态变化 +5. 当前工序标签跟当前工序变化 +6. 增加按键点击时,设计重量会增加1g,最大值90g +7. 减小按键点击时,设计重量会减少1g,最小值1g +8. 复位按键点击时,发出机器复位的指令,所有工序停止,并且各种结构归零复位。 +9. 运行按键点击时,开始运行,并开始进行包装。并且启动按键变成红色,文字变成停止,状态灯变绿,文字变为运行中,再次点击时,按键变为绿色言,文字变为启动,状态灯变红,文字变为已停止。 + + +