Compare commits

..
10 Commits
10 changed files with 527 additions and 394 deletions
+2 -1
View File
@@ -34,8 +34,9 @@ set(TARGET_SRC
Src/led.c
Src/uart_ring_buffer.c
Src/command.c
Src/i2c.c
# Src/i2c.c
Src/board_config.c
Src/actuator.c
)
# 设置输出目录
+16
View File
@@ -0,0 +1,16 @@
#ifndef ACTUATOR_H
#define ACTUATOR_H
#include "board_config.h"
#include "gd32e23x.h"
#include "stdbool.h"
#define ACTUARTOR_PERIOD_MAX 1000u
void actuator_init(void);
void actuator_output(actuator_channel_t channel, uint16_t duty, actuator_direction_t direction);
void actuator_stop(actuator_channel_t channel);
#endif // ACTUATOR_H
+75 -20
View File
@@ -1,12 +1,15 @@
#ifndef BOARD_CONFIG_H
#define BOARD_CONFIG_H
#ifndef DISABLE
#define DISABLE 0
#include "gd32e23x.h"
#include "stdbool.h"
#ifndef CFG_DISABLE
#define CFG_DISABLE 0
#endif
#ifndef ENABLE
#define ENABLE 1
#ifndef CFG_ENABLE
#define CFG_ENABLE 1
#endif
#define GD32E23XF4 0x10
@@ -17,27 +20,27 @@
#include "version.h"
/* >>>>>>>>>>>>>>>>>>>>[IIC TYPE DEFINE]<<<<<<<<<<<<<<<<<<<< */
/* >>>>>>>>>>>>>>>>>>>>[IIC TYPE CONFIG]<<<<<<<<<<<<<<<<<<<< */
#define SOFTWARE_IIC DISABLE // DISABLE: Hardware IIC; ENABLE: Software IIC
#define SOFTWARE_IIC CFG_DISABLE // CFG_DISABLE: Hardware IIC; CFG_ENABLE: Software IIC
/* >>>>>>>>>>>>>>>>>>>>[DEBUG MODE]<<<<<<<<<<<<<<<<<<<< */
#define DEBUG_MODE DISABLE // DISABLE: Release Mode; ENABLE: Debug Mode
#define DEBUG_MODE CFG_DISABLE // CFG_DISABLE: Release Mode; CFG_ENABLE: Debug Mode
/* >>>>>>>>>>>>>>>>>>>>[COMMAND DEBUG]<<<<<<<<<<<<<<<<<<<< */
#define COM_DEBUG DISABLE // DISABLE: Command debug off; ENABLE: Command debug on
#define COM_DEBUG CFG_DISABLE // CFG_DISABLE: Command debug off; CFG_ENABLE: Command debug on
/* >>>>>>>>>>>>>>>>>>>>[DEBUG ASSERTIONS DEFINE]<<<<<<<<<<<<<<<<<<<< */
/* >>>>>>>>>>>>>>>>>>>>[DEBUG ASSERTIONS CONFIG]<<<<<<<<<<<<<<<<<<<< */
#define DEBUG_VERBOSE DISABLE // DISABLE: Verbose debug off; ENABLE: Verbose debug on
#define DEBUG_VERBOSE CFG_DISABLE // CFG_DISABLE: Verbose debug off; CFG_ENABLE: Verbose debug on
/* >>>>>>>>>>>>>>>>>>>>[SEGGER RTT DETECTION]<<<<<<<<<<<<<<<<<<<< */
/* >>>>>>>>>>>>>>>>>>>>[SEGGER RTT CONFIG]<<<<<<<<<<<<<<<<<<<< */
#define SEGGER_RTT_DETECTION ENABLE // DISABLE: SEGGER RTT off; ENABLE: SEGGER RTT on
#define SEGGER_RTT_DETECTION CFG_ENABLE // CFG_DISABLE: SEGGER RTT off; CFG_ENABLE: SEGGER RTT on
#if SEGGER_RTT_DETECTION == ENABLE
#if SEGGER_RTT_DETECTION == CFG_ENABLE
#include "SEGGER_RTT.h"
#define RTT_printf(ch, ...) SEGGER_RTT_printf(ch, __VA_ARGS__)
#define RTT_WriteString(ch, s) SEGGER_RTT_WriteString(ch, s)
@@ -48,6 +51,10 @@
#define RTT_PutChar(ch, c)
#endif
/* >>>>>>>>>>>>>>>>>>>>[RS485 MODE CONFIG]<<<<<<<<<<<<<<<<<<<< */
#define RS485_MODE CFG_ENABLE // CFG_DISABLE: RS485 off; CFG_ENABLE: RS485 on
/******************************************************************************/
/* Dynamic USART Configuration Structure */
@@ -67,13 +74,13 @@ void usart1_irq_handler(void);
/******************************************************************************/
#define RCU_GPIO_I2C RCU_GPIOF
#define RCU_I2C RCU_I2C0
#define I2C_SCL_PORT GPIOF
#define I2C_SCL_PIN GPIO_PIN_1
#define I2C_SDA_PORT GPIOF
#define I2C_SDA_PIN GPIO_PIN_0
#define I2C_GPIO_AF GPIO_AF_1
// #define RCU_GPIO_I2C RCU_GPIOF
// #define RCU_I2C RCU_I2C0
// #define I2C_SCL_PORT GPIOF
// #define I2C_SCL_PIN GPIO_PIN_1
// #define I2C_SDA_PORT GPIOF
// #define I2C_SDA_PIN GPIO_PIN_0
// #define I2C_GPIO_AF GPIO_AF_1
/******************************************************************************/
@@ -83,6 +90,40 @@ void usart1_irq_handler(void);
/******************************************************************************/
typedef enum {
ACTUATOR_CH1 = 0,
ACTUATOR_CH2
} actuator_channel_t;
typedef enum {
DIRECTION_PUSH = 0, // 推动方向
DIRECTION_PULL // 拉动方向
} actuator_direction_t;
/******************************************************************************/
#define ACTUATOR_CH1_PWM_RCU RCU_GPIOA
#define ACTUATOR_CH1_PWM_PORT GPIOA
#define ACTUATOR_CH1_PWM_PIN GPIO_PIN_10
#define ACTUATOR_CH1_GPIO_RCU RCU_GPIOF
#define ACTUATOR_CH1_GPIO_PORT GPIOF
#define ACTUATOR_CH1_GPIO_PIN GPIO_PIN_0
#define ACTUATOR_CH2_PWM_RCU RCU_GPIOA
#define ACTUATOR_CH2_PWM_PORT GPIOA
#define ACTUATOR_CH2_PWM_PIN GPIO_PIN_9
#define ACTUATOR_CH2_GPIO_RCU RCU_GPIOF
#define ACTUATOR_CH2_GPIO_PORT GPIOF
#define ACTUATOR_CH2_GPIO_PIN GPIO_PIN_1
#define ACTUATOR_PWM_TIMER_RCU RCU_TIMER0
#define ACTUATOR_PWM_TIMER TIMER0
#define ACTUATOR_CH1_PWM_TIMER_CH TIMER_CH_2
#define ACTUATOR_CH2_PWM_TIMER_CH TIMER_CH_1
/******************************************************************************/
#define UART_RCU (g_usart_config.rcu_usart)
#define UART_PHY (g_usart_config.usart_periph)
#define UART_IRQ (g_usart_config.irq_type)
@@ -92,6 +133,20 @@ void usart1_irq_handler(void);
#define UART_RX_PIN GPIO_PIN_3
#define UART_BAUDRATE 115200U
#if RS485_MODE == CFG_ENABLE
#define RS485_DE_RCU RCU_GPIOA
#define RS485_DE_PORT GPIOA
#define RS485_DE_PIN GPIO_PIN_1
#endif
#define ADDR_RCU RCU_GPIOA
#define ADDR_PORT GPIOA
#define ADDR_BITO_PIN GPIO_PIN_0
#define ADDR_BIT1_PIN GPIO_PIN_4
#define ADDR_BIT2_PIN GPIO_PIN_5
#define ADDR_BIT3_PIN GPIO_PIN_6
/******************************************************************************/
#define DEBUG_UART USART0
+2 -2
View File
@@ -12,8 +12,8 @@ _Min_Stack_Size = 0x400; /* required amount of stack */
/* Memories definition */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 16K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 4K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
}
/* Sections */
+198 -338
View File
@@ -1,396 +1,256 @@
# GD32E23x 工程模板
# LA-T8 推杆驱动控制固件
仓库为兆易创新 GD32E23x 系列 MCU 的 CMake + VSCode 工程模板,适合嵌入式开发快速上手和团队协作
工程是 LA-T8-12-5-50/105-188 电动推杆的控制板驱动固件,基于 GD32E230F8Cortex-M23)开发,使用 CMake + VSCode + ARM GCC 构建
当前为调试工程:不配合 BootloaderFlash 从 `0x08000000` 全量使用,链接脚本已放开为 F8 的完整 `64KB Flash / 8KB RAM`
---
## 目录
- [适用范围](#适用范围)
- [默认配置](#默认配置)
- [快速开始](#快速开始)
- [推杆型号说明](#推杆型号说明)
- [硬件资源](#硬件资源)
- [控制原理](#控制原理)
- [串口协议](#串口协议)
- [命令表](#命令表)
- [工程配置](#工程配置)
- [工程结构](#工程结构)
- [板级配置](#板级配置)
- [Flash 偏移配置(配合 Bootloader](#flash-偏移配置配合-bootloader)
- [工具链准备](#工具链准备)
- [使用说明](#使用说明)
- [时钟配置说明](#时钟配置说明)
- [vcpkg 依赖管理(可选)](#vcpkg-依赖管理可选)
- [编译与烧录](#编译与烧录)
- [调试](#调试)
- [已知限制](#已知限制)
---
## 适用范围
## 推杆型号说明
- 适用于兆易创新 GD32E23x 系列 Cortex-M23 内核单片机
- 支持标准外设库开发
- 推荐开发环境:VSCode + CMake + ARM GCC 工具链
型号:`LA-T8-12-5-50/105-188`
| 型号片段 | 常见含义 |
|---|---|
| `LA-T8` | LA-T8 系列微型电动推杆 |
| `12` | 额定输入电压 12VDC |
| `5` | 空载速度约 5mm/s |
| `50` | 行程 50mm |
| `105` | 最小安装距约 105mm(该系列常见 Lmin ≈ 54.5mm + 行程) |
| `188` | 额定推/拉力约 188N |
> 型号对应参数以推杆实物铭牌或厂家规格书为准。本固件只输出 PWM 与方向信号,不采集推杆位置、限位或电流反馈。
---
## 默认配置
## 硬件资源
- MCU 主频:内部 RC 振荡器,系统时钟配置为 72MHz
- 调试串口:USART0PA2 TX / PA3 RX),115200 波特率
- I2C:默认硬件 I2C0PF0 SDA / PF1 SCL),可通过 `board_config.h` 切换为软件 I2C
| 功能 | 引脚 / 外设 | 说明 |
|---|---|---|
| 主控 | GD32E230F8 | Cortex-M2364KB Flash8KB RAM |
| 系统时钟 | IRC8M + PLL | 72MHz |
| 推杆 CH1 | PA10 / TIMER0_CH2 + PF0 方向 | 通道 0 |
| 推杆 CH2 | PA9 / TIMER0_CH1 + PF1 方向 | 通道 1 |
| 通信口 | PA2 TX / PA3 RX | F8 自动选择 USART1115200 8N1 |
| RS485 DE | PA1 | AF1,由 RS485 PHY 自动控制方向 |
| 状态 LED | PB1 | 低电平点亮 |
| 地址配置 | PA0 / PA4 / PA5 / PA6 | 当前已定义宏,暂未参与控制逻辑 |
| 调试通道 | SWD + SEGGER RTT | 不占用 UART 引脚 |
---
## 快速开始
## 控制原理
### 基于模板创建新项目
推杆驱动使用 TIMER0 输出两路 PWM,占空比范围为 `0 ~ 1000`
1. **克隆或复制本仓库**
```bash
git clone https://gitea.hulk.wang/hulk/gd32e23x_template_cmake_vscode.git my-new-project
cd my-new-project
```
```text
Timer 时钟 = 72MHz / (prescaler 2 + 1) = 24MHz
PWM 频率 = 24MHz / (period 999 + 1) = 24kHz
```
2. **修改项目配置** — 编辑 `cmake/project_config.cmake`
```cmake
set(PROJECT_NAME "MyProject") # 项目名称
set(BOARD_TYPE_CODE 20) # 板卡类型码(协议帧中的标识)
set(VERSION_MAJOR 1) # 主版本号
set(VERSION_MINOR 0) # 次版本号
set(VERSION_PATCH 0) # 修订号
set(BUILD_VARIANT "APP") # 编译变体
```
当前实现
3. **添加业务源文件** — 编辑 `CMakeLists.txt`,在 `TARGET_SRC` 中添加你的 `.c` 文件。
| 命令 | 方向引脚 | PWM |
|---|---|---|
| M3 推出 | 低 | 占空比 = `duty` |
| M4 拉回 | 高 | 占空比 = `1000 - duty` |
| M5 停止 | 高 | 输出置为停止状态 |
4. **配置板级引脚** — 编辑 `Inc/board_config.h`,修改 I2C、UART、LED 等引脚定义
`duty` 越大表示电机获得的有效功率越大,实际推杆速度还受负载、电压和推杆本身特性影响
5. **编译**
```bash
cmake --preset Debug
cmake --build build/Debug
```
产物在 `build/Debug/` 下,包含 `.elf`、`.hex`、`.bin`、`.map`、`.list`。
---
### 分支说明
## 串口协议
| 分支 | 用途 |
|------|------|
| `template_pc` | **主模板**(推荐),用于桌面端 VSCode 开发 |
| `template_xl` | 小琅适配版 |
| `main` | 早期版本,不推荐使用 |
通信口为 RS485,默认 `115200, 8N1`。协议帧最大长度为 32 字节。
### 主机 -> 设备命令帧
```text
D5 01 LEN CMD... CRC
```
| 字节 | 含义 |
|---|---|
| `D5` | 包头 |
| `01` | 板卡类型标识(协议帧类型,与 M999 返回的工程代号不同) |
| `LEN` | `CMD` 区字节数 |
| `CMD` | 命令内容,如 `M3P0S500` |
| `CRC` | 从索引 1 到倒数第 2 字节的累加和,取低 8 位 |
示例:`M3P0S500` 完整帧
```text
D5 01 08 4D 33 50 30 53 35 30 30 F1
```
### 设备 -> 主机响应帧
```text
B5 TYPE LEN DATA... CRC
```
| TYPE | 含义 |
|---|---|
| `F0` | 成功 |
| `F1` | CRC 错误 |
| `F2` | 包头错误 |
| `F3` | 板卡类型错误 |
| `F4` | 长度错误 |
| `FD` | 参数错误 |
| `FE` | 命令错误 |
| `FF` | 通用错误 |
---
## 命令表
| 命令 | 参数 | 说明 |
|---|---|---|
| `M3P{ch}S{duty}` | `ch=0/1``duty=0~1000` | 推杆推出 |
| `M4P{ch}S{duty}` | `ch=0/1``duty=0~1000` | 推杆拉回 |
| `M5P{ch}` | `ch=0/1` | 停止指定通道 |
| `M999` | 无 | 返回固件版本 |
| `M888` | 无 | 软件复位(当前已注释停用) |
| `M9999` | 无 | 进入 Bootloader(当前已注释停用) |
命令示例:
```text
M3P0S500 // CH1 推出,占空比 500
M4P1S1000 // CH2 拉回,占空比 1000
M5P0 // CH1 停止
M999 // 返回版本信息
```
`M999` 当前返回格式为 `v{工程代号}.{主版本}.{次版本}.{修订号}`,当前工程为 `v51.0.0.1`
---
## 工程配置
### 项目元信息
配置文件:[cmake/project_config.cmake](E:/Hulk_Coding/actuator_ctrl/cmake/project_config.cmake)
| 配置项 | 当前值 |
|---|---|
| `PROJECT_NAME` | `actuator` |
| `BOARD_TYPE_CODE` | `51` |
| `VERSION` | `V0.0.1` |
| `BUILD_VARIANT` | `APP` |
### 功能开关
配置文件:[Inc/board_config.h](E:/Hulk_Coding/actuator_ctrl/Inc/board_config.h)
| 宏 | 当前值 | 说明 |
|---|:---:|---|
| `RS485_MODE` | `ENABLE` | 使能 RS485 通信与 DE 引脚 |
| `SEGGER_RTT_DETECTION` | `ENABLE` | 使能 SEGGER RTT 调试输出 |
| `DEBUG_MODE` | `DISABLE` | 关闭 printf 串口调试 |
| `COM_DEBUG` | `DISABLE` | 关闭命令帧调试打印 |
| `DEBUG_VERBOSE` | `DISABLE` | 关闭详细调试信息 |
| `SOFTWARE_IIC` | `DISABLE` | I2C 未参与当前推杆控制逻辑 |
### 链接脚本
配置文件:[LD/gd32e23x_flash.ld](E:/Hulk_Coding/actuator_ctrl/LD/gd32e23x_flash.ld)
```text
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
```
当前为独立调试固件,不从 Bootloader 偏移启动,向量表偏移保持 `0x00`
---
## 工程结构
```
```text
.
├── CMakeLists.txt # 主构建文件
├── CMakePresets.json # CMake 预设(Debug/Release
├── cmake/
│ ├── arm-none-eabi-gcc.cmake # ARM GCC 工具链配置
│ ├── project.cmake # 编译选项(-Os/-O0, -mcpu=cortex-m23
│ ├── project_config.cmake # 项目名/版本号/编译变体
│ └── version.h.in # 自动生成固件版本头
├── Inc/ # 头文件
│ ├── board_config.h # 板级引脚定义 + 功能开关
├── CMakePresets.json # Debug / Release 预设
├── cmake/ # 工具链与版本配置
├── Inc/
│ ├── board_config.h # 引脚、外设与功能开关
│ ├── actuator.h # 推杆驱动接口
│ ├── command.h # 串口命令协议
── i2c.h / led.h / systick.h / uart.h
│ └── uart_ring_buffer.h / gd32e23x_it.h / gd32e23x_libopt.h
├── Src/ # 源码
│ ├── main.c # 入口函数
│ ├── command.c # 命令解析处理
│ ├── board_config.c # MCU 型号自动检测
── i2c.c / led.c / systick.c / uart.c / uart_ring_buffer.c
│ └── gd32e23x_it.c / system_gd32e23x.c / syscalls.c
├── SDK/
│ ├── CMSIS/ # ARM CMSIS Core (Cortex-M23) + GD 启动文件
│ └── GD32E23x_standard_peripheral/ # GD32 标准外设库
── ...
├── Src/
│ ├── main.c # 主循环
│ ├── actuator.c # PWM / 方向控制
│ ├── command.c # 协议解析与命令处理
│ ├── uart.c # RS485 / UART 初始化
── ...
├── SDK/ # CMSIS 与 GD32 标准外设库
├── LD/gd32e23x_flash.ld # 链接脚本
├── doc/ # 芯片数据手册
└── .vscode/ # VSCode 调试/烧录配置
├── doc/ # GD32E230 数据手册与技术文档
└── .vscode/ # 编译、烧录、调试任务
```
---
## 板级配置(`Inc/board_config.h`
所有功能开关和引脚定义集中在 `Inc/board_config.h`。功能开关均为单行数值宏:将右侧的 `ENABLE` 或 `DISABLE` 改为另一值即可;其中 `ENABLE` 为 `1``DISABLE` 为 `0`。以下为完整的宏开关说明和推荐使用方式。
### 功能开关速查表
| 宏 | 作用 | 默认值 | Release 建议 |
|---|------|:---:|:---:|
| `SOFTWARE_IIC` | I2C 实现方式 | `DISABLE`(硬件) | `DISABLE` |
| `DEBUG_MODE` | printf 串口输出 | `DISABLE` | `DISABLE` |
| `COM_DEBUG` | 命令帧调试打印 | `DISABLE` | `DISABLE` |
| `DEBUG_VERBOSE` | 详细调试信息 | `DISABLE` | `DISABLE` |
| `SEGGER_RTT_DETECTION` | SEGGER RTT 支持 | `ENABLE` | `DISABLE` |
---
### `SOFTWARE_IIC` — I2C 实现方式
选择 I2C 使用硬件外设还是软件 GPIO 模拟。
> 当前工程尚未实现 `SOFTWARE_IIC` 的条件编译驱动选择;该宏已迁移为数值配置,但改值不会在此版本切换 I2C 实现。
```c
#define SOFTWARE_IIC DISABLE // DISABLE: 硬件 I2C(默认);ENABLE: 软件 I2CGPIO 模拟)
```
| 选项 | 优点 | 缺点 |
|------|------|------|
| 硬件 I2C | DMA 支持、CPU 占用低 | 仅限固定引脚、调试复杂 |
| 软件 I2C | 任意 GPIO、移植方便 | CPU 占用高、速率受限 |
> 切换后需同步修改下方 I2C 引脚定义。
---
### `DEBUG_MODE` — 调试模式
开启后 USART0 输出 printf 调试信息。**Release 固件必须关闭。**
```c
#define DEBUG_MODE DISABLE // DISABLE: 关闭(默认);ENABLE: 开启调试输出
```
**影响范围:**
- 使能 `USART0` 初始化和 `printf` 重定向到串口
- 会占用 PA2/PA3 引脚和 USART0 硬件资源
- 增加 ROM 约 2~4KB(取决于 printf 调用量)
---
### `COM_DEBUG` — 命令帧调试打印
开启后串口命令解析过程打印每帧的详细内容(地址、长度、数据、校验)。**仅调试通信协议时开启。**
```c
#define COM_DEBUG DISABLE // DISABLE: 关闭(默认);ENABLE: 开启命令帧调试
```
**依赖:** 需要先开启 `DEBUG_MODE`,否则输出无法外发。
**输出示例:**
```text
[CMD] ADDR=01 LEN=05 DATA: AA BB CC DD EE CHK=OK
```
> ⚠️ Release 必须关闭,否则大量串口输出会严重拖慢主循环。
---
### `DEBUG_VERBOSE` — 详细调试信息
在 `DEBUG_MODE` 基础上输出更底层的信息,如 I2C 总线扫描结果、MCU 型号识别等。
```c
#define DEBUG_VERBOSE DISABLE // DISABLE: 关闭(默认);ENABLE: 开启详细调试
```
**额外输出:**
- 启动时打印 MCU Flash 容量检测结果
- I2C 初始化时扫描总线上的设备地址
- 其他诊断信息
> 依赖 `DEBUG_MODE`,开启后 ROM 进一步增加约 1~2KB。
---
### `SEGGER_RTT_DETECTION` — SEGGER RTT 支持
RTTReal-Time Transfer)是 SEGGER 的调试通道技术,通过 SWD 接口传输数据,不占用串口引脚,速度远超 UART。
```c
#define SEGGER_RTT_DETECTION ENABLE // DISABLE: 禁用 RTTENABLE: 启用 RTT(默认)
```
**启用时:**
- 自动包含 `SEGGER_RTT.h`,提供 `RTT_printf` / `RTT_WriteString` / `RTT_PutChar` 宏
- `SDK/SEGGER_RTT/` 模块参与编译和链接
- 可用 J-Link RTT Viewer 或 VSCode + cortex-debug 查看实时日志
**禁用时:**
- 应用层 RTT 头文件引用与调用代码均在预处理阶段排除
- RTT 宏展开为空操作;应用目标不生成 RTT 调用代码
- 为保持现有 CMake SDK 加载方式,`SDK/SEGGER_RTT/` 仍会参与构建;静态库中未被引用的对象不会被链接器提取
> **Release 建议关闭** — RTT 依赖调试器连接,量产固件中无意义且占用 ROM。
**依赖关系总览:**
```
COM_DEBUG ──── 依赖 ──→ DEBUG_MODE
DEBUG_VERBOSE ─ 依赖 ──→ DEBUG_MODE
SEGGER_RTT_DETECTION ─ 独立,与 DEBUG_MODE 并行
```
---
### 引脚定义
所有引脚宏集中在 `board_config.h` 尾部,按需修改:
```c
/* I2C */
#define I2C_SCL_PORT GPIOF
#define I2C_SCL_PIN GPIO_PIN_1
#define I2C_SDA_PORT GPIOF
#define I2C_SDA_PIN GPIO_PIN_0
/* LED */
#define LED_RCU RCU_GPIOB
#define LED_PORT GPIOB
#define LED_PIN GPIO_PIN_1
/* UART */
#define UART_GPIO_PORT GPIOA
#define UART_TX_PIN GPIO_PIN_2
#define UART_RX_PIN GPIO_PIN_3
#define UART_BAUDRATE 115200U
```
### MCU 型号自动检测
`board_config.c` 中的 `mcu_detect_and_config()` 上电自动识别 GD32E230 的 Flash 容量(F4=16K / F6=32K / F8=64K),结果存入全局变量 `g_mcu_flash_size`,并自动选择对应的 UART 外设(USART0 或 USART1)。
---
## Flash 偏移配置(配合 Bootloader
如果固件需要通过 Bootloader 启动(Bootloader 占用 Flash 前部区域),需修改两处:
**1. 链接脚本** — `LD/gd32e23x_flash.ld` 第 15 行:
```c
// 默认:从 Flash 起始运行
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 16K
// 配合 Bootloader:前 8KB 留给 BootloaderApp 从 0x08002000 开始
FLASH (rx) : ORIGIN = 0x08002000, LENGTH = 8K
```
**2. 向量表偏移** — `Src/system_gd32e23x.c` 第 44 行:
```c
// 默认
#define VECT_TAB_OFFSET (uint32_t)0x00
// 配合 Bootloader(值 = Flash 偏移量,不含 0x0800 前缀)
#define VECT_TAB_OFFSET (uint32_t)0x2000
```
> ⚠️ 两个偏移值必须对应修改:`LD` 中的 `ORIGIN` 减去 `0x08000000` 应等于 `VECT_TAB_OFFSET`。
---
## 工具链准备
### 1. ARM GCC 工具链
- **版本**xpack-arm-none-eabi-gcc-11.3.1-1.1
- **建议解压路径**:工程根目录下 `Toolchain/xpack-arm-none-eabi-gcc-11.3.1-1.1`
- **官方下载地址**https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases
- **路径自定义**
如需自定义工具链路径,修改 `cmake/arm-none-eabi-gcc.cmake` 中的 `_TOOLCHAIN_CANDIDATES` 列表,或通过 CMake 参数传入:
```bash
cmake --preset Debug -DTOOLCHAIN_DIRECTORY=/your/path/bin
```
### 2. OpenOCD(调试/烧录)
- **版本**xpack-openocd-0.11.0-3
- **建议解压路径**:任意位置(在 `.vscode/launch.json` 中配置路径)
- **获取地址**https://github.com/burakenez/gd32-tools-xpack-openocd/tree/v0.11.0-3
- **说明**
- 本版本提取自 Embedded Builder V1.4.1.23782。
- ⚠️ 请勿随意更换版本,因 GD32 MCU 支持有限,推荐严格使用此版本。
- **路径自定义**
修改 `.vscode/launch.json` 中 `miDebuggerPath` 和 `serverpath` 指向你的 OpenOCD 路径。
---
## 使用说明
## 编译与烧录
### 编译
```bash
# Debug 构建(-O0, -g3
cmake --preset Debug
cmake --build build/Debug
# Release 构建(-Os, -g0
```powershell
cmake --preset Release
cmake --build build/Release
cmake --build --preset Release
```
Debug 版本将 `Release` 换成 `Debug`。构建产物位于 `Build/Release/Application/`
```text
Application.elf
Application.hex
Application.bin
Application.map
actuator_V0.0.1_APP_<日期>.hex
actuator_V0.0.1_APP_<日期>.bin
```
### 烧录
通过 VSCode 任务栏运行 `Flash MCU` 任务,或命令行
使用 CMSIS-DAP + OpenOCD
```bash
openocd -f interface/cmsis-dap.cfg -f target/gd32e23x.cfg -c "program build/Debug/Application.elf verify reset exit"
```powershell
& 'D:\toolchain\openocd\bin\openocd.exe' -s 'D:\toolchain\openocd\scripts' `
-f 'interface/cmsis-dap.cfg' -f 'target/gd32e23x.cfg' `
-c 'reset_config srst_only connect_assert_srst; init; reset halt; flash write_image erase Build/Release/Application/Application.elf; reset; exit'
```
### 产物
编译输出位于 `build/<Config>/`
| 文件 | 说明 |
|------|------|
| `Application.elf` | ELF 固件(调试用) |
| `{项目名}_{版本}_{编译条件}_{日期}.hex` | Hex 文件 |
| `{项目名}_{版本}_{编译条件}_{日期}.bin` | 二进制文件 |
| `{项目名}_{版本}_{编译条件}_{日期}.list` | 反汇编清单 |
| `{项目名}_{版本}_{编译条件}_{日期}.map` | 内存映射 |
也可以直接在 VSCode 中运行 `Flash MCU` 任务。
---
## 时钟配置说明
## 调试
本工程默认系统时钟为内部 IRC8M 振荡器经 PLL 倍频后的 72MHz
如需修改主频或时钟源,请编辑 `Src/system_gd32e23x.c` 文件:
1. 查找如下宏定义区:
```c
// #define __SYSTEM_CLOCK_8M_HXTAL (__HXTAL)
// #define __SYSTEM_CLOCK_8M_IRC8M (__IRC8M)
// #define __SYSTEM_CLOCK_72M_PLL_HXTAL (uint32_t)(72000000)
#define __SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2 (uint32_t)(72000000)
```
2. 取消你需要的时钟方案的注释,并注释掉其它方案。
3. 保存后重新编译工程即可生效。
详细时钟初始化流程可参考 `Src/system_gd32e23x.c` 文件中的 `system_clock_config` 及相关函数实现。
- 使用 `.vscode/launch.json` 中的 `Debug with OpenOCD` 配置进行 SWD 调试
- `SEGGER_RTT_DETECTION` 开启时,可通过 RTT Viewer 或 cortex-debug 查看 `RTT_printf` 输出。
- 当前固件 Release 也保留了 RTT,便于联调;量产固件可关闭该宏以减小 ROM。
---
## vcpkg 依赖管理(可选)
## 已知限制
本工程可选支持 vcpkg 作为 C/C++ 工具链和构建工具的自动化依赖管理方案
- 自动下载和管理如 CMake、Ninja 等构建工具,简化环境配置
- 可扩展用于第三方 C/C++ 库的统一管理。
**启用方法**
1. 在项目根目录创建 `vcpkg-configuration.json` 文件,内容如下:
```json
{
"registries": [
{
"name": "microsoft",
"location": "https://aka.ms/vcpkg-ce-default",
"kind": "artifact"
},
{
"name": "arm",
"location": "https://aka.ms/vcpkg-artifacts-arm",
"kind": "artifact"
}
],
"requires": {
"arm:tools/ninja-build/ninja": "^1.12.0",
"arm:tools/kitware/cmake": "^3.28.4"
}
}
```
2. 启动 VSCode 或命令行,vcpkg 会自动检测并安装所需工具。
如不需要 vcpkg,可忽略本文件。
- 当前固件只控制推杆的 PWM 和方向,不读取推杆位置、限位开关或电流反馈
- `M888``M9999` 当前已在 `Src/command.c` 中注释停用,避免调试时误复位或误进入 Bootloader;需要时取消注释即可恢复。
- 若后续要配合 Bootloader,需要把 `LD/gd32e23x_flash.ld` 的 Flash 起点改为 Bootloader 之后的地址,并同步修改 `Src/system_gd32e23x.c` 中的 `VECT_TAB_OFFSET`
+127
View File
@@ -0,0 +1,127 @@
#include "actuator.h"
void actuator_init(void) {
// Initialize PWM pins for actuators
rcu_periph_clock_enable(ACTUATOR_CH1_PWM_RCU);
rcu_periph_clock_enable(ACTUATOR_CH2_PWM_RCU);
rcu_periph_clock_enable(ACTUATOR_CH1_GPIO_RCU);
rcu_periph_clock_enable(ACTUATOR_CH2_GPIO_RCU);
// rcu_periph_clock_enable(PWM3_RCU);
// rcu_periph_clock_enable(PWM4_RCU);
rcu_periph_clock_enable(ACTUATOR_PWM_TIMER_RCU); // Enable clock for TIMER0
gpio_mode_set(ACTUATOR_CH1_PWM_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, ACTUATOR_CH1_PWM_PIN);
gpio_output_options_set(ACTUATOR_CH1_PWM_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, ACTUATOR_CH1_PWM_PIN);
gpio_af_set(ACTUATOR_CH1_PWM_PORT, GPIO_AF_2, ACTUATOR_CH1_PWM_PIN);
gpio_mode_set(ACTUATOR_CH2_PWM_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, ACTUATOR_CH2_PWM_PIN);
gpio_output_options_set(ACTUATOR_CH2_PWM_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, ACTUATOR_CH2_PWM_PIN);
gpio_af_set(ACTUATOR_CH2_PWM_PORT, GPIO_AF_2, ACTUATOR_CH2_PWM_PIN);
gpio_mode_set(ACTUATOR_CH1_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, ACTUATOR_CH1_GPIO_PIN);
gpio_output_options_set(ACTUATOR_CH1_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, ACTUATOR_CH1_GPIO_PIN);
gpio_bit_reset(ACTUATOR_CH1_GPIO_PORT, ACTUATOR_CH1_GPIO_PIN); // Set initial state to LOW
gpio_mode_set(ACTUATOR_CH2_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, ACTUATOR_CH2_GPIO_PIN);
gpio_output_options_set(ACTUATOR_CH2_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, ACTUATOR_CH2_GPIO_PIN);
gpio_bit_reset(ACTUATOR_CH2_GPIO_PORT, ACTUATOR_CH2_GPIO_PIN); // Set initial state to LOW
// Additional actuator initialization code can be added here
// HSI = 72MHz , Freq Timer = 72MHz / (Prescaler + 1) / (Period + 1)
timer_deinit(ACTUATOR_PWM_TIMER);
timer_parameter_struct timer_initpara;
timer_initpara.prescaler = 2; // 72MHz / (2+1) = 24MHz
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 999; // 24MHz / (999 + 1) = 24kHz
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(ACTUATOR_PWM_TIMER, &timer_initpara);
timer_oc_parameter_struct timer_ocinitpara;
timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocinitpara.outputstate = TIMER_CCX_ENABLE;
timer_ocinitpara.outputnstate = TIMER_CCXN_DISABLE;
timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocinitpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
timer_ocinitpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
// CH0
timer_channel_output_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH1_PWM_TIMER_CH, &timer_ocinitpara);
timer_channel_output_mode_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH1_PWM_TIMER_CH, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH1_PWM_TIMER_CH, TIMER_OC_SHADOW_ENABLE);
timer_channel_output_pulse_value_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH1_PWM_TIMER_CH, 0);
// CH1
timer_channel_output_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH2_PWM_TIMER_CH, &timer_ocinitpara);
timer_channel_output_mode_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH2_PWM_TIMER_CH, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH2_PWM_TIMER_CH, TIMER_OC_SHADOW_ENABLE);
timer_channel_output_pulse_value_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH2_PWM_TIMER_CH, 0);
timer_auto_reload_shadow_enable(ACTUATOR_PWM_TIMER);
timer_primary_output_config(ACTUATOR_PWM_TIMER, ENABLE);
timer_enable(ACTUATOR_PWM_TIMER);
}
void actuator_output(actuator_channel_t channel, uint16_t duty, actuator_direction_t direction) {
if (duty > ACTUARTOR_PERIOD_MAX) duty = ACTUARTOR_PERIOD_MAX; // Limit duty cycle to max value
if (direction != DIRECTION_PUSH && direction != DIRECTION_PULL) {
// Invalid direction, handle error if necessary
return;
}
// Set PWM output for the specified actuator channel
// This is a placeholder; actual implementation will depend on the PWM configuration
// For example, setting the duty cycle to a specific value to activate the actuator
if (channel == ACTUATOR_CH1) {
if (direction == DIRECTION_PUSH) {
SEGGER_RTT_printf(0, "[ACTUATOR] Actuator CH1 PUSH with duty %d\n", duty);
gpio_bit_reset(ACTUATOR_CH1_GPIO_PORT, ACTUATOR_CH1_GPIO_PIN); // Set direction LOW
timer_channel_output_pulse_value_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH1_PWM_TIMER_CH, duty);
} else if (direction == DIRECTION_PULL) {
SEGGER_RTT_printf(0, "[ACTUATOR] Actuator CH1 PULL with duty %d\n", duty);
gpio_bit_set(ACTUATOR_CH1_GPIO_PORT, ACTUATOR_CH1_GPIO_PIN); // Set direction HIGH
timer_channel_output_pulse_value_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH1_PWM_TIMER_CH, (ACTUARTOR_PERIOD_MAX - duty));
}
} else if (channel == ACTUATOR_CH2) {
if (direction == DIRECTION_PUSH) {
SEGGER_RTT_printf(0, "[ACTUATOR] Actuator CH2 PUSH with duty %d\n", duty);
gpio_bit_reset(ACTUATOR_CH2_GPIO_PORT, ACTUATOR_CH2_GPIO_PIN); // Set direction LOW
timer_channel_output_pulse_value_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH2_PWM_TIMER_CH, duty);
} else if (direction == DIRECTION_PULL) {
SEGGER_RTT_printf(0, "[ACTUATOR] Actuator CH2 PULL with duty %d\n", duty);
gpio_bit_set(ACTUATOR_CH2_GPIO_PORT, ACTUATOR_CH2_GPIO_PIN); // Set direction HIGH
timer_channel_output_pulse_value_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH2_PWM_TIMER_CH, (ACTUARTOR_PERIOD_MAX - duty));
}
} else {
// Invalid channel, handle error if necessary
timer_channel_output_pulse_value_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH1_PWM_TIMER_CH, 0); // Ensure CH1 is off
timer_channel_output_pulse_value_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH2_PWM_TIMER_CH, 0); // Ensure CH2 is off
gpio_bit_reset(ACTUATOR_CH1_GPIO_PORT, ACTUATOR_CH1_GPIO_PIN); // Set CH1 direction LOW
gpio_bit_reset(ACTUATOR_CH2_GPIO_PORT, ACTUATOR_CH2_GPIO_PIN); // Set CH2 direction LOW
}
}
void actuator_stop(actuator_channel_t channel) {
if(channel == ACTUATOR_CH1) {
SEGGER_RTT_printf(0, "[ACTUATOR] Stopping Actuator CH1\n");
timer_channel_output_pulse_value_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH1_PWM_TIMER_CH, ACTUARTOR_PERIOD_MAX); // Ensure CH1 is off
gpio_bit_set(ACTUATOR_CH1_GPIO_PORT, ACTUATOR_CH1_GPIO_PIN); // Set CH1 direction High
} else if(channel == ACTUATOR_CH2) {
SEGGER_RTT_printf(0, "[ACTUATOR] Stopping Actuator CH2\n");
timer_channel_output_pulse_value_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH2_PWM_TIMER_CH, ACTUARTOR_PERIOD_MAX); // Ensure CH2 is off
gpio_bit_set(ACTUATOR_CH2_GPIO_PORT, ACTUATOR_CH2_GPIO_PIN); // Set CH2 direction High
} else {
// Invalid channel, handle error if necessary
SEGGER_RTT_printf(0, "[ACTUATOR] Invalid channel specified for stop: %d\n", channel);
timer_channel_output_pulse_value_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH1_PWM_TIMER_CH, ACTUARTOR_PERIOD_MAX); // Ensure CH1 is off
timer_channel_output_pulse_value_config(ACTUATOR_PWM_TIMER, ACTUATOR_CH2_PWM_TIMER_CH, ACTUARTOR_PERIOD_MAX); // Ensure CH2 is off
gpio_bit_set(ACTUATOR_CH1_GPIO_PORT, ACTUATOR_CH1_GPIO_PIN); // Set CH1 direction High
gpio_bit_set(ACTUATOR_CH2_GPIO_PORT, ACTUATOR_CH2_GPIO_PIN); // Set CH2 direction High
}
}
+83 -23
View File
@@ -21,6 +21,7 @@
#include "gd32e23x_usart.h"
#include "i2c.h"
#include "core_cm23.h"
#include "actuator.h"
/* ============================================================================
* 协议格式说明
@@ -67,15 +68,15 @@
/** @name 响应帧标识符
* @{ */
#define RESP_HEADER 0xB5 /**< 响应帧包头标识 >**/
#define RESP_TYPE_OK 0xF0 /**< 成功响应类型 >**/
#define RESP_TYPE_CRC_ERR 0xF1 /**< CRC校验错误 >**/
#define RESP_TYPE_HEADER_ERR 0xF2 /**< 包头错误 >**/
#define RESP_TYPE_TYPE_ERR 0xF3 /**< 板类型错误 >**/
#define RESP_TYPE_LEN_ERR 0xF4 /**< 长度错误 >**/
#define RESP_TYPE_PARAM_ERR 0xFD /**< 参数错误 >**/
#define RESP_TYPE_CMD_ERR 0xFE /**< 命令错误 >**/
#define RESP_TYPE_ERR 0xFF /**< 通用错误 >**/
#define RESP_HEADER 0xB5 /**< 响应帧包头标识 */
#define RESP_TYPE_OK 0xF0 /**< 成功响应类型 */
#define RESP_TYPE_CRC_ERR 0xF1 /**< CRC校验错误 */
#define RESP_TYPE_HEADER_ERR 0xF2 /**< 包头错误 */
#define RESP_TYPE_TYPE_ERR 0xF3 /**< 板类型错误 */
#define RESP_TYPE_LEN_ERR 0xF4 /**< 长度错误 */
#define RESP_TYPE_PARAM_ERR 0xFD /**< 参数错误 */
#define RESP_TYPE_CMD_ERR 0xFE /**< 命令错误 */
#define RESP_TYPE_ERR 0xFF /**< 通用错误 */
/** @} */
/* ============================================================================
@@ -101,7 +102,7 @@ void system_software_reset(void)
}
/* Debug output control */
#if COM_DEBUG == ENABLE
#if COM_DEBUG == CFG_ENABLE
#include <stdio.h>
#define COMMAND_DEBUG(fmt, ...) printf("[COMMAND] " fmt "\n", ##__VA_ARGS__)
#else
@@ -444,19 +445,78 @@ void handle_command(const uint8_t *frame, uint8_t len) {
send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok));
return;
case 3u: // M3 p_val: Actuator Channel. s_val: Actuator Duty Cycle
{
uint32_t p_val = 0;
uint32_t s_val = 0;
bool has_p = find_parameter_value(cmd, cmd_len, 'P', &p_val);
bool has_s = find_parameter_value(cmd, cmd_len, 'S', &s_val);
if (!(has_p && has_s)) {
send_response(RESP_TYPE_PARAM_ERR, s_report_status_err, sizeof(s_report_status_err));
return;
}
if (p_val > (uint32_t)ACTUATOR_CH2 || s_val > ACTUARTOR_PERIOD_MAX) {
send_response(RESP_TYPE_PARAM_ERR, s_report_status_err, sizeof(s_report_status_err));
return;
}
SEGGER_RTT_printf(0, "[COMMAND] M3 Command(PUSH): Actuator Channel=%u, Duty Cycle=%u \n", p_val, s_val);
actuator_output((actuator_channel_t)p_val, (uint16_t)s_val, DIRECTION_PUSH);
send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok));
}
return;
case 4u: // M4 p_val: Actuator Channel. s_val: Actuator Duty Cycle
{
uint32_t p_val = 0;
uint32_t s_val = 0;
bool has_p = find_parameter_value(cmd, cmd_len, 'P', &p_val);
bool has_s = find_parameter_value(cmd, cmd_len, 'S', &s_val);
if (!(has_p && has_s)) {
send_response(RESP_TYPE_PARAM_ERR, s_report_status_err, sizeof(s_report_status_err));
return;
}
if (p_val > (uint32_t)ACTUATOR_CH2 || s_val > ACTUARTOR_PERIOD_MAX) {
send_response(RESP_TYPE_PARAM_ERR, s_report_status_err, sizeof(s_report_status_err));
return;
}
SEGGER_RTT_printf(0, "[COMMAND] M4 Command(PULL): Actuator Channel=%u, Duty Cycle=%u \n", p_val, s_val);
actuator_output((actuator_channel_t)p_val, (uint16_t)s_val, DIRECTION_PULL);
send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok));
}
return;
case 5u: // M5 stop actuator output
{
uint32_t p_val = 0;
bool has_p = find_parameter_value(cmd, cmd_len, 'P', &p_val);
if (!has_p || p_val > (uint32_t)ACTUATOR_CH2) {
send_response(RESP_TYPE_PARAM_ERR, s_report_status_err, sizeof(s_report_status_err));
return;
}
SEGGER_RTT_printf(0, "[COMMAND] M5 Command(STOP): Actuator Channel=%u \n", p_val);
actuator_stop((actuator_channel_t)p_val);
send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok));
}
return;
/* ==========================================
* M888 软件重启命令
* ========================================== */
case 888u:
// 先发送确认响应
send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok));
// case 888u:
// // 先发送确认响应
// send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok));
// 短暂延时确保响应发送完成
delay_ms(100);
// // 短暂延时确保响应发送完成
// delay_ms(100);
// 执行软件重启
system_software_reset();
return;
// // 执行软件重启
// system_software_reset();
// return;
/* ==========================================
* M999 输出固件版本号命令
@@ -485,10 +545,10 @@ void handle_command(const uint8_t *frame, uint8_t len) {
/* ==========================================
* M9999 进入OTA模式
* ========================================== */
case 9999u: //M9999: 进入OTA模式
__disable_irq(); // 关中断,防止竞态条件
NVIC_SystemReset(); // 触发系统复位,进入Bootloader
return;
// case 9999u: //M9999: 进入OTA模式
// __disable_irq(); // 关中断,防止竞态条件
// NVIC_SystemReset(); // 触发系统复位,进入Bootloader
// return;
default:
send_response(RESP_TYPE_CMD_ERR, s_report_status_err, sizeof(s_report_status_err));
@@ -565,7 +625,7 @@ void command_process(void) {
// 到帧尾,进行各项校验
bool verification_status = true;
#if DEBUG_VERBOSE == ENABLE
#if DEBUG_VERBOSE == CFG_ENABLE
if (cmd_buf[0] != PROTOCOL_PACKAGE_HEADER) {
send_response(RESP_TYPE_HEADER_ERR, s_report_status_err, sizeof(s_report_status_err));
verification_status = false;
+8 -9
View File
@@ -41,6 +41,7 @@ OF SUCH DAMAGE.
#include <stdio.h>
#include "i2c.h"
#include "board_config.h"
#include "actuator.h"
/*!
\brief main function
@@ -52,31 +53,29 @@ int main(void)
{
led_init();
mcu_detect_and_config();
// delay_ms(1000);
systick_config();
uart_ring_buffer_init();
uart_init();
i2c_config();
actuator_init();
#if DEBUG_MODE == ENABLE
#if DEBUG_MODE == CFG_ENABLE
printf("Hello World!\r\n");
#endif
#if SEGGER_RTT_DETECTION == ENABLE
#if SEGGER_RTT_DETECTION == CFG_ENABLE
RTT_printf(0, "Hello World!\r\n");
#endif
#if DEBUG_VERBOSE == ENABLE
i2c_scan();
#if DEBUG_VERBOSE == CFG_ENABLE
// i2c_scan();
i2c_bus_reset();
// i2c_bus_reset();
#endif
/* ========== Command Testing ========== */
// command_execute("M3P0S999");
/* ========== */
+15
View File
@@ -17,6 +17,14 @@ void uart_init(void) {
gpio_mode_set(UART_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, UART_TX_PIN | UART_RX_PIN);
gpio_output_options_set(UART_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, UART_TX_PIN | UART_RX_PIN);
#if RS485_MODE == CFG_ENABLE
/* 配置 RS485 DE 引脚 */
rcu_periph_clock_enable(RS485_DE_RCU);
gpio_af_set(RS485_DE_PORT, GPIO_AF_1, RS485_DE_PIN);
gpio_mode_set(RS485_DE_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, RS485_DE_PIN);
gpio_output_options_set(RS485_DE_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_DE_PIN);
#endif
/* 配置波特率、数据位、停止位等 */
usart_deinit(UART_PHY);
usart_word_length_set(UART_PHY, USART_WL_8BIT);
@@ -26,6 +34,13 @@ void uart_init(void) {
usart_receive_config(UART_PHY, USART_RECEIVE_ENABLE);
usart_transmit_config(UART_PHY, USART_TRANSMIT_ENABLE);
#if RS485_MODE == CFG_ENABLE
// 配置 RS485 模式
usart_rs485_driver_enable(UART_PHY);
usart_driver_assertime_config(UART_PHY, 10); // 设置驱动器断言时间为 10 个时钟周期
usart_driver_deassertime_config(UART_PHY, 10); // 设置驱动器去断言时间为 10 个时钟周期
#endif
usart_enable(UART_PHY);
nvic_irq_enable(UART_IRQ, 0);
+1 -1
View File
@@ -1,6 +1,6 @@
# Project basic info
set(PROJECT_NAME "actuator")
set(BOARD_TYPE_CODE 99)
set(BOARD_TYPE_CODE 51)
set(VERSION_MAJOR 0)
set(VERSION_MINOR 0)
set(VERSION_PATCH 1)