Electricity/FWLIB/source/ENS1_WAVEGEN.c

315 lines
12 KiB
C
Raw Permalink 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.

/*
*Copyright (C),2023 , NANOCHAP
*File name: ENS1_WAVEGEN.C
*Author:
*Version: V1.0
*Date: 2023-11-
*Description: 波形生成器电刺激功能实现
*Function List:
1 int wavegen_driverA_sine_test(CMSDK_WAVE_GEN_TypeDef *CMSDK_WAVEGEN_DRVA, uint16_t incount);
2 void wavegen_Stop(CMSDK_WAVE_GEN_TypeDef *CMSDK_WAVEGEN_DRVA);
3 void wavegen_Init(void);
4 void wavegen_Start(void);
History:
1.V1.0
Date:
Author:
Modification: 初版
*/
#include <stdio.h>
#include "ENS1_WAVEGEN.h"
#include "ENS1_CLOCK.h"
#include "ENS1_BOOST.h"
EMS_Config_TypeDef ems_config = {
.frequency = 100, // 100Hz
.duration = 1000, // 1000ms
.intensity = 128, // 中等强度
.rest_time = 100, // 100ms休息时间
.silent_time = 50, // 50ms静默时间
// 缓进缓出控制参数
.ramp_up_time = 2, // 缓进时间2秒
.hold_time = 6, // 保持时间6秒
.ramp_down_time = 2, // 缓出时间2秒·
.enable_ramp = 1 // 启用渐进控制
};
// 全局变量
EMS_Config_TypeDef g_ems_config = {0};
static volatile uint8_t g_ems_running = 0;
static volatile uint32_t g_ems_count = 0;
float waves_per_step = 0;
// 缓进缓出控制变量
static volatile float g_current_intensity = 0; // 当前强度
static volatile uint8_t g_ramp_phase = 0; // 渐进阶段0=缓进, 1=保持, 2=缓出
static volatile uint32_t g_wave_counter = 0; // 方波周期计数器
static volatile uint32_t g_ramp_step_counter = 0; // 缓进步进计数器
/* --------------------------------------------------------------- */
/* 波形生成器驱动器A正弦波测试 */
/* --------------------------------------------------------------- */
int wavegen_driverA_sine_test(CMSDK_WAVE_GEN_TypeDef *CMSDK_WAVEGEN_DRVA, uint16_t incount)
{
int return_val = 0;
int err_code = 0;
// printf("\n驱动器A正弦波测试\n");
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_REST_T_REG = 100; // 死区时间10ms //交替模式下死区时间失效即使CONFIG_REG使能了死区时间也无效
// CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_SILENT_T_REG = 200; //静默时间20ms
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_CLK_FREQ_REG = 0x00000020; // 32MHz ==PCLK
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_CLK_FREQ_REG = 32; // 32MHz ==PCLK //MHz为单位
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_HLF_WAVE_PRD_REG = 100; // 正半周期脉宽10ms有交替方波
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_NEG_HLF_WAVE_PRD_REG = 100; // 负半周期脉宽10ms无交替方波
#if 1 // 无需静默时间
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_CONFIG_REG = 0x00000050; // bit 0:rest enable 正半周期和负半周期中间的休息时间
// 1:negative enable 负半周期发生使能,如果不使能,则没有负半周期的波形(注意交替模式只会对正半周期起作用)
// 2: silent enable 负半周期结束后的静默时间
// 3: source B enable 负脉宽方向使能位1负脉宽在负半周期0负脉宽在正半周期
// 4: alternating the positive side ,正极交替产生包络
// 5: continue mode ,连续模式
// 6: multi-electrode ,多电极模式
#else // 需要静默时间
/*交替模式下config寄存器说明
正脉宽交替无负脉宽无死区时间无静默时间0x50 或 0x51 或 0x58 或 0x59
正脉宽交替无死区时间无负脉宽有静默时间0x54 或 0x55 或 0x5C 或 0x5D
正脉宽交替,无死区时间,负脉宽不交替但有波形,无静默时间 0x5A 或 0x5B
正脉宽交替无死区时间负脉宽不交替但有波形且波形在正脉宽上因为源B失能了无静默时间 0x52 或 0x53
正脉宽交替无死区时间负脉宽不交替但有波形且波形在正脉宽上因为源B失能了有静默时间 0x56 或 0x57
正脉宽交替,无死区时间,负脉宽不交替但有波形,有静默时间 0x5E 或 0x5F
*/
// CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_CONFIG_REG = 0x5F; //bit 0:rest enable 正半周期和负半周期中间的死区时间
// 1:negative enable 负半周期发生使能,如果不使能,则没有负半周期的波形
// 2: silent enable 负半周期结束后的静默时间
// 3: source B enable
// 4: alternating the positive side ,正极交替产生包络
// 5: continue mode ,连续模式
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_CONFIG_REG = 0x34; // 静默时间、交替模式和多电极使能 //6: multi-electrode ,多电极模式
#endif
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_ISEL_REG = 0x04; // 总电流 = 单元电流ISEL * WAVE_GEN_DRV_IN_WAVE_REG
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_REG = sine_data[i]; //正弦波数据数组,根据数组中的点描绘正半周期的波形
// CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_IN_WAVE_REG = saw_data[i]; //三角波数据
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_IN_WAVE_REG = incount; // 方波数据固定值0x80
}
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_ALT_LIM_REG = 3200; // 3200 需要设置一个正半周期下需要再生成多少个周期波形。设置10kHz=0.1ms=100us100us=A*(1/32us),所以A=3200。
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_ALT_SILENT_LIM_REG = 0; // 交替后静默的时钟数无死区时间设置。在这种情况下驱动器B连续交替。//包络下波形的静默时间
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_DELAY_LIM_REG = 0x00000000; // 延迟时钟数
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_NEG_SCALE_REG = 0x00000001; // 负半周期幅值倍乘系数如超过255则从0开始增长
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_NEG_OFFSET_REG = 0x00000000; // 负半周期幅值偏移量如超过255则从0开始增长
// 如正半周期幅值为250此处设置为10则负半周期幅值为5
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_INT_REG = 0x0; // 中断寄存器设置为0
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_CTRL_REG = 0x00000001; // 使能驱动器
/* 生成返回值 */
/*if (err_code != 0)
{
printf("\n错误 : 驱动器A测试失败\n");
return_val = 1;
err_code = 0;
}*/
return (return_val);
}
void wavegen_Stop(CMSDK_WAVE_GEN_TypeDef *CMSDK_WAVEGEN_DRVA)
{
CMSDK_WAVEGEN_DRVA->WAVE_GEN_DRV_ISEL_REG = 0; // 范围 0x00 - 0x07
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_REG = 0; // 最大值0xff
}
}
// 初始化波形生成器
void wavegen_Init(void)
{
// 设置MTP等待周期
CMSDK_MTPREG->MTP_CR = 0x00000002;
// 注意时钟配置已在ClockInit()中完成,这里不再重复配置
// 使用HSI作为主频 32MHz
// CMSDK_SYSCON->HSI_CTRL = (CMSDK_SYSCON->HSI_CTRL & ~CMSDK_SYSCON_HSI_FREQ_Msk) | (0x3 << CMSDK_SYSCON_HSI_FREQ_Pos); //HSI=32MHz
// 使能UART和WAVE_GEN外设时钟不覆盖TIMER0时钟
CMSDK_SYSCON->APB_CLKEN |= 0x1003 | 0x4000; // 使用|=而不是=,避免覆盖其他时钟使能
// 升压电压选择
//boost_voltage_select_11V();
//boost_voltage_select_15V();
//boost_voltage_select_26V();
//boost_voltage_select_45V();
boost_voltage_select_55V();
}
// 启动波形生成器
void wavegen_Start(void)
{
g_ems_running = 1;
// 初始化缓进缓出控制
if (g_ems_config.enable_ramp)
{
g_current_intensity = 0; // 从0开始
g_ramp_phase = 0; // 缓进阶段
g_wave_counter = 0; // 重置方波计数器
g_ramp_step_counter = 0; // 重置步进计数器
}
else
{
g_current_intensity = g_ems_config.intensity; // 直接使用设定强度
}
// 初始化硬件配置(只执行一次)
wavegen_driverA_sine_test(WAVE_GEN_DRVA_BLK0, g_current_intensity);
}
// 电刺激参数配置
void EMS_Configure(EMS_Config_TypeDef *config)
{
if (config != NULL)
{
g_ems_config = *config;
}
}
// 启动电刺激
void EMS_Start(void)
{
wavegen_Start();
}
// 停止电刺激
void EMS_Stop(void)
{
g_ems_running = 0;
g_current_intensity = 0; // 重置强度
g_ramp_phase = 0; // 重置渐进阶段
g_wave_counter = 0; // 重置方波计数器
g_ramp_step_counter = 0; // 重置步进计数器
wavegen_Stop(WAVE_GEN_DRVA_BLK0);
}
// 更新电刺激强度
void EMS_UpdateIntensity(uint16_t intensity)
{
g_ems_config.intensity = intensity;
}
// 缓进缓出处理函数(在电刺激处理中调用)
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;
// 计算当前应该达到的强度从最大值递减到0
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;
}
}
}
}
// 更新波形强度(不重新配置硬件)
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_REG = intensity;
}
}
// 电刺激主循环处理函数(在主循环中调用)
void EMS_Process(void)
{
if (g_ems_running)
{
EMS_Process_Ramp();
// 使用当前缓进缓出的强度
uint16_t current_intensity = g_current_intensity;
wavegen_UpdateIntensity(WAVE_GEN_DRVA_BLK0, current_intensity);
}
}