431 lines
14 KiB
Markdown
431 lines
14 KiB
Markdown
# UART电刺激控制系统技术文档
|
||
|
||
## 1. 系统概述
|
||
|
||
本系统基于ENS1芯片实现UART通信控制的电刺激(EMS)功能,通过串口接收控制指令,实时调整电刺激参数并控制输出波形。
|
||
|
||
### 1.1 主要功能
|
||
- UART数据接收与解析
|
||
- 电刺激参数配置
|
||
- 实时波形控制
|
||
- 数据回传确认
|
||
|
||
### 1.2 技术特点
|
||
- 中断驱动的UART通信
|
||
- CRC校验确保数据完整性
|
||
- 实时参数更新
|
||
- 渐进式波形控制
|
||
|
||
## 2. 系统架构
|
||
|
||
### 2.1 文件结构
|
||
```
|
||
USER/
|
||
├── mian.c # 主程序文件
|
||
├── ENS001_CONFIG.h # 配置文件
|
||
└── MY_HEADER.h # 自定义头文件
|
||
|
||
FWLIB/
|
||
├── source/
|
||
│ ├── ENS1_UART.c # UART驱动实现
|
||
│ ├── ENS1_TIMER.c # 定时器控制
|
||
│ └── ENS1_WAVEGEN.c # 波形生成
|
||
└── include/
|
||
└── ENS1_UART.h # UART驱动头文件
|
||
```
|
||
|
||
### 2.2 核心模块
|
||
- **UART通信模块**: 负责数据接收、解析和回传
|
||
- **电刺激控制模块**: 负责参数配置和波形控制
|
||
- **定时器模块**: 提供系统时钟基准
|
||
- **波形生成模块**: 生成电刺激输出波形
|
||
|
||
## 3. UART通信协议
|
||
|
||
### 3.1 数据包格式
|
||
```
|
||
总长度: 19字节
|
||
┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
|
||
│ 功能码 │ 功能码 │ 数据长度│ 数据长度│ 开关类型│ 强度 │ 频率 │ 频率 │ 持续时间│ 持续时间│ 休息时间│ 休息时间│ 静默时间│ 静默时间│ 缓进时间│ 保持时间│ 缓出时间│ CRC16 │ CRC16 │
|
||
│ (低字节)│ (高字节)│ (低字节)│ (高字节)│ │ │ (低字节)│ (高字节)│ (低字节)│ (高字节)│ (低字节)│ (高字节)│ (低字节)│ (高字节)│ │ │ │ (低字节)│ (高字节)│
|
||
└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
|
||
```
|
||
|
||
### 3.2 字段说明
|
||
| 字段 | 字节位置 | 长度 | 说明 | 示例值 |
|
||
|------|----------|------|------|--------|
|
||
| 功能码 | 0-1 | 2字节 | 固定值0x0003 | 0x0003 |
|
||
| 数据长度 | 2-3 | 2字节 | 数据部分长度 | 0x000D |
|
||
| 开关类型 | 4 | 1字节 | 0x00=关闭, 0x10~0x1F=开启 | 0x10 |
|
||
| 强度 | 5 | 1字节 | 电刺激强度(0-255) | 50 |
|
||
| 频率 | 6-7 | 2字节 | 电刺激频率(Hz) | 100 |
|
||
| 持续时间 | 8-9 | 2字节 | 总持续时间(ms) | 5000 |
|
||
| 休息时间 | 10-11 | 2字节 | 休息间隔(ms) | 1000 |
|
||
| 静默时间 | 12-13 | 2字节 | 静默间隔(ms) | 244 |
|
||
| 缓进时间 | 14 | 1字节 | 渐入时间(ms) | 1 |
|
||
| 保持时间 | 15 | 1字节 | 保持时间(ms) | 1 |
|
||
| 缓出时间 | 16 | 1字节 | 渐出时间(ms) | 3 |
|
||
| CRC16 | 17-18 | 2字节 | CRC-16-CCITT-FALSE校验 | 0x90B7 |
|
||
|
||
### 3.3 字节序说明
|
||
- 多字节字段采用小端序(Little Endian)
|
||
- 低字节在前,高字节在后
|
||
|
||
## 4. 工作流程
|
||
|
||
### 4.1 系统初始化流程
|
||
```mermaid
|
||
graph TD
|
||
A[系统启动] --> B[MTP初始化]
|
||
B --> C[GPIO配置]
|
||
C --> D[UART初始化]
|
||
D --> E[定时器初始化]
|
||
E --> F[电刺激模块初始化]
|
||
F --> G[进入主循环]
|
||
```
|
||
|
||
### 4.2 UART数据接收流程
|
||
```mermaid
|
||
graph TD
|
||
A[UART中断触发] --> B[读取FIFO数据]
|
||
B --> C[存储到接收缓冲区]
|
||
C --> D[回传数据确认]
|
||
D --> E{数据包完整?}
|
||
E -->|否| F[继续接收]
|
||
E -->|是| G[解析数据包]
|
||
G --> H{解析成功?}
|
||
H -->|否| I[丢弃数据包]
|
||
H -->|是| J[更新电刺激配置]
|
||
J --> K[启动/停止电刺激]
|
||
K --> L[清除缓冲区]
|
||
```
|
||
|
||
### 4.3 电刺激控制流程
|
||
```mermaid
|
||
graph TD
|
||
A[接收UART数据] --> B[解析数据包]
|
||
B --> C{开关类型检查}
|
||
C -->|0x00| D[停止电刺激]
|
||
C -->|0x10~0x1F| E[参数有效性检查]
|
||
E --> F[创建新配置]
|
||
F --> G[应用配置]
|
||
G --> H[启动电刺激]
|
||
H --> I[波形生成]
|
||
```
|
||
|
||
## 5. 电刺激缓进缓出实现
|
||
|
||
### 5.1 缓进缓出原理
|
||
|
||
电刺激的缓进缓出功能通过三个阶段实现平滑的强度变化:
|
||
|
||
#### 5.1.1 三个阶段
|
||
1. **缓进阶段 (Ramp Up)**: 强度从0逐渐增加到目标值
|
||
2. **保持阶段 (Hold)**: 强度保持在目标值
|
||
3. **缓出阶段 (Ramp Down)**: 强度从目标值逐渐减少到0
|
||
|
||
#### 5.1.2 时间控制
|
||
```c
|
||
// 时间参数(单位:毫秒)
|
||
uint32_t ramp_up_ms = g_ems_config.ramp_up_time * 1000; // 缓进时间
|
||
uint32_t hold_ms = g_ems_config.hold_time * 1000; // 保持时间
|
||
uint32_t ramp_down_ms = g_ems_config.ramp_down_time * 1000; // 缓出时间
|
||
```
|
||
|
||
#### 5.1.3 强度计算算法
|
||
- **缓进阶段**: `target_intensity = (time_count * max_intensity) / ramp_up_ms`
|
||
- **保持阶段**: `target_intensity = max_intensity`
|
||
- **缓出阶段**: `target_intensity = max_intensity - (ramp_down_elapsed * max_intensity) / ramp_down_ms`
|
||
|
||
### 5.2 缓进缓出实现代码
|
||
|
||
```c
|
||
// 缓进缓出处理函数(在电刺激处理中调用)
|
||
void EMS_Process_Ramp(void)
|
||
{
|
||
if(ems_state)
|
||
{
|
||
time_count++;
|
||
if (!g_ems_config.enable_ramp || !g_ems_running)
|
||
{
|
||
return; // 如果未启用缓进缓出或未运行,直接返回
|
||
}
|
||
|
||
// 计算各阶段时间(毫秒)
|
||
uint32_t ramp_up_ms = g_ems_config.ramp_up_time * 1000;
|
||
uint32_t hold_ms = g_ems_config.hold_time * 1000;
|
||
uint32_t ramp_down_ms = g_ems_config.ramp_down_time * 1000;
|
||
|
||
switch (g_ramp_phase)
|
||
{
|
||
case 0: // 缓进阶段
|
||
{
|
||
if (time_count <= g_ems_config.ramp_up_time * 1000)
|
||
{
|
||
// 线性递增强度
|
||
uint16_t target_intensity = (time_count * g_ems_config.intensity) / ramp_up_ms;
|
||
if (target_intensity > g_ems_config.intensity) {
|
||
target_intensity = g_ems_config.intensity;
|
||
}
|
||
g_current_intensity = target_intensity;
|
||
}
|
||
else
|
||
{
|
||
// 缓进完成,进入保持阶段
|
||
g_ramp_phase = 1;
|
||
g_current_intensity = g_ems_config.intensity;
|
||
}
|
||
break;
|
||
}
|
||
|
||
case 1: // 保持阶段
|
||
{
|
||
if(time_count <= (ramp_up_ms + hold_ms))
|
||
{
|
||
g_current_intensity = g_ems_config.intensity;
|
||
}
|
||
else
|
||
{
|
||
g_ramp_phase = 2; // 进入缓出阶段
|
||
}
|
||
break;
|
||
}
|
||
|
||
case 2: // 缓出阶段
|
||
{
|
||
if(time_count <= (ramp_up_ms + hold_ms + ramp_down_ms))
|
||
{
|
||
// 计算缓出阶段的时间偏移
|
||
uint32_t ramp_down_start = ramp_up_ms + hold_ms;
|
||
uint32_t ramp_down_elapsed = time_count - ramp_down_start;
|
||
|
||
// 线性递减强度
|
||
uint16_t target_intensity = g_ems_config.intensity -
|
||
(ramp_down_elapsed * g_ems_config.intensity) / ramp_down_ms;
|
||
|
||
if (target_intensity > g_ems_config.intensity) {
|
||
target_intensity = 0;
|
||
}
|
||
g_current_intensity = target_intensity;
|
||
}
|
||
else
|
||
{
|
||
// 缓出完成,停止电刺激
|
||
g_current_intensity = 0;
|
||
g_ramp_phase = 0; // 重置为缓进阶段
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.3 波形强度更新
|
||
|
||
```c
|
||
// 更新波形强度(不重新配置硬件)
|
||
void wavegen_UpdateIntensity(CMSDK_WAVE_GEN_TypeDef *CMSDK_WAVEGEN_DRVA, uint16_t intensity)
|
||
{
|
||
// 只更新波形数据,不重新配置硬件
|
||
for (int i = 0; i < 64; i++)
|
||
{
|
||
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_IN_WAVE_ADDR_REG = i;
|
||
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_IN_WAVE_DATA_REG = intensity;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.4 状态管理变量
|
||
|
||
```c
|
||
// 全局状态变量
|
||
uint8_t g_ramp_phase = 0; // 渐进阶段:0=缓进, 1=保持, 2=缓出
|
||
uint32_t time_count = 0; // 时间计数器(毫秒)
|
||
uint16_t g_current_intensity = 0; // 当前强度值
|
||
uint8_t g_ems_running = 0; // 电刺激运行状态
|
||
```
|
||
|
||
### 5.5 缓进缓出流程图
|
||
|
||
```mermaid
|
||
graph TD
|
||
A[开始电刺激] --> B[缓进阶段]
|
||
B --> C{时间 < 缓进时间?}
|
||
C -->|是| D[线性增加强度]
|
||
C -->|否| E[进入保持阶段]
|
||
D --> F[更新波形强度]
|
||
F --> C
|
||
E --> G{时间 < 保持时间?}
|
||
G -->|是| H[保持最大强度]
|
||
G -->|否| I[进入缓出阶段]
|
||
H --> J[更新波形强度]
|
||
J --> G
|
||
I --> K{时间 < 缓出时间?}
|
||
K -->|是| L[线性减少强度]
|
||
K -->|否| M[停止电刺激]
|
||
L --> N[更新波形强度]
|
||
N --> K
|
||
M --> O[重置状态]
|
||
O --> A
|
||
```
|
||
|
||
## 6. 核心代码实现
|
||
|
||
### 6.1 UART中断处理函数
|
||
```c
|
||
void UART1_Handler(void) {
|
||
uint8_t rev_data = 0;
|
||
uint32_t ParamNumber = 0;
|
||
|
||
// 清除NVIC中断挂起位
|
||
NVIC_ClearPendingIRQ(UART1_IRQn);
|
||
|
||
// 检查中断类型
|
||
uint8_t int_type = UART_INT_TYPE(CMSDK_UART1);
|
||
|
||
// 数据就绪中断处理
|
||
if((int_type == INT_RCV_DATA_AVAILABLE) || (int_type == INT_CHAR_TIMEOUT_INDICATION)) {
|
||
ParamNumber = (CMSDK_UART1->FSR >> 16) & 0x1f;
|
||
|
||
// 读取FIFO中的所有数据
|
||
for(uint32_t i = 0; i < ParamNumber; i++) {
|
||
rev_data = CMSDK_UART1->RBR;
|
||
|
||
// 存储到缓冲区
|
||
if(uart_rx_count < sizeof(uart_rx_buffer)) {
|
||
uart_rx_buffer[uart_rx_count] = rev_data;
|
||
uart_rx_count++;
|
||
}
|
||
|
||
// 回传数据确认
|
||
UartPutc(CMSDK_UART1, rev_data);
|
||
}
|
||
|
||
// 检查完整数据包
|
||
if(uart_rx_count >= 19) {
|
||
UART_EMS_Packet_t ems_packet;
|
||
if(ParseUART_EMS_Packet(uart_rx_buffer, uart_rx_count, &ems_packet)) {
|
||
UpdateEMS_ConfigFromUART(&ems_packet);
|
||
}
|
||
uart_rx_count = 0; // 清除缓冲区
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 6.2 数据包解析函数
|
||
```c
|
||
uint8_t ParseUART_EMS_Packet(uint8_t *data, uint16_t length, UART_EMS_Packet_t *packet) {
|
||
// 解析数据包(小端序)
|
||
packet->function_code = (data[1] << 8) | data[0];
|
||
packet->data_length = (data[3] << 8) | data[2];
|
||
packet->switch_type = data[4];
|
||
packet->intensity = data[5];
|
||
packet->frequency = (data[7] << 8) | data[6];
|
||
packet->duration = (data[9] << 8) | data[8];
|
||
packet->rest_time = (data[11] << 8) | data[10];
|
||
packet->silent_time = (data[13] << 8) | data[12];
|
||
packet->ramp_up_time = data[14];
|
||
packet->hold_time = data[15];
|
||
packet->ramp_down_time = data[16];
|
||
packet->crc16 = (data[18] << 8) | data[17];
|
||
|
||
// CRC校验(当前已注释)
|
||
// uint16_t calculated_crc = CalculateCRC16_CCITT_FALSE(data, 17);
|
||
// if(calculated_crc != packet->crc16) return 0;
|
||
|
||
return 1; // 解析成功
|
||
}
|
||
```
|
||
|
||
### 6.3 电刺激配置更新函数
|
||
```c
|
||
void UpdateEMS_ConfigFromUART(UART_EMS_Packet_t *packet) {
|
||
// 检查开关状态
|
||
if(packet->switch_type == 0x00) {
|
||
EMS_Stop();
|
||
return;
|
||
}
|
||
|
||
// 检查电刺激类型有效性
|
||
if(packet->switch_type < 0x10 || packet->switch_type > 0x1F) {
|
||
return;
|
||
}
|
||
|
||
// 创建新配置
|
||
EMS_Config_TypeDef new_config = {
|
||
.frequency = packet->frequency,
|
||
.duration = packet->duration,
|
||
.intensity = packet->intensity,
|
||
.rest_time = packet->rest_time,
|
||
.silent_time = packet->silent_time,
|
||
.ramp_up_time = packet->ramp_up_time,
|
||
.hold_time = packet->hold_time,
|
||
.ramp_down_time = packet->ramp_down_time,
|
||
.enable_ramp = 1
|
||
};
|
||
|
||
// 应用配置并启动
|
||
EMS_Configure(&new_config);
|
||
EMS_Start();
|
||
}
|
||
```
|
||
|
||
## 7. 关键数据结构
|
||
|
||
### 7.1 UART数据包结构
|
||
```c
|
||
typedef struct {
|
||
uint16_t function_code; // 功能码 (0x0003)
|
||
uint16_t data_length; // 数据长度 (0x000D)
|
||
uint8_t switch_type; // 开关状态以及电刺激类型
|
||
uint8_t intensity; // 强度值
|
||
uint16_t frequency; // 频率值
|
||
uint16_t duration; // 总持续时间 (ms)
|
||
uint16_t rest_time; // 休息时间 (ms)
|
||
uint16_t silent_time; // 静默时间 (ms)
|
||
uint8_t ramp_up_time; // 缓进时间
|
||
uint8_t hold_time; // 保持时间
|
||
uint8_t ramp_down_time; // 缓出时间
|
||
uint16_t crc16; // CRC16校验
|
||
} UART_EMS_Packet_t;
|
||
```
|
||
|
||
### 7.2 电刺激配置结构
|
||
```c
|
||
typedef struct {
|
||
uint16_t frequency; // 频率
|
||
uint16_t duration; // 持续时间
|
||
uint8_t intensity; // 强度
|
||
uint16_t rest_time; // 休息时间
|
||
uint16_t silent_time; // 静默时间
|
||
uint8_t ramp_up_time; // 缓进时间
|
||
uint8_t hold_time; // 保持时间
|
||
uint8_t ramp_down_time; // 缓出时间
|
||
uint8_t enable_ramp; // 启用渐进控制
|
||
} EMS_Config_TypeDef;
|
||
```
|
||
|
||
## 8. 调试与测试
|
||
|
||
### 8.1 调试输出
|
||
系统提供详细的调试输出,包括:
|
||
- 接收到的原始数据
|
||
- 解析后的参数值
|
||
- 配置更新状态
|
||
- 错误信息
|
||
|
||
### 8.2 测试用例
|
||
1. **停止指令测试**
|
||
```
|
||
数据包: 03 00 0d 00 00 32 64 00 88 13 e8 03 f4 01 01 03 01 b7 90
|
||
预期: 停止电刺激
|
||
```
|
||
|
||
2. **启动指令测试**
|
||
```
|
||
数据包: 03 00 0d 00 10 32 64 00 88 13 e8 03 f4 01 01 03 01 [CRC]
|
||
预期: 启动电刺激,频率100Hz,强度50
|
||
```
|