second commit

This commit is contained in:
ZhangJinLong 2025-10-09 11:29:11 +08:00
parent 9ca4aad163
commit 0802617137
3 changed files with 444 additions and 14 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,430 @@
# 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
```

View File

@ -150,7 +150,7 @@ void UpdateEMS_ConfigFromUART(UART_EMS_Packet_t *packet)
.enable_ramp = 1 // 启用渐进控制 .enable_ramp = 1 // 启用渐进控制
}; };
// 打印接收到的参数数据
printf("0x%02X\n", packet->switch_type); printf("0x%02X\n", packet->switch_type);
printf("%d\n", packet->intensity); printf("%d\n", packet->intensity);
printf("%d\n", packet->frequency); printf("%d\n", packet->frequency);