初始版本

This commit is contained in:
xiaozhengsheng
2025-08-19 09:49:41 +08:00
parent 10f1ddf1c1
commit 6df0f7d96e
2974 changed files with 1712873 additions and 54 deletions

201
app/Src/IoControl.c Normal file
View File

@@ -0,0 +1,201 @@
/********************************************************************
Copyright (c) 2021 Xiangyu Medical Co.Ltd. All rights reserved.
FileName : IoControl.c
Author : zhangdawei
Version : V1.0
Date :
Note :
History :
********************************************************************/
/* Includes ------------------------------------------------------*/
#include "IoControl.h"
#include "drv_uart.h"
#include "nrf_drv_gpiote.h"
/* Private define ------------------------------------------------*/
/* Private typedef -----------------------------------------------*/
/* Private constants ---------------------------------------------*/
/* Private variables ---------------------------------------------*/
uint8_t LastState = Null; //保存上一次的状态
/* Private function prototypes -----------------------------------*/
/* Public constants ----------------------------------------------*/
/* Public variables ----------------------------------------------*/
DeviceStateInfo_e DeviceState = POWER_CLOSE; //设备开关机状态
ChargingStateInfo_e ChargeState = Uncharged;
ChargingStateInfo_e ChargeLastState = Uncharged;
KeyStateInfo_t KeyStateInfo;
/********************************************************************
* name : void GpioInit(void)
* description : GPIO引脚初始化
* Input : void
* Output : void
* Return :
********************************************************************/
void GpioInit(void)
{
NRF_UICR->NFCPINS = 0;
nrf_gpio_cfg_output(KEY_POWER);
nrf_gpio_cfg_output(LED_YELLOW);
// nrf_gpio_cfg_output(CHARGE_LED);
nrf_gpio_cfg_output(STIM_RMS_RELAY_PIN);
nrf_gpio_cfg_output(STIM_RELAY_PIN);
nrf_gpio_cfg_output(SAMPLE_POWER_PIN);
// nrf_gpio_pin_clear(KEY_POWER);
nrf_gpio_pin_clear(LED_YELLOW);
// nrf_gpio_pin_clear(CHARGE_LED);
nrf_gpio_pin_clear(STIM_RMS_RELAY_PIN);
nrf_gpio_pin_clear(STIM_RELAY_PIN);
nrf_gpio_pin_clear(SAMPLE_POWER_PIN);
/////////
nrf_gpio_cfg_input(CHG_MANAGER_CHG, NRF_GPIO_PIN_NOPULL);//检测充电状态
}
/* 电刺激输出使能脚 */
void StimOutCtlOpen(void)
{
}
void StimOutCtlClose(void)
{
}
/* 能量释放控制 */
void StimReleaseOpen(void)
{
}
void StimReleaseClose(void)
{
}
// OK按键处理函数
void KEY_PWR_SWITICH_Handler(void)
{
}
//GPIOTE事件处理函回调函数事件回调函数里面可以获取pin编号和引脚状态变化
void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
if(pin == KEY_PWR_SWITICH)
{
KeyStateInfo.shineng = true;
KeyStateInfo.KeyPinNumber = KEY_PWR_SWITICH;
}
}
void EXIT_KEY_Init(void)
{
ret_code_t err_code;
nrf_gpio_cfg_input(KEY_PWR_SWITICH, NRF_GPIO_PIN_PULLUP);//检测开关机信号
}
/********************************************************************
* name : void open_acquisition_relay(void)
* description : 打开采样继电器
* Input : void
* Output : void
* Return :
********************************************************************/
void open_acquisition_relay(void)
{
nrf_gpio_pin_set(STIM_RMS_RELAY_PIN); //闭合继电器
nrf_gpio_pin_clear(STIM_RELAY_PIN); //打开刺激继电器
}
/********************************************************************
* name : void close_acquisition_relay(void)
* description : 关闭采样继电器
* Input : void
* Output : void
* Return :
********************************************************************/
void close_acquisition_relay(void)
{
nrf_gpio_pin_clear(STIM_RMS_RELAY_PIN);
nrf_gpio_pin_clear(STIM_RELAY_PIN);
}
/********************************************************************
* name : void open_stimulate_relay(void)
* description : 打开刺激继电器
* Input : void
* Output : void
* Return :
********************************************************************/
void open_stimulate_relay(void)
{
nrf_gpio_pin_clear(STIM_RMS_RELAY_PIN);
nrf_gpio_pin_set(STIM_RELAY_PIN);
}
/********************************************************************
* name : void close_stimulate_relay(void)
* description : 关闭刺激继电器
* Input : void
* Output : void
* Return :
********************************************************************/
void close_stimulate_relay(void)
{
nrf_gpio_pin_clear(STIM_RMS_RELAY_PIN);
nrf_gpio_pin_clear(STIM_RELAY_PIN);
}
/********************************************************************
* name : void StimStateInfoStructInit(SchemeData_t SchemeDataIn)
* description : 初始化通道信息描述结构体
* Input : void
* Output : void
* Return :
********************************************************************/
void StimStateInfoStructInit(SchemeData_t SchemeDataIn)
{
}
// 设备预存信息初始化ID :101 腹直肌分离
void PreStorageSchemeDataInit(void)
{
}
void KeyPinHandler(void)
{
if(KeyStateInfo.shineng == true)
{
switch(KeyStateInfo.KeyPinNumber)
{
case KEY_PWR_SWITICH:
{
KEY_PWR_SWITICH_Handler();
break;
}
}
KeyStateInfo.shineng = false;
}
}
/********************************************************************
* name : void VariableInit(void)
* description : 初始化变量
* Input : void
* Output : void
* Return :
********************************************************************/
void VariableInit(void)
{
}
/*************************** END OF FILE ***************************/

364
app/Src/drv_saadc.c Normal file
View File

