generated from hulk/gd32e23x_template_cmake_vscode
Compare commits
10
Commits
cb720da01f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0fd0d911a9 | ||
|
|
43c25b2865 | ||
|
|
b683c877b9 | ||
|
|
ffb8ba0329 | ||
|
|
86351a7bcb | ||
|
|
15cf25a9e0 | ||
|
|
37232c617f | ||
|
|
f6ba273aff | ||
|
|
c8700aa353 | ||
|
|
6e3290c70e |
+2
-1
@@ -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
|
||||
)
|
||||
|
||||
# 设置输出目录
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -1,396 +1,256 @@
|
||||
# GD32E23x 工程模板
|
||||
# LA-T8 推杆驱动控制固件
|
||||
|
||||
本仓库为兆易创新 GD32E23x 系列 MCU 的 CMake + VSCode 工程模板,适合嵌入式开发快速上手和团队协作。
|
||||
本工程是 LA-T8-12-5-50/105-188 电动推杆的控制板驱动固件,基于 GD32E230F8(Cortex-M23)开发,使用 CMake + VSCode + ARM GCC 构建。
|
||||
|
||||
当前为调试工程:不配合 Bootloader,Flash 从 `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
|
||||
- 调试串口:USART0(PA2 TX / PA3 RX),115200 波特率
|
||||
- I2C:默认硬件 I2C0(PF0 SDA / PF1 SCL),可通过 `board_config.h` 切换为软件 I2C
|
||||
| 功能 | 引脚 / 外设 | 说明 |
|
||||
|---|---|---|
|
||||
| 主控 | GD32E230F8 | Cortex-M23,64KB Flash,8KB RAM |
|
||||
| 系统时钟 | IRC8M + PLL | 72MHz |
|
||||
| 推杆 CH1 | PA10 / TIMER0_CH2 + PF0 方向 | 通道 0 |
|
||||
| 推杆 CH2 | PA9 / TIMER0_CH1 + PF1 方向 | 通道 1 |
|
||||
| 通信口 | PA2 TX / PA3 RX | F8 自动选择 USART1,115200 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: 软件 I2C(GPIO 模拟)
|
||||
```
|
||||
|
||||
| 选项 | 优点 | 缺点 |
|
||||
|------|------|------|
|
||||
| 硬件 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 支持
|
||||
|
||||
RTT(Real-Time Transfer)是 SEGGER 的调试通道技术,通过 SWD 接口传输数据,不占用串口引脚,速度远超 UART。
|
||||
|
||||
```c
|
||||
#define SEGGER_RTT_DETECTION ENABLE // DISABLE: 禁用 RTT;ENABLE: 启用 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 留给 Bootloader,App 从 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
@@ -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
@@ -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
@@ -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
@@ -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,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)
|
||||
|
||||
Reference in New Issue
Block a user