# 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
   ```
