Electricity/UART电刺激控制系统技术文档.md

431 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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