@@ -0,0 +1,364 @@
/********************************************************************
Copyright (c) 2021 Xiangyu Medical Co.Ltd. All rights reserved.
FileName : drv_saadc.c
Author : zhangdawei
Version : V1.0
Date :
Note :
History :
********************************************************************/
/* Includes ------------------------------------------------------*/
#include "nrf_drv_ppi.h"
#include "app_timer.h"
#include "bsp_btn_ble.h"
#include "drv_saadc.h"
#include "timer.h"
#include "string.h"
#include "drv_uart.h"
#include "nrf_drv_ppi.h"
#include "IIR.h"
/* Private define ------------------------------------------------*/
/* Private typedef -----------------------------------------------*/
#define SAMPLES_BUFFER_LEN 10
/* Private constants ---------------------------------------------*/
//定义Timer1的驱动程序实例。驱动程序实例的ID对应Timer的ID如NRF_DRV_TIMER_INSTANCE(1)对应Timer1
const nrfx_timer_t TIMER_ADC = NRF_DRV_TIMER_INSTANCE(4);
static nrf_ppi_channel_t m_ppi_channel5;
const nrfx_timer_t TIMER3_RMS = NRFX_TIMER_INSTANCE(3); //读取rms值的定时器3
static nrf_saadc_value_t m_buffer_pool[2][SAMPLES_BUFFER_LEN];
/* Private variables ---------------------------------------------*/
/* Private function prototypes -----------------------------------*/
/* Public constants ----------------------------------------------*/
/* Public variables ----------------------------------------------*/
//电池电压回调函数,堵塞模式,不需要事件,定义空的事件回调函数
void saadc_battery_callback(nrfx_saadc_evt_t const * p_event){}
//刺激反馈电压,堵塞模式,不需要事件,定义空的事件回调函数
void saadc_stimulate_callback(nrfx_saadc_evt_t const * p_event){}
/********************************************************************
* name : void battery_adc_init(void)
* description : ADC初始化,刺激电压检测、电池电压检测、电极脱落电压检测
* Input : void
* Output : void
* Return :
********************************************************************/
void battery_adc_init(void)
{
ret_code_t err_code;
//初始化SAADC注册事件回调函数。空函数即可
err_code = nrf_drv_saadc_init(NULL, saadc_battery_callback);
APP_ERROR_CHECK(err_code);
//配置通道1输入引脚为AIN7电池电压
nrf_saadc_channel_config_t channeltwo_config =
NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);
err_code = nrfx_saadc_channel_init(SAADC_BATTERY_CHANNEL, &channeltwo_config);
APP_ERROR_CHECK(err_code);
// //配置通道2输入引脚为AIN4电极片脱落电压检测
// nrf_saadc_channel_config_t channelthree_config =
// NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);
// //初始化SAADC通道3
// err_code = nrfx_saadc_channel_init(SAADC_ELECTRODE_CHANNEL, &channelthree_config);
// APP_ERROR_CHECK(err_code);
}
// 如需更高精度非线性计算(示例)
float nonlinear_percentage(float voltage) {
// 三元锂电池的典型放电曲线拟合多项式
float p = (voltage - 3.4f) / 0.8f; // 归一化到[0,1]
return 100 * (1.0f - 0.2f*p - 0.8f*p*p);
}
// 锂电池电量计算函数
// 输入:当前电压(单位:伏特)
// 输出电量百分比0~100
int calculate_battery_percentage(float voltage)
{
// 定义电压范围
const float VOLTAGE_MIN = 3.4f; // 0%电量对应电压
const float VOLTAGE_MAX = 4.195f; // 100%电量对应电压
// 边界检查
if (voltage <= VOLTAGE_MIN) {
return 0;
} else if (voltage >= VOLTAGE_MAX) {
return 100;
}
// 线性插值计算百分比(可根据实际放电曲线修改算法)
float percentage = (voltage - VOLTAGE_MIN) / (VOLTAGE_MAX - VOLTAGE_MIN) * 100.0f;
// 四舍五入取整
return (int)(percentage + 0.5f);
}
/********************************************************************
* name : void CalculateBatteryPower(void)
* description : 计算电池电量0-100
* Input : void
* Output : void
* Return : void
********************************************************************/
void CalculateBatteryPower(void)
{
uint16_t Adctemp;
nrf_saadc_value_t Battery_Saadc_Value;
//启动一次ADC采样,存在Battery_Saadc_Value中
nrfx_saadc_sample_convert(SAADC_BATTERY_CHANNEL, &Battery_Saadc_Value);
Adctemp = ((Battery_Saadc_Value * 3600) / 16384);
static float lastBatteryPercentage = 100;
int temp = calculate_battery_percentage(Adctemp * 5.12557);
if(Uncharged == ChargeState) //如果没有处于充电状态,不允许电量上升,只能下降
{
if(temp < lastBatteryPercentage)
Battery_Percentage = temp;
}
else
{
Battery_Percentage = temp;
}
lastBatteryPercentage = Battery_Percentage;
}
short short_to_big_endian(short value)
{
uint8_t buf[2];
short resultShort;
buf[0] = (value >> 8) & 0xFF; // 高字节Big-Endian 第一个字节)
buf[1] = value & 0xFF; // 低字节Big-Endian 第二个字节)
memcpy(&resultShort,buf,2);
return resultShort;
}
/********************************************************************
* name : void rms_saadc_callback(nrfx_saadc_evt_t const * p_event)
* description : 肌电采集SAADC事件回调函数只有一个缓存填满后才会进入事件回调函数
* Input : nrfx_saadc_evt_t const * p_eventsaadc事件
* Output : void
* Return :
********************************************************************/
void rms_saadc_callback(nrfx_saadc_evt_t const * p_event)
{
static float32_t AdcFilter_g[AD_RAW_MAX] __attribute__((aligned(4)));
float32_t outFilter __attribute__((aligned(4)));
float32_t vol __attribute__((aligned(4)));
static emg_data_t emgData=
{
.emgCnt = 0
};
if(p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
ret_code_t err_code;
err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_BUFFER_LEN);
APP_ERROR_CHECK(err_code);
}
for(int i = 0; i < SAMPLES_BUFFER_LEN; i++)
{
if(p_event->data.done.p_buffer[i] < 0)
vol = 0;
else
{
vol = (p_event->data.done.p_buffer[i]*3600/16384) - 1545; //
}
bs_bp(&vol, &outFilter); //5.6us
if(emgData.emgCnt < AD_RAW_MAX) //防止溢出
AdcFilter_g[emgData.emgCnt] = outFilter;
emgData.emgCnt++;
if(emgData.emgCnt >= AD_RAW_MAX)
{
emgData.emgCnt=0;
float32_t temp __attribute__((aligned(4)));
arm_rms_f32(AdcFilter_g, AD_RAW_MAX, &temp);//6us
emgData.EmgValue = temp*0.8806 - 3.028;
if(emgData.EmgValue < 0)
emgData.EmgValue = 0;
// if(temp < 0)
// emgData.EmgValue = 0;
// else
// emgData.EmgValue = 0.6722 * temp + 3.7097;
uint16_t outfRms;
outfRms = (short)emgData.EmgValue;
outfRms = short_to_big_endian(outfRms);
ble_send_rms_data(outfRms);
}
//ble_send_rms_data(save_value[i]);
}
}
void timer3_rms_handler(nrf_timer_event_t event_type, void* p_context)
{
}
/********************************************************************
* name : void timer3_rms_init(void)
* description : 定时器1初始化
* Input : void
* Output : void
* Return :
********************************************************************/
void timer3_rms_init(void)
{
uint32_t err_code = NRF_SUCCESS;
uint32_t time_us = 500; //采样频率2kHz
uint32_t time_ticks;
nrfx_timer_config_t timer3_cfg = NRFX_TIMER_DEFAULT_CONFIG;
err_code = nrfx_timer_init(&TIMER3_RMS, &timer3_cfg, timer3_rms_handler);
APP_ERROR_CHECK(err_code);
time_ticks = nrfx_timer_us_to_ticks(&TIMER3_RMS, time_us);
nrfx_timer_extended_compare(
&TIMER3_RMS, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
}
/********************************************************************
* name : void timer3_rms_start(void)
* description : 开启定时器1
* Input : void
* Output : void
* Return :
********************************************************************/
void timer3_rms_start(void)
{
nrfx_timer_enable(&TIMER3_RMS);
}
/********************************************************************
* name : void timer3_rms_stop(void)
* description : 停止定时器1
* Input : void
* Output : void
* Return :
********************************************************************/
void timer3_rms_stop(void)
{
nrfx_timer_disable(&TIMER3_RMS);
}
/********************************************************************
* name : void PPIEegAdcInit(void)
* description : ADCPPI通道初始化
* Input : void
* Output : void
* Return :
********************************************************************/
void PPIEegAdcInit(void)
{
uint32_t err_code = NRF_SUCCESS;
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);
//分配PPI通道PPI通道的分配是由驱动函数完成的分配的通道号保存到my_ppi_channel1中
err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel5);
APP_ERROR_CHECK(err_code);
//分配PPI通道的EEP和TEP
err_code = nrf_drv_ppi_channel_assign(m_ppi_channel5,
nrf_drv_timer_event_address_get(&TIMER3_RMS, NRF_TIMER_EVENT_COMPARE0),
nrf_drv_saadc_sample_task_get());
APP_ERROR_CHECK(err_code);
//使能PPI通道
err_code = nrf_drv_ppi_channel_enable(m_ppi_channel5);
APP_ERROR_CHECK(err_code);
}
/********************************************************************
* name : void rms_saadc_init(void)
* description : 肌电采集saadc初始化
* Input : void
* Output : void
* Return :
********************************************************************/
void rms_saadc_init(void)
{
ret_code_t err_code;
nrf_drv_saadc_uninit(); //先反初始化
//配置通道0输入引脚为AIN3采集信号
nrf_saadc_channel_config_t channel_config =
NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
//初始化SAADC注册事件回调函数。
err_code = nrf_drv_saadc_init(NULL, rms_saadc_callback);
APP_ERROR_CHECK(err_code);
//初始化SAADC通道0
err_code = nrfx_saadc_channel_init(SAADC_RMS_SAMPLE_CHANNEL, &channel_config);
APP_ERROR_CHECK(err_code);
//配置缓存1将缓存1地址赋值给SAADC驱动程序中的控制块m_cb的一级缓存指针
err_code = nrfx_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_BUFFER_LEN);
APP_ERROR_CHECK(err_code);
//配置缓存2将缓存1地址赋值给SAADC驱动程序中的控制块m_cb的二级缓存指针
err_code = nrfx_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_BUFFER_LEN);
APP_ERROR_CHECK(err_code);
}
// 电极脱落检测
void ElectFallOff(void)
{
}
/********************************************************************
* name : void timer4_output_ctrl_handler(nrf_timer_event_t event_type, void* p_context)
* description : 变压器电压读取、变压器开关控制、脱落检测、刺激自调节
* Input : nrf_timer_event_t event_type定时器事件类型
void* p_context
* Output : void
* Return :
********************************************************************/
void timer1_output_ctrl_handler(nrf_timer_event_t event_type, void* p_context)
{
switch(event_type)
{
case NRF_TIMER_EVENT_COMPARE0:
//ElectFallOff();
break;
default:
break;
}
}
/********************************************************************
* name : void timer1_output_ctrl_init(void)
* description : 输出控制定时器初始化
* Input : void
* Output : void
* Return :
********************************************************************/
void timer1_output_ctrl_init(void)
{
ret_code_t err_code = NRF_SUCCESS;
uint32_t time_us = 50;
uint32_t time_ticks;
nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG;
err_code = nrfx_timer_init(&TIMER_ADC, &timer_cfg, timer1_output_ctrl_handler);
APP_ERROR_CHECK(err_code);
//定时时间(单位us)转换为ticks
time_ticks = nrfx_timer_us_to_ticks(&TIMER_ADC, time_us);
//设置定时器捕获/比较通道及该通道的比较值,使能通道的比较中断
nrfx_timer_extended_compare(
&TIMER_ADC, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
nrfx_timer_enable(&TIMER_ADC);
}
/*************************** END OF FILE ***************************/

817
app/Src/drv_uart.c Normal file
View File

@@ -0,0 +1,817 @@
/********************************************************************
Copyright (c) 2021 Xiangyu Medical Co.Ltd. All rights reserved.
FileName : drv_uart.c
Author : zhangdawei
Version : V1.0
Date :
Note :
History :
********************************************************************/
/* Includes ------------------------------------------------------*/
#include "drv_uart.h"
#include "pca10040.h"
#include "ble_nus.h"
#include "time.h"
#include "IoControl.h"
#include "nrf_drv_timer.h"
#include "fds.h"
/* Private define ------------------------------------------------*/
BLE_NUS_DEF(m_nus); //定义名称为m_nus的串口透传服务实例
/* Private typedef -----------------------------------------------*/
/* Private constants ---------------------------------------------*/
/* 接收到的方案信息 */
SchemeData_t SchemeData;
SchemeData_t PreStorageSchemeData;// 设备预存信息
uint16_t m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - 3; /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
/* Private variables ---------------------------------------------*/
//该变量用于保存连接句柄,初始值设置为无连接
uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;
/* 电池电量的原始值 */
nrf_saadc_value_t Battery_Saadc_Value = 10000;
/* 电池电压百分比 */
uint8_t Battery_Percentage = 100;
/* 肌电采集定时器初始化标志 */
uint8_t TimerEegAdcInit_Flag = 0;
/* 控制电流标志 */
uint8_t CurrentFlag = 0;
/* 设备的连接状态 */
ConnectStateInfo_e DeviceConnectState = DisconnectState;
ElectrodeStatusInfo_e ElectrodeStatusInfo = ElectrodeConnectted;
ElectrodeStatusInfo_e LastElectrodeStatusInfo = ElectrodeConnectted;
/* 适配器连接状态 */
AdapterStateInfo_e AdapterState = AdapterNotConnected;
AdapterStateInfo_e LastAdapterState = AdapterNotConnected;
/* MAC地址数组 */
uint8_t BLE_MAC[BLE_GAP_ADDR_LEN];
//定义FDS异步操作标志结构体
my_fds_info_t my_fds_info;
// 初始化参数信息
SchemePara_t SchemePara = {
.text = 0
};
uint16_t ccrvaluebuf[70] = {
23,25,27,29,31,33,35,37,39,41, //1-10
43,45,47,50,52,54,56,58,60,63, //11-20
65,67,69,71,74,76,78,80,82,85, //21-30
87,89,91,93,95,97,99,101,103,105, //31-40
108,111,114,117,120,123,126,129,132,134, //41-50
136,138,140,142,144,146,148,150,152,154, //51-60
155,156,158,160,162,164,167,170,172,174 //61-70
};
#define EEG_DATA_LENGTH ( 50 )
uint8_t aEEGData[EEG_DATA_LENGTH] = {
23,25,27,29,31,33,35,37,39,41,
43,45,47,50,52,54,56,58,60,63,
65,67,69,71,74,76,78,80,82,85,
87,89,91,93,95,97,99,101,103,105,
108,111,114,117,120,123,126,129,132,134
};
uint8_t eegmode = 0;
uint8_t eegflag = 0;
StimStateInfo_t ChannelStimStateInfo_t;
rms_data_t rmsData = {.frameHeader = FRAME_HEADER,
.frameLength = sizeof(rmsData) - 4, //减去帧头、帧长度、校验和、帧尾
.functionCode = D_EMG_DATA_REPORT,
.myNumber = 0x01,
.channel = 0x01,
//.rmsDataBuffer = {0},
.checkSum = 0,
.frameTail = FRAME_TAIL
};
/* Private function prototypes -----------------------------------*/
void StatusInquiry(ElectrodeStatusInfo_e Electrodestatus);
void StartStopCtrl(uint8_t StartStopValue);
void MACQuery(void);
/* Public constants ----------------------------------------------*/
/* Public variables ----------------------------------------------*/
/********************************************************************
* name : void SetFreqWidth(uint8_t* AnalysisDataBffer_t)
* description : 设置脉冲频率
* Input : AnalysisDataBffer_t接收到的数据缓冲区
* Output : void
* Return : void
********************************************************************/
void SetFreqWidth(uint8_t* AnalysisDataBffer_t)
{
}
/********************************************************************
* name : void SetRampTime(uint8_t* AnalysisDataBfferIn_t)
* description : 设置斜坡时间
* Input : AnalysisDataBffer_t接收到的数据缓冲区
* Output : void
* Return : void
********************************************************************/
void SetRampTime(uint8_t* AnalysisDataBffer_t)
{
}
/********************************************************************
* name : void SetStimPara(uint8_t* AnalysisDataBfferIn_t)
* description : 设置刺激参数
* Input : AnalysisDataBffer_t接收到的数据缓冲区
* Output : void
* Return : void
********************************************************************/
void SetStimPara(uint8_t* AnalysisDataBffer_t)
{
//开启采集模式
if(1 == AnalysisDataBffer_t[4])
{
eegmode = 1;
return;
}
}
/********************************************************************
* name : static void nus_data_handler(ble_nus_evt_t * p_evt)
* description : BLE串口透传事件回调函数
* Input : ble_nus_evt_t * p_evt发生的事件
* Output : void
* Return : void
********************************************************************/
static void nus_data_handler(ble_nus_evt_t * p_evt)
{
uint8_t FrameLength = 0;//帧长度
uint8_t FunctionCode = 0;//功能码
uint8_t CheckSum = 0;//校验和
uint8_t Sum = 0;//数据和
uint8_t SumCCR = 0;//CCR值
#define RX_BLE_DATA_LEN 100
uint8_t RecieveData[RX_BLE_DATA_LEN] = {0}; //接收数据帧的数组
if(p_evt->type == BLE_NUS_EVT_RX_DATA)
{
uint16_t Length = 0;
Length = p_evt->params.rx_data.length;
if(Length > RX_BLE_DATA_LEN)
{
NRF_LOG_ERROR("RecieveData length error");
return;
}
else
{
memcpy(RecieveData, p_evt->params.rx_data.p_data, Length);
}
/* 解析蓝牙收到的数据 */
if(0xAA == RecieveData[0])
{
FrameLength = RecieveData[1]; //帧长度
if(FrameLength > (RX_BLE_DATA_LEN - 4))
{
NRF_LOG_ERROR("RecieveData length error %d", FrameLength);
return;
}
else if(0x55 != RecieveData[FrameLength + 3]) //查找帧尾
{
NRF_LOG_ERROR("RecieveData end flag error");
return;
}
CheckSum = RecieveData[FrameLength + 2]; //校验和
//if(0x55 == RecieveData[FrameLength + 3]) //查找帧尾
{
/*校验数据包*/
for(uint8_t i = 0; i < FrameLength; i++)
{
Sum += RecieveData[i+2];
}
SumCCR = Sum & 0xff;
if(CheckSum == SumCCR)
{
FunctionCode = RecieveData[2];
/*模式、脉宽、频率、斜坡时间设置*/
if(STIM_PARA_CONTROL == FunctionCode)
{
SetStimPara(RecieveData); //设置参数
ble_nus_data_send(&m_nus, RecieveData, &Length, m_conn_handle);//将收到的数据回复回去
}
/*电流控制 (控制刺激强度)*/
else if(CURRENT_CONTROL == FunctionCode)
{
NRF_LOG_INFO("CURRENT_CONTROL");
// SetStandardCurrent(RecieveData); //设置电流
// CurrentFlag = 1; //设置电流的标志此标志为1时表示可以输出电流
ble_nus_data_send(&m_nus, RecieveData, &Length, m_conn_handle);//将收到的数据回复回去
}
/*刺激启停控制*/
else if(START_STOP_CONTROL == FunctionCode)
{
NRF_LOG_INFO("START_STOP_CONTROL");
// CurrentFlag = 0; //此标志清0此时开启电流的标志由通道模式和通道状态控制
uint8_t StartStopValue = CH_STOP; //初始状态为停止
StartStopValue = RecieveData[StartStopOffset]; //设置启停状态
StartStopCtrl(StartStopValue); //启停控制
ble_nus_data_send(&m_nus, RecieveData, &Length, m_conn_handle);//将收到的数据回复回去
}
/*触发采集开始*/
else if(TRIG_COLLECT_START_CONTROL == FunctionCode)
{
NRF_LOG_INFO("TRIG_COLLECT_START_CONTROL");
ble_nus_data_send(&m_nus, RecieveData, &Length, m_conn_handle);//将收到的数据回复回去
}
/*触发刺激开始*/
else if(TRIG_STIM_START_CONTROL == FunctionCode)
{
NRF_LOG_INFO("TRIG_STIM_START_CONTROL");
ble_nus_data_send(&m_nus, RecieveData, &Length, m_conn_handle);//将收到的数据回复回去
}
/*轮询0x8A*/
else if(STATUS_INQUIRY == FunctionCode)
{
StatusInquiry(ElectrodeStatusInfo);
NRF_LOG_INFO("STATUS_INQUIRY");
}
/* 运行轮询 */
else if(RUN_ROLL == FunctionCode)
{
RunRoll();
NRF_LOG_INFO("RUN_ROLL");
}
/* 版本查询 */
else if(VERSION_INQUIRY == FunctionCode)
{
CheckVersion();
NRF_LOG_INFO("VERSION_INQUIRY");
}
else if(SCHEME_QUERY == FunctionCode)
{
//SchemeQuery();
my_fds_info.read = true;
NRF_LOG_INFO("SCHEME_QUERY");
}
else if(MAC_QUERY == FunctionCode)
{
MACQuery();
}
}
}
}
/***********end***********/
}
}
/********************************************************************
* name : void service_nus_init(void)
* description : 串口透传服务初始化
* Input : void
* Output : void
* Return : void
********************************************************************/
void service_nus_init(void)
{
ret_code_t err_code;
ble_nus_init_t nus_init; //定义串口透传初始化结构体
/*------------------以下代码初始化串口透传服务-------------*/
memset(&nus_init, 0, sizeof(nus_init)); //清零串口透传服务初始化结构体
nus_init.data_handler = nus_data_handler; //设置串口透传事件回调函数
err_code = ble_nus_init(&m_nus, &nus_init); //初始化串口透传服务
APP_ERROR_CHECK(err_code);
/*------------------初始化串口透传服务-END-----------------*/
}
/********************************************************************
* name : void StartStopCtrl(uint8_t ucStartStopValueIn)
* description : 启、停控制处理函数
* Input : ucStartStopValueIn启、停控制值
ucChannelIn通道号
* Output : void
* Return : void
********************************************************************/
void StartStopCtrl(uint8_t StartStopValue)
{
switch(StartStopValue)
{
case CH_START: StartManage();
break;
case CH_PAUSE: PauseManage();
break;
case CH_CONTINUE: RecoverManage();
break;
case CH_STOP: StopManage();
break;
default: break;
}
}
/********************************************************************
* name : void StartManage(void)
* description : 开始处理函数
* Input : void
* Output : void
* Return : void
********************************************************************/
void StartManage(void)
{
if(eegmode == 1)
{
eegflag = 1;
}
}
/********************************************************************
* name : void PauseManage(void)
* description : 暂停处理函数
* Input : Channel通道号
* Output : void
* Return : void
********************************************************************/
void PauseManage(void)
{
if(eegmode == 1)
{
eegflag = 0;
}
// CHAChannelState_e = IdleState; //设置状态为空闲态空闲状态下pwm_flag置0
// ChannelStimStateInfo_t.ChannelWorkState = Pause;
// PwmDACStop();
// CloseOutput(); //关闭输出
// NRF_LOG_INFO("Pause_Stim");
}
/********************************************************************
* name : void CloseOutput(void)
* description : 将输出电流置0斜坡时间置0,关闭输出PWM
* Input : void
* Output : void
* Return : void
********************************************************************/
void CloseOutput(void)
{
if(eegmode == 1)
{
eegmode = 0;
eegflag = 0;
}
//ChannelStimStateInfo_t.ucCurrent = 0;
// ChannelStimStateInfo_t.Ramp_e = RampIdle;//斜坡状态为空闲态
// RampTime = 0; //斜坡时间清0
// SetCurrent(0); //设置输出电流为0
// PwmSubtractStop(); //关闭输出PWM
// PwmDACStop(); //停止充能PWM
//// GpioteInit();
}
/********************************************************************
* name : void RecoverManage(void)
* description : 继续处理函数
* Input : void
* Output : void
* Return : void
********************************************************************/
void RecoverManage(void)
{
if(eegmode == 1)
{
eegflag = 1;
}
}
/********************************************************************
* name : void StopManage(void)
* description : 停止处理函数
* Input : void
* Output : void
* Return : void
********************************************************************/
void StopManage(void)
{
}
/********************************************************************
* name : void SetStandardCurrent(uint8_t* AnalysisDataBfferIn_t)
* description : 设置标称电流值
* Input : AnalysisDataBfferIn_t接收到的数据缓冲区
* Output : void
* Return : void
********************************************************************/
void SetStandardCurrent(uint8_t* AnalysisDataBffer_t)
{
}
/********************************************************************
* name : void StatusInquiry(void)
* description : 状态轮询
* Input : void
* Output : void
* Return : void
********************************************************************/
void StatusInquiry(ElectrodeStatusInfo_e Electrodestatus)
{
uint8_t j = 2;
static uint8_t aTxBuffer[10] = {0};
uint32_t ulCrc = 0;
uint16_t Length = 10;
/* 帧头、帧尾*/
aTxBuffer[HeadOffset] = 0xAA;
aTxBuffer[DataLengthOffset] = 0x06;
aTxBuffer[FunctionCodeOffset] = STATUS_INQUIRY;
aTxBuffer[ChannelNumOffset] = 0x00;
aTxBuffer[ElectrodeStatusOffset] = 0x01;
aTxBuffer[StimStatusOffset] = ChannelStimStateInfo_t.Ramp_e;
aTxBuffer[StimCurrentOffset] = ChannelStimStateInfo_t.ucCurrent;
aTxBuffer[ResetOffset] = 0x00;
aTxBuffer[TailOffset] = 0x55;
/* 校验和 */
for(uint8_t i = 0; i < 6; i++)
{
ulCrc += aTxBuffer[j];
j++;
}
aTxBuffer[DataCrcOffset] = (uint8_t)ulCrc;
ble_nus_data_send(&m_nus, aTxBuffer, &Length, m_conn_handle);
}
/********************************************************************
* name : uint8_t caculate_sum_check(void)
* description : 运行校验和计算
* Input : typeStructHeader数据结构头部
typeStructLength数据结构长度
* Output : void
* Return : 计算结果
********************************************************************/
uint8_t caculate_sum_check(uint8_t *typeStructHeader, uint8_t typeStructLength)
{
uint8_t sum = 0;
uint8_t * typeStructCMD = &typeStructHeader[2];
for (uint8_t i = 0; i < typeStructLength; i++)
{
sum += typeStructCMD[i];
}
return sum&0xFF;
}
/// @brief 运行状态回复
reply_run_status_t replyRunStatus = {
.frameHeader = FRAME_HEADER,
.frameLength = sizeof(replyRunStatus) - 4, //减去帧头、帧长度、校验和、帧尾
.functionCode = RUN_ROLL,
.myNumber = 0x01,
.channel = 0x01,
.checkSum = 0,
.frameTail = FRAME_TAIL
};
/********************************************************************
* name : void RunRoll(void)
* description : 运行轮询
* Input : void
* Output : void
* Return : void
********************************************************************/
void RunRoll(void)
{
uint32_t ulCrc = 0;
uint16_t Length = sizeof(replyRunStatus);
replyRunStatus.ChargeState = ChargeState;
replyRunStatus.BatteryLevelA = Battery_Percentage;
replyRunStatus.checkSum = (uint8_t)caculate_sum_check((uint8_t *)&replyRunStatus, replyRunStatus.frameLength);
ble_nus_data_send(&m_nus, &replyRunStatus.frameHeader, &Length, m_conn_handle);
}
/********************************************************************
* name : void CheckVersion(void)
* description : 版本查询
* Input : void
* Output : void
* Return : void
********************************************************************/
check_version_t checkVersion = {
.frameHeader = FRAME_HEADER,
.frameLength = sizeof(checkVersion) - 4, //减去帧头、帧长度、校验和、帧尾
.functionCode = VERSION_INQUIRY,
.myNumber = 0x01,
.channel = 0x01,
.checkSum = 0,
.frameTail = FRAME_TAIL
}
void CheckVersion(void)
{
uint8_t j = 2;
static uint8_t aTxBuffer[21] = {0};
uint32_t ulCrc = 0;
uint16_t Length = 21;
/* 帧头、帧尾*/
aTxBuffer[HeadOffset] = 0xAA;
aTxBuffer[DataLengthOffset] = 0x11;
aTxBuffer[FunctionCodeOffset] = VERSION_INQUIRY;
aTxBuffer[ChannelNumOffset] = 0x00;
aTxBuffer[20] = 0x55;
/* 协议中规定先发送高字节,后发送低字节 */
aTxBuffer[4] = VersionDes[0];
aTxBuffer[5] = VersionDes[1];
aTxBuffer[6] = VersionDes[2];
aTxBuffer[7] = VersionDes[3];
aTxBuffer[8] = VersionDes[4];
aTxBuffer[9] = VersionDes[5];
aTxBuffer[10] = VersionDes[6];
aTxBuffer[11] = VersionDes[7];
aTxBuffer[12] = 0x00;
aTxBuffer[13] = 0x00;
aTxBuffer[14] = 0x00;
aTxBuffer[15] = 0x00;
aTxBuffer[16] = 0x00;
aTxBuffer[17] = 0x00;
aTxBuffer[18] = 0x00;
/* 校验和 */
for(uint8_t i = 0; i < 17; i++)
{
ulCrc += aTxBuffer[j];
j++;
}
aTxBuffer[19] = (uint8_t)ulCrc;
ble_nus_data_send(&m_nus, aTxBuffer, &Length, m_conn_handle);
}
/********************************************************************
* name : void EegDataSend(void)
* description : 发送肌电数据
* Input : void
* Output : void
* Return : void
********************************************************************/
void EegDataSend(void)
{
uint8_t j = 2;
static uint8_t aTxBuffer[EEG_DATA_LENGTH+6] = {0};
uint32_t ulCrc = 0;
uint16_t Length = EEG_DATA_LENGTH+6;
ret_code_t err_code;
/* 帧头、帧尾*/
aTxBuffer[HeadOffset] = 0xAA;
aTxBuffer[DataLengthOffset] = 0x34;
aTxBuffer[FunctionCodeOffset] = EEG_DATA;
aTxBuffer[ChannelNumOffset] = 0x00;
aTxBuffer[EEG_DATA_LENGTH+5] = 0x55;
/* 协议中规定先发送高字节,后发送低字节 */
memcpy(&aTxBuffer[4],aEEGData,EEG_DATA_LENGTH);
/* 校验和 */
for(uint8_t i = 0; i < EEG_DATA_LENGTH+2; i++)
{
ulCrc += aTxBuffer[j];
j++;
}
aTxBuffer[EEG_DATA_LENGTH+4] = (uint8_t)ulCrc;
ble_nus_data_send(&m_nus, aTxBuffer, &Length, m_conn_handle);
}
/********************************************************************
* name : void UpdateCurrent(uint8_t CurrentSend)
* description : 同步电流
* Input : void
* Output : void
* Return : void
********************************************************************/
void UpdateCurrent(uint8_t CurrentSend)
{
uint8_t j = 2;
uint8_t aTxBuffer[8] = {0};
uint32_t ulCrc = 0;
uint16_t Length = 8;
/* 帧头、帧尾*/
aTxBuffer[HeadOffset] = 0xAA;
aTxBuffer[DataLengthOffset] = 0x04;
aTxBuffer[FunctionCodeOffset] = CURRENT_CONTROL;
aTxBuffer[ChannelNumOffset] = 0x00;
aTxBuffer[7] = 0x55;
/* 协议中规定先发送高字节,后发送低字节 */
aTxBuffer[4] = CurrentSend;
aTxBuffer[5] = 0x01; // 01代表蓝牙设备发送
/* 校验和 */
for(uint8_t i = 0; i < 4; i++)
{
ulCrc += aTxBuffer[j];
j++;
}
aTxBuffer[6] = (uint8_t)ulCrc;
ble_nus_data_send(&m_nus, aTxBuffer, &Length, m_conn_handle);
}
void user_ble_or_uart_send(char * txBufferP, uint16_t Length)
{
ble_nus_data_send(&m_nus, txBufferP, &Length, m_conn_handle);
}
/********************************************************************
* name : void ble_send_rms_data(uint16_t rms_data)
* description : 发送肌电数据到主机
* Input : uint16_t rms_data肌电数据
* Output : void
* Return :
********************************************************************/
void ble_send_rms_data(uint16_t rms_data)
{
uint32_t TempSum = 0;
static uint8_t sendCnt = 0;
if(sendCnt < RMS_USER_DATA_LENGTH)
{
rmsData.rmsDataBuffer[sendCnt] = rms_data; //将rms_data存入rmsData的rmsDataBuffer数组中
sendCnt++;
if(sendCnt < RMS_USER_DATA_LENGTH)
return ; //如果发送次数小于RMS_USER_DATA_LENGTH则不发送
}
sendCnt = 0; //发送次数达到RMS_USER_DATA_LENGTH后重置发送次数
rmsData.myNumber = 1;
//rmsData.myNumber++;
uint8_t * sumCheckStartP = (uint8_t *)&rmsData.functionCode;
for(uint8_t i = 0; i < rmsData.frameLength; i++)
{
TempSum += sumCheckStartP[i];
}
rmsData.checkSum = TempSum & 0xff;
user_ble_or_uart_send((uint8_t *)&rmsData, sizeof(rmsData)); //145us
}
/********************************************************************
* name : void StateUpLoad(AdapterStateInfo_e AdapterStateTemp , ElectrodeStatusInfo_e ElectrodeStatusTemp)
* description : 电极片和适配器状态上传
* Input : AdapterStateInfo_e AdapterStateTemp , ElectrodeStatusInfo_e ElectrodeStatusTemp
* Output : void
* Return : void
********************************************************************/
void StateUpLoad(AdapterStateInfo_e AdapterStateTemp , ElectrodeStatusInfo_e ElectrodeStatusTemp)
{
uint8_t j = 2;
uint8_t aTxBuffer[8] = {0};
uint32_t ulCrc = 0;
uint16_t Length = 8;
AdapterStateInfo_e AdapterStateIn;
ElectrodeStatusInfo_e ElectrodeStatusIn;
AdapterStateIn = AdapterStateTemp;
ElectrodeStatusIn = ElectrodeStatusTemp;
/* 帧头、帧尾*/
aTxBuffer[HeadOffset] = 0xAA;
aTxBuffer[DataLengthOffset] = 0x04;
aTxBuffer[FunctionCodeOffset] = STATE_UPLOAD;
aTxBuffer[ChannelNumOffset] = 0x00;
aTxBuffer[7] = 0x55;
aTxBuffer[4] = AdapterStateIn; // 适配器连接状态
aTxBuffer[5] = ElectrodeStatusIn; // 电极片状态
if(ElectrodeStatusIn == ElectrodeFalloff)
{
ElectrodeStatusInfo = ElectrodeConnectted;
}
NRF_LOG_INFO("Electrodestatus = %d",ElectrodeStatusIn);
/* 校验和 */
for(uint8_t i = 0; i < 4; i++)
{
ulCrc += aTxBuffer[j];
j++;
}
aTxBuffer[6] = (uint8_t)ulCrc;
ble_nus_data_send(&m_nus, aTxBuffer, &Length, m_conn_handle);
}
/********************************************************************
* name : void UpdateControlStatus(uint8_t ControlStatus)
* description : 同步电流
* Input : void
* Output : void
* Return : void
********************************************************************/
void UpdateControlStatus(uint8_t ControlStatus)
{
uint8_t j = 2;
uint8_t aTxBuffer[8] = {0};
uint32_t ulCrc = 0;
uint16_t Length = 8;
/* 帧头、帧尾*/
aTxBuffer[HeadOffset] = 0xAA;
aTxBuffer[DataLengthOffset] = 0x04;
aTxBuffer[FunctionCodeOffset] = START_STOP_CONTROL;
aTxBuffer[ChannelNumOffset] = 0x00;
aTxBuffer[7] = 0x55;
/* 协议中规定先发送高字节,后发送低字节 */
aTxBuffer[4] = ControlStatus;
aTxBuffer[5] = 0x01; // 01代表蓝牙设备发送
/* 校验和 */
for(uint8_t i = 0; i < 4; i++)
{
ulCrc += aTxBuffer[j];
j++;
}
aTxBuffer[6] = (uint8_t)ulCrc;
ble_nus_data_send(&m_nus, aTxBuffer, &Length, m_conn_handle);
}
/********************************************************************
* name : void SchemeQuery(uint8_t idMSB,uint8_t idLSB)
* description : 方案查询
* Input : void
* Output : void
* Return : void
********************************************************************/
void SchemeQuery(uint8_t idMSB,uint8_t idLSB)
{
uint8_t j = 2;
static uint8_t aTxBuffer[8] = {0};
uint32_t ulCrc = 0;
uint16_t Length = 8;
/* 帧头、帧尾*/
aTxBuffer[HeadOffset] = 0xAA;
aTxBuffer[DataLengthOffset] = 0x04;
aTxBuffer[FunctionCodeOffset] = SCHEME_QUERY;
aTxBuffer[ChannelNumOffset] = 0x00;
aTxBuffer[7] = 0x55;
/* 协议中规定先发送高字节,后发送低字节 */
aTxBuffer[4] = idMSB;
aTxBuffer[5] = idLSB;
/* 校验和 */
for(uint8_t i = 0; i < 4; i++)
{
ulCrc += aTxBuffer[j];
j++;
}
aTxBuffer[6] = (uint8_t)ulCrc;
ble_nus_data_send(&m_nus, aTxBuffer, &Length, m_conn_handle);
}
/********************************************************************
* name : void MACQuery(void)
* description : MAC地址查询
* Input : void
* Output : void
* Return : void
********************************************************************/
void MACQuery(void)
{
uint8_t j = 2;
static uint8_t aTxBuffer[12] = {0};
uint32_t ulCrc = 0;
uint16_t Length = 12;
/* 帧头、帧尾*/
aTxBuffer[HeadOffset] = 0xAA;
aTxBuffer[DataLengthOffset] = 0x08;
aTxBuffer[FunctionCodeOffset] = MAC_QUERY;
aTxBuffer[ChannelNumOffset] = 0x00;
aTxBuffer[11] = 0x55;
aTxBuffer[4] = BLE_MAC[5];
aTxBuffer[5] = BLE_MAC[4];
aTxBuffer[6] = BLE_MAC[3];
aTxBuffer[7] = BLE_MAC[2];
aTxBuffer[8] = BLE_MAC[1];
aTxBuffer[9] = BLE_MAC[0];
/* 校验和 */
for(uint8_t i = 0; i < 8; i++)
{
ulCrc += aTxBuffer[j];
j++;
}
aTxBuffer[10] = (uint8_t)ulCrc;
ble_nus_data_send(&m_nus, aTxBuffer, &Length, m_conn_handle);
}
/********************************************************************
* name : void JudgeLedMode(void)
* description :
* Input : void
* Output : void
* Return : void
********************************************************************/
void JudgeLedMode(void)
{
}
void DisconnectControl(void)
{
StopManage();
}
/*************************** END OF FILE ***************************/

482
app/Src/timer.c Normal file
View File

@@ -0,0 +1,482 @@
/********************************************************************
Copyright (c) 2021 Xiangyu Medical Co.Ltd. All rights reserved.
FileName : timer.c
Author : zhangdawei
Version : V1.0
Date :
Note :
History :
********************************************************************/
/* Includes ------------------------------------------------------*/
#include "nrf_drv_pwm.h"
#include "drv_uart.h"
#include "IoControl.h"
#include "timer.h"
#include "nrf_delay.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_gpiote.h"
/* Private define ------------------------------------------------*/
/* 定义APP定时器 */
APP_TIMER_DEF(detect_button_100ms);
#define DETECT_BUTTON APP_TIMER_TICKS(100)
/* Private typedef -----------------------------------------------*/
//定义名称为m_pwm_add的驱动程序实例
static nrfx_pwm_t m_pwm_dac = NRFX_PWM_INSTANCE(1);
static nrfx_pwm_t m_pwm0 = NRFX_PWM_INSTANCE(0);
static nrfx_pwm_t m_pwm2 = NRFX_PWM_INSTANCE(2);
/* Private constants ---------------------------------------------*/
/* Private variables ---------------------------------------------*/
/* 呼吸灯占空比 */
uint16_t m_step = 150;
/* 存放RunLED占空比的数组 */
static nrf_pwm_values_common_t seq3_values[M_STEP*2];
//定义PWM序列该序列必须位于RAM中因此要定义为static类型
static nrf_pwm_values_common_t dac_values[] = {CYCLE_CALUE}; //14
static nrf_pwm_values_wave_form_t seq0_current_values[] =
{
10000 - 600,
10000 - 400,
10000 - 200,
10000 //100Hz
};
static nrf_pwm_values_wave_form_t seq2_current_values[] =
{
800 - 125,
800,
800,
800 //20khz
};
E_WORK_STATE eRmsState = E_RMS_STOP;
/* Private function prototypes -----------------------------------*/
/* Public constants ----------------------------------------------*/
/* Public variables ----------------------------------------------*/
/********************************************************************
* name : void acquisition_start(void)
* description : 开始采集肌电
* Input : void
* Output : void
* Return :
********************************************************************/
void acquisition_start(void)
{
eRmsState = E_RMS_START;
// rms_saadc_init();
nrf_gpio_pin_set(SAMPLE_POWER_PIN);
open_acquisition_relay();
timer3_rms_start();
}
/********************************************************************
* name : void acquisition_stop(void)
* description : 停止肌电采集
* Input : void
* Output : void
* Return :
********************************************************************/
void acquisition_stop(void)
{
timer3_rms_stop();
eRmsState = E_RMS_STOP;
nrf_gpio_pin_clear(SAMPLE_POWER_PIN);
close_acquisition_relay();
}
/********************************************************************
* name : void stimulate_start(void)
* description : 开始刺激
* Input : void
* Output : void
* Return :
********************************************************************/
void stimulate_start(void)
{
acquisition_stop(); //先停止肌电采集
// stimulate_stop(); //停止刺激,重新开始刺激
eRmsState = E_STIM_START;
open_stimulate_relay();
pwm0_play();
pwm2_play();
}
/********************************************************************
* name : void stimulate_stop(void)
* description : 停止刺激
* Input : void
* Output : void
* Return :
********************************************************************/
void stimulate_stop(void)
{
eRmsState = E_STIM_STOP;
close_stimulate_relay();
}
/********************************************************************
* name : static void detect_button(void)
* description : 开关机按键检测处理
* Input : void
* Output : void
* Return :
********************************************************************/
static void detect_button(void)
{
static uint8_t CountValue=0;
if((Bit_RESET == nrf_gpio_pin_read(KEY_PWR_SWITICH))&&((ChargeState == Uncharged))) //检测按键是否按下
{
CountValue++;
if(CountValue == 10)
{
if(POWER_CLOSE == DeviceState) //开机
{
DeviceState = POWER_OPEN;
nrf_gpio_pin_set(KEY_POWER); //锁定电源键给MCU供电
NRF_LOG_INFO("Open!");
StartAdv();
}
else if(POWER_OPEN == DeviceState) //关机
{
DeviceState = POWER_CLOSE;
acquisition_stop();
NRF_LOG_INFO("Close!");
nrf_gpio_pin_clear(KEY_POWER); //断电
}
}
}
else
{
CountValue = 0;
}
static uint16_t runBlinkCount = 0;
if(runBlinkCount == 0 && DeviceState == POWER_OPEN)
nrf_gpio_pin_set(LED_YELLOW);
else if(runBlinkCount == 1)
nrf_gpio_pin_clear(LED_YELLOW);
if(runBlinkCount++ > 8) //1S闪烁一次
{
runBlinkCount = 0;
}
}
/********************************************************************
* name : static void detect_charging_status(void)
* description : 充电状态检测处理
* Input : void
* Output : void
* Return :
********************************************************************/
static void detect_charging_status(void)
{
static uint8_t CountValue=0;
if((Bit_RESET == nrf_gpio_pin_read(CHG_MANAGER_CHG))) //检测按键是否按下
{
ChargeState = Charging;
}
else
{
ChargeState = Uncharged;
}
}
/********************************************************************
* name : static void Hundredms_handler(void * p_context)
* description : 检测按键是否长按函数100ms中断一次累计计数
* Input : void *p_context
* Output : void
* Return :
********************************************************************/
static void Hundredms_handler(void * p_context)
{
//防止编译器警告同时清晰地的表明p_context未使用而不是应用程序忽略了。如果应用
//程序需要使用p_context则不需要这行代码
UNUSED_PARAMETER(p_context);
/* 开机按键检测处理 */
detect_button();
/* 电池电量检测 */
CalculateBatteryPower();
/* 充电状态检测 */
detect_charging_status();
static uint16_t delay_open = 0;
if(POWER_OPEN == DeviceState && delay_open != 70 && delay_open++ >60 )
{
//acquisition_start();
stimulate_start();
delay_open = 70;
}
}
/********************************************************************
* name : void AppTimersInit(void)
* description : 初始化APP定时器模块、创建APP定时器
* Input : void
* Output : void
* Return :
********************************************************************/
void AppTimersInit(void)
{
ret_code_t err_code = app_timer_init();//初始化APP定时器模块
APP_ERROR_CHECK(err_code);
err_code = app_timer_create(&detect_button_100ms,
APP_TIMER_MODE_REPEATED,
Hundredms_handler);
APP_ERROR_CHECK(err_code);
}
/********************************************************************
* name : void ApplicationTimersStart(void)
* description : 启动已经创建的的APP定时器
* Input : void
* Output : void
* Return :
********************************************************************/
void ApplicationTimersStart(void)
{
ret_code_t err_code;
err_code = app_timer_start(detect_button_100ms, DETECT_BUTTON, NULL);
APP_ERROR_CHECK(err_code);
}
/********************************************************************
* name : void PwmDACInit(void)
* description : 控制DAC的pwm初始化
* Input : void
* Output : void
* Return :
********************************************************************/
void PwmDACInit(void)
{
//定义PWM初始化配置结构体并初始化参数
nrfx_pwm_config_t const config0 =
{
.output_pins =
{
PWM_DAC_GPIO, //通道0映射到P WM_DAC_GPIO空闲状态输出低电平
NRFX_PWM_PIN_NOT_USED , //通道1不使用
NRFX_PWM_PIN_NOT_USED , //通道2不使用
NRFX_PWM_PIN_NOT_USED //通道3不使用
},
.irq_priority = APP_IRQ_PRIORITY_LOWEST,//中断优先级
.base_clock = NRF_PWM_CLK_1MHz, //PWM时钟频率设置为1MHz
.count_mode = NRF_PWM_MODE_UP, //向上计数模式
.top_value = CYCLE_CALUE, //该值为周期值
.load_mode = NRF_PWM_LOAD_COMMON, //通用模式
.step_mode = NRF_PWM_STEP_AUTO //序列中的周期自动推进
};
APP_ERROR_CHECK(nrfx_pwm_init(&m_pwm_dac, &config0, NULL));//初始化PWM
}
/********************************************************************
* name : void PwmDACPlay(void)
* description : 播放充能PWM
* Input : void
* Output : void
* Return :
********************************************************************/
void PwmDACPlay(void)
{
//定义PWM播放序列播放序列包含了PWM序列的起始地址、大小和序列播放控制描述
nrf_pwm_sequence_t const seq =
{
.values.p_common = dac_values,//指向PWM序列
.length = NRF_PWM_VALUES_LENGTH(dac_values),//PWM序列中包含的周期个数
.repeats = 0, //序列中周期重复次数为0
.end_delay = 0 //序列后不插入延时
};
//启动PWM序列播放flags设置为NRFX_PWM_FLAG_LOOP序列播放完成后自动触发任务重新播放
(void)nrfx_pwm_simple_playback(&m_pwm_dac, &seq, 1, NRFX_PWM_FLAG_LOOP);
}
void SetPWMValues(uint16_t tempvalue)
{
*dac_values = CYCLE_CALUE - tempvalue;
}
/********************************************************************
* name : void PwmDACStop(void)
* description : 停止播放充能PWM
* Input : void
* Output : void
* Return :
********************************************************************/
void PwmDACStop(void)
{
nrfx_pwm_stop(&m_pwm_dac,1);
}
/********************************************************************
* name : void pwm0_common_init(void)
* description : 电流控制PWM初始化
* Input : void
* Output : void
* Return :
********************************************************************/
void pwm0_common_init(void)
{
//定义PWM初始化配置结构体并初始化参数
nrfx_pwm_config_t const config0 =
{
.output_pins =
{
BASE_WAVE_06_PIN,
BASE_WAVE_07_PIN,
BASE_WAVE_08_PIN,
NRFX_PWM_PIN_NOT_USED
},
.irq_priority = APP_IRQ_PRIORITY_LOWEST,//中断优先级
.base_clock = NRF_PWM_CLK_1MHz, //PWM时钟频率设置为16MHz
.count_mode = NRF_PWM_MODE_UP, //向上计数模式
.top_value = 0, //使用波形装载模式时,该值被忽略
.load_mode = NRF_PWM_LOAD_WAVE_FORM, //独立装载模式
.step_mode = NRF_PWM_STEP_AUTO //序列中的周期自动推进
};
//初始化PWM
APP_ERROR_CHECK(nrfx_pwm_init(&m_pwm0, &config0, NULL));
/////////////
//pwm0_play();
}
/********************************************************************
* name : void pwm0_play(void)
* description : 电流控制PWM开始播放
* Input : void
* Output : void
* Return :
********************************************************************/
void pwm0_play(void)
{
//定义PWM播放序列播放序列包含了PWM序列的起始地址、大小和序列播放控制描述
nrf_pwm_sequence_t const seq0 =
{
.values.p_wave_form = seq0_current_values,//指向PWM序列
.length = NRF_PWM_VALUES_LENGTH(seq0_current_values),//PWM序列中包含的周期个数
.repeats = 0, //序列中周期重复次数为0
.end_delay = 0 //序列后不插入延时
};
//启动PWM序列播放flags设置为NRFX_PWM_FLAG_LOOP序列播放完成后自动触发任务重新播放
//如改为NRFX_PWM_FLAG_STOP则播放结束后PWM停止
(void)nrfx_pwm_simple_playback(&m_pwm0, &seq0, 1,
NRFX_PWM_FLAG_LOOP);
}
void pwm0_stop(void)
{
nrfx_pwm_stop(&m_pwm0, 1);
}
/********************************************************************
* name : void pwm2_common_init(void)
* description : 电流控制PWM初始化
* Input : void
* Output : void
* Return :
********************************************************************/
void pwm2common_init(void)
{
//定义PWM初始化配置结构体并初始化参数
nrfx_pwm_config_t const config0 =
{
.output_pins =
{
BOOST_VOLTAGE_CONTROL_PIN,
NRFX_PWM_PIN_NOT_USED,
NRFX_PWM_PIN_NOT_USED,
NRFX_PWM_PIN_NOT_USED
},
.irq_priority = APP_IRQ_PRIORITY_LOWEST,//中断优先级
.base_clock = NRF_PWM_CLK_16MHz, //PWM时钟频率设置为16MHz
.count_mode = NRF_PWM_MODE_UP, //向上计数模式
.top_value = 0, //使用波形装载模式时,该值被忽略
.load_mode = NRF_PWM_LOAD_WAVE_FORM, //独立装载模式
.step_mode = NRF_PWM_STEP_AUTO //序列中的周期自动推进
};
//初始化PWM
APP_ERROR_CHECK(nrfx_pwm_init(&m_pwm2, &config0, NULL));
/////////////
//pwm2_play();
}
/********************************************************************
* name : void pwm2_play(void)
* description : 电流控制PWM开始播放
* Input : void
* Output : void
* Return :
********************************************************************/
void pwm2_play(void)
{
//定义PWM播放序列播放序列包含了PWM序列的起始地址、大小和序列播放控制描述
nrf_pwm_sequence_t const seq2 =
{
.values.p_wave_form = seq2_current_values,//指向PWM序列
.length = NRF_PWM_VALUES_LENGTH(seq2_current_values),//PWM序列中包含的周期个数
.repeats = 0, //序列中周期重复次数为0
.end_delay = 0 //序列后不插入延时
};
//启动PWM序列播放flags设置为NRFX_PWM_FLAG_LOOP序列播放完成后自动触发任务重新播放
//如改为NRFX_PWM_FLAG_STOP则播放结束后PWM停止
(void)nrfx_pwm_simple_playback(&m_pwm2, &seq2, 1,
NRFX_PWM_FLAG_LOOP);
}
void pwm2_stop(void)
{
nrfx_pwm_stop(&m_pwm2, 1);
}
/********************************************************************
* name : void GpioteInit(void)
* description : 刺激的任务GPIOTE初始化
* Input : void
* Output : void
* Return :
********************************************************************/
void GpioteInit(void)
{
}
/********************************************************************
* name : void PPIPwmInit(void)
* description : 刺激PWM的PPI初始化
* Input : void
* Output : void
* Return :
********************************************************************/
void PPIPwmInit(void)
{
}
/*************************** END OF FILE ***************************/

32
app/Src/user_config.c Normal file
View File

@@ -0,0 +1,32 @@
/********************************************************************
Copyright (c) 2025 Xiangyu Medical Co.Ltd. All rights reserved.
FileName : spi.c
Author : xiaozhengsheng
Version : V1.0
Date :
Note :
History :
********************************************************************/
/* Includes ------------------------------------------------------*/
#include "user_config.h"
//Log需要引用的头文件
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
version_t softVersion={
.major = 1,
.minor = 0,
.patch = 0, // 修订号 (.0)
.build = 0, // 构建号 (.0)
.testVersion = {"alpha1-1"} //内部测试版本正式发布需要填0alpha内部测试
};
char softWareVersion[SOFT_VERSION_MAX_LENGTH] = {0}; //软件版本号
void read_config_user_config(void)
{
snprintf(softWareVersion, SOFT_VERSION_MAX_LENGTH, "V%d.%d.%d.%d-%s", softVersion.major, softVersion.minor, softVersion.patch, softVersion.build, softVersion.testVersion);
NRF_LOG_INFO("Software Version: %s", softWareVersion);
NRF_LOG_INFO("product model: HL-PDJ-1");
}