初始版本
This commit is contained in:
108
app/Inc/IoControl.h
Normal file
108
app/Inc/IoControl.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/********************************************************************
|
||||
Copyright (c) 2021 Xiangyu Medical Co.,Ltd. All rights reserved.
|
||||
FileName : IoControl.h
|
||||
Author : zhangdawei
|
||||
Version : V1.0
|
||||
Date :
|
||||
Note :
|
||||
History :
|
||||
********************************************************************/
|
||||
#ifndef _IOCONTROL_H__
|
||||
#define _IOCONTROL_H__
|
||||
/* Includes ------------------------------------------------------*/
|
||||
#include "nrf52.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "timer.h"
|
||||
#include "drv_saadc.h"
|
||||
#include "drv_uart.h"
|
||||
#include "nrf_drv_gpiote.h"
|
||||
//Log需要引用的头文件
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_log_ctrl.h"
|
||||
#include "nrf_log_default_backends.h"
|
||||
#include "nrf_delay.h"
|
||||
/* Public define -------------------------------------------------*/
|
||||
#define MERGE(Msb,Lsb) ((Msb<<8)|Lsb)
|
||||
/* 按键检测 */
|
||||
#define KEY_PWR_SWITICH ( 16 )
|
||||
|
||||
/* 电源锁定 */
|
||||
#define KEY_POWER ( 13 )
|
||||
/* 指示灯 */
|
||||
#define LED_YELLOW ( 11 )
|
||||
#define LED_WHITE ( 12 )
|
||||
/* DAC 引脚*/
|
||||
#define PWM_DAC_GPIO ( 26 )
|
||||
|
||||
|
||||
/* 充电芯片引脚定义,低电平是充电中,高电平是充电完成或未充电 */
|
||||
#define CHG_MANAGER_EN ( 15 ) //充电管理芯片的EN引脚,内部200K下拉电阻。 高电平:禁用充电器 ,低电平(Low)或悬空(Floating):启用充电器
|
||||
#define CHG_MANAGER_PPR ( 23 ) //充电管理芯片的PPR引脚 ,开漏输出,外部上拉3.0V,低电平:输入充电电压正常,高电平:输入充电电压异常
|
||||
#define CHG_MANAGER_CHG ( 14 ) //充电指示引脚,低电平是充电中,充电结束为高电平
|
||||
|
||||
#define STIM_RMS_RELAY_PIN ( 27 ) // 肌电采集继电器控制引脚
|
||||
#define STIM_RELAY_PIN ( 28 ) //刺激继电器控制引脚
|
||||
|
||||
#define SAMPLE_POWER_PIN ( 20 ) //采样电源控制引脚
|
||||
|
||||
#define BOOST_DISCHARGE_PIN ( 18 ) //boost升压放电引脚
|
||||
|
||||
#define BASE_WAVE_06_PIN ( 6 ) //刺激基础波形控制引脚6
|
||||
#define BASE_WAVE_07_PIN ( 7 ) //刺激基础波形控制引脚7
|
||||
#define BASE_WAVE_08_PIN ( 8 ) //刺激基础波形控制引脚8
|
||||
|
||||
#define BOOST_VOLTAGE_CONTROL_PIN ( 25 ) //boost电压控制引脚
|
||||
|
||||
|
||||
|
||||
/* Public typedef ------------------------------------------------*/
|
||||
//设备开关机状态
|
||||
typedef enum
|
||||
{
|
||||
POWER_OPEN = 0,
|
||||
POWER_CLOSE
|
||||
}DeviceStateInfo_e;
|
||||
// 充电状态
|
||||
typedef enum
|
||||
{
|
||||
Uncharged = 0,
|
||||
Charging,
|
||||
ChargeComplete
|
||||
}ChargingStateInfo_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
Bit_RESET = 0,
|
||||
Bit_SET
|
||||
}BitAction;
|
||||
|
||||
typedef struct{
|
||||
nrf_drv_gpiote_pin_t KeyPinNumber;
|
||||
bool shineng;
|
||||
}KeyStateInfo_t;
|
||||
/* Public constants ----------------------------------------------*/
|
||||
/* Public variables ----------------------------------------------*/
|
||||
extern DeviceStateInfo_e DeviceState;
|
||||
extern ChargingStateInfo_e ChargeState;
|
||||
extern ChargingStateInfo_e ChargeLastState;
|
||||
/* Public function prototypes ------------------------------------*/
|
||||
void StartAdv(void);
|
||||
void StopAdv(void);
|
||||
void GpioInit(void);
|
||||
void EXIT_KEY_Init(void);
|
||||
void open_acquisition_relay(void);
|
||||
void close_acquisition_relay(void);
|
||||
void LedControl(void);
|
||||
void StimStateInfoStructInit(SchemeData_t SchemeDataIn);
|
||||
void VariableInit(void);
|
||||
void StimOutCtlOpen(void);
|
||||
void StimOutCtlClose(void);
|
||||
void StimReleaseOpen(void);
|
||||
void StimReleaseClose(void);
|
||||
void PreStorageSchemeDataInit(void);
|
||||
void KeyPinHandler(void);
|
||||
void close_stimulate_relay(void);
|
||||
void open_stimulate_relay(void);
|
||||
#endif
|
||||
|
||||
/*************************** END OF FILE ***************************/
|
||||
45
app/Inc/drv_saadc.h
Normal file
45
app/Inc/drv_saadc.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/********************************************************************
|
||||
Copyright (c) 2021 Xiangyu Medical Co.,Ltd. All rights reserved.
|
||||
FileName : drv_saadc.h
|
||||
Author : zhangdawei
|
||||
Version : V1.0
|
||||
Date :
|
||||
Note :
|
||||
History :
|
||||
********************************************************************/
|
||||
/* Includes ------------------------------------------------------*/
|
||||
#ifndef DRV_SAADC_H__
|
||||
#define DRV_SAADC_H__
|
||||
#include "nrf_drv_timer.h"
|
||||
#include "nrf_drv_saadc.h"
|
||||
#include "IoControl.h"
|
||||
/* Public define -------------------------------------------------*/
|
||||
#define SAADC_BATTERY_CHANNEL 1 // 电池电压检测通道
|
||||
#define SAADC_ELECTRODE_CHANNEL 2 // 电极片脱落电压
|
||||
#define SAADC_RMS_SAMPLE_CHANNEL 0 // 肌电采样通道
|
||||
|
||||
#define AD_RAW_MAX 50
|
||||
|
||||
/* Public typedef ------------------------------------------------*/
|
||||
typedef struct
|
||||
{
|
||||
//float AdRaw[AD_RAW_MAX+50];//原始值数组
|
||||
float EmgValue;//计算值
|
||||
unsigned char emgCnt;
|
||||
}emg_data_t;
|
||||
|
||||
/* Public constants ----------------------------------------------*/
|
||||
/* Public variables ----------------------------------------------*/
|
||||
extern uint8_t Battery_Percentage;
|
||||
/* Public function prototypes ------------------------------------*/
|
||||
void battery_adc_init(void);
|
||||
void timer1_output_ctrl_init(void);
|
||||
void rms_saadc_init(void);
|
||||
void PPIEegAdcInit(void);
|
||||
void timer3_rms_init(void);
|
||||
void timer3_rms_stop(void);
|
||||
void timer3_rms_start(void);
|
||||
void CalculateBatteryPower(void);
|
||||
#endif
|
||||
/*************************** END OF FILE ***************************/
|
||||
|
||||
241
app/Inc/drv_uart.h
Normal file
241
app/Inc/drv_uart.h
Normal file
@@ -0,0 +1,241 @@
|
||||
/********************************************************************
|
||||
Copyright (c) 2021 Xiangyu Medical Co.,Ltd. All rights reserved.
|
||||
FileName : drv_uart.h
|
||||
Author : zhangdawei
|
||||
Version : V1.0
|
||||
Date :
|
||||
Note :
|
||||
History :
|
||||
********************************************************************/
|
||||
/* Includes ------------------------------------------------------*/
|
||||
#ifndef DRV_UART_H__
|
||||
#define DRV_UART_H__
|
||||
#include "sdk_config.h"
|
||||
#include "ble_nus.h"
|
||||
#include "ble_link_ctx_manager.h"
|
||||
/* Public define -------------------------------------------------*/
|
||||
#define ONE_SECOND ( 1000000 ) /* 1s = 1000000us */
|
||||
/* 功能码定义 */
|
||||
#define RUN_ROLL ( 0x81 ) //运行轮询
|
||||
#define VERSION_INQUIRY ( 0x82 ) //版本查询
|
||||
#define STIM_PARA_CONTROL ( 0x83 ) //模式、脉宽、频率、斜坡时间设置
|
||||
#define START_STOP_CONTROL ( 0x84 ) //控制
|
||||
#define PRE_ADJUST ( 0x85 ) //预调节
|
||||
#define CURRENT_CONTROL ( 0x86 ) //电流设置
|
||||
#define EEG_DATA ( 0x87 ) //肌电数据上报
|
||||
#define TRIG_COLLECT_START_CONTROL ( 0x88 ) //触发采集开始
|
||||
#define TRIG_STIM_START_CONTROL ( 0x89 ) //触发刺激开始
|
||||
#define STATUS_INQUIRY ( 0x8A ) //轮询
|
||||
#define MAC_QUERY ( 0x8B ) //MAC地址查询
|
||||
#define STATE_UPLOAD ( 0x92 ) //状态上传(电极片状态和适配器状态)
|
||||
#define SCHEME_QUERY ( 0x91 ) //方案查询
|
||||
/* 刺激启停控制数据偏移定义 */
|
||||
#define StartStopOffset ( 4 )
|
||||
/* 刺激启停控制数据描述 */
|
||||
#define CH_STOP ( 0x00 )
|
||||
#define CH_START ( 0x01 )
|
||||
#define CH_PAUSE ( 0x02 )
|
||||
#define CH_CONTINUE ( 0x03 )
|
||||
/* 刺激参数数据偏移定义 */
|
||||
#define HeadOffset ( 0 )
|
||||
#define DataLengthOffset ( 1 )
|
||||
#define FunctionCodeOffset ( 2 )
|
||||
#define ChannelNumOffset ( 3 )
|
||||
#define SchemeCategoryOffset ( 4 )
|
||||
#define SchemeIDMSBOffset ( 5 )
|
||||
#define SchemeIDLSBOffset ( 6 )
|
||||
#define FreqMSBOffset ( 7 )
|
||||
#define FreqLSBOffset ( 8 )
|
||||
#define WidthMSBOffset ( 9 )
|
||||
#define WidthLSBOffset ( 10 )
|
||||
#define RampUpTimeLSBOffset ( 12 )
|
||||
#define RampUpTimeMSBOffset ( 11 )
|
||||
#define RampSmoothTimeLSBOffset ( 14 )
|
||||
#define RampSmoothTimeMSBOffset ( 13 )
|
||||
#define RampDownTimeLSBOffset ( 16 )
|
||||
#define RampDownTimeMSBOffset ( 15 )
|
||||
#define RampBreakTimeLSBOffset ( 18 )
|
||||
#define RampBreakTimeMSBOffset ( 17 )
|
||||
/* 状态轮询数据偏移定义 */
|
||||
#define ElectrodeStatusOffset ( 4 )
|
||||
#define StimStatusOffset ( 5 )
|
||||
#define StimCurrentOffset ( 6 )
|
||||
#define ResetOffset ( 7 )
|
||||
#define DataCrcOffset ( 8 )
|
||||
#define TailOffset ( 9 )
|
||||
/* 运行轮询数据偏移定义 */
|
||||
#define AdapterStatusOffset ( 5 )
|
||||
#define BatteryLevelOffset ( 4 )
|
||||
/* 刺激电流数据偏移定义 */
|
||||
#define PRE_ADJUST_OFFSET ( 4 )
|
||||
/* 预调节数据定义 */
|
||||
#define START_PRE_ADJUST ( 0x01 )
|
||||
#define STOP_PRE_ADJUST ( 0x00 )
|
||||
/* 方案存储属性定义 */
|
||||
#define TEMP_STORAGE ( 1 ) // 临时存储
|
||||
#define PERMANENT_STORAGE ( 2 ) // 永久存储
|
||||
#define FDS_DATA_LENGTH ( 20 ) // 存储空间长度
|
||||
|
||||
//头尾帧
|
||||
#define FRAME_HEADER (0xAA)
|
||||
#define FRAME_TAIL (0x55)
|
||||
|
||||
//功能码
|
||||
// Function Codes (Converted to UPPER_SNAKE_CASE)
|
||||
#define D_PARAMETER_SET (0x71) // Original: D_ParameterSet
|
||||
#define D_CHANNEL_CTRL (0x72) // Original: D_ChannelCtrl
|
||||
#define D_CURRENT_SET (0x73) // Original: D_CurrentSet
|
||||
#define D_EMG_DATA_REPORT (0x74) // Original: D_EmgDataReport
|
||||
#define D_DATA_MODE_SWITCH (0x75) // Original: D_DataModeSwitch
|
||||
#define D_PREINSTALL_CTRL (0x76) // Original: D_PreinstallCtrl
|
||||
#define D_TRIGGER_MODE_CTRL (0x77) // Original: D_TriggerModeCtrl
|
||||
#define D_POLL_CMD (0x78) // Original: D_PollCmd
|
||||
#define D_SLICE_FALL_DETECT_SWITCH (0x79) // Original: D_SliceFallDetectSwitch
|
||||
#define D_TURN_OFF_CMD (0x7A) // Original: D_TurnOffCmd
|
||||
#define D_BLE_SCAN_SWITCH (0x7B) // Original: D_BleScanSwitch
|
||||
#define D_MAC_ADDR_REPORT (0x7C) // Original: D_MacAddrReport
|
||||
#define D_BLE_CONNECT_CMD (0x7D) // Original: D_BleConnectCmd
|
||||
|
||||
/* Public typedef ------------------------------------------------*/
|
||||
/* 方案信息结构体 */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t StorageMode; //存储模式
|
||||
uint8_t SchemeIDMSB; //方案ID
|
||||
uint8_t SchemeIDLSB;
|
||||
uint8_t FreqMSB; //频率
|
||||
uint8_t FreqLSB;
|
||||
uint8_t WidthMSB; //脉宽
|
||||
uint8_t WidthLSB;
|
||||
uint8_t RampUpTimeMSB; //波升
|
||||
uint8_t RampUpTimeLSB;
|
||||
uint8_t RampSmoothTimeMSB;//保持
|
||||
uint8_t RampSmoothTimeLSB;
|
||||
uint8_t RampDownTimeMSB; //波降
|
||||
uint8_t RampDownTimeLSB;
|
||||
uint8_t RampBreakTimeMSB; //休息
|
||||
uint8_t RampBreakTimeLSB;
|
||||
}SchemeData_t;
|
||||
|
||||
#define RMS_USER_DATA_LENGTH 4//110///4 //用户数据长度
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t frameHeader; //帧头
|
||||
uint8_t frameLength; //帧长度
|
||||
uint8_t functionCode; //功能码
|
||||
uint8_t myNumber; //编号
|
||||
uint8_t channel; //通道号
|
||||
uint16_t rmsDataBuffer[RMS_USER_DATA_LENGTH]; //数据内容
|
||||
uint8_t checkSum; //校验和
|
||||
uint8_t frameTail; //帧尾
|
||||
} rms_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t frameHeader; //帧头
|
||||
uint8_t frameLength; //帧长度
|
||||
uint8_t functionCode; //功能码
|
||||
uint8_t channel; //通道号
|
||||
uint8_t ChargeState; //充电状态
|
||||
uint8_t BatteryLevelA; //A 电池电量
|
||||
uint8_t BatteryLevelB; //B 电池电量
|
||||
uint8_t BatteryLevelC; //C 电池电量
|
||||
|
||||
uint8_t reserve[5]; //保留字段
|
||||
|
||||
uint8_t checkSum; //校验和
|
||||
uint8_t frameTail; //帧尾
|
||||
} reply_run_status_t;
|
||||
|
||||
#define MAX_VERSION_LEN 15
|
||||
typedef struct
|
||||
{
|
||||
uint8_t frameHeader; //帧头
|
||||
uint8_t frameLength; //帧长度
|
||||
uint8_t functionCode; //功能码
|
||||
uint8_t channel; //通道号
|
||||
uint8_t VersionDes[MAX_VERSION_LEN]; //版本描述
|
||||
|
||||
uint8_t checkSum; //校验和
|
||||
uint8_t frameTail; //帧尾
|
||||
} check_version_t;
|
||||
|
||||
|
||||
#pragma pack()
|
||||
|
||||
|
||||
//设备连接状态
|
||||
typedef enum
|
||||
{
|
||||
DisconnectState = 0,
|
||||
ConnectState
|
||||
}ConnectStateInfo_e;
|
||||
// 电极片状态
|
||||
typedef enum
|
||||
{
|
||||
ElectrodeFalloff,
|
||||
ElectrodeConnectted
|
||||
}ElectrodeStatusInfo_e;
|
||||
// 适配器连接状态
|
||||
typedef enum
|
||||
{
|
||||
AdapterNotConnected = 0,
|
||||
AdapterConnected
|
||||
}AdapterStateInfo_e;
|
||||
//FDS异步操作标志结构体
|
||||
typedef struct
|
||||
{
|
||||
bool scheme_update; //scheme_record记录更新标志
|
||||
bool read; //读记录标志
|
||||
bool gc; //碎片收集标志
|
||||
bool busy; //FDS忙标志
|
||||
}my_fds_info_t;
|
||||
|
||||
//记录scheme的id和内容
|
||||
typedef struct
|
||||
{
|
||||
uint8_t text[FDS_DATA_LENGTH];
|
||||
}__attribute__((aligned(4)))SchemePara_t;
|
||||
/* Public constants ----------------------------------------------*/
|
||||
/* Public variables ----------------------------------------------*/
|
||||
extern uint16_t m_conn_handle;
|
||||
extern uint16_t m_ble_nus_max_data_len;
|
||||
extern uint8_t CurrentFlag;
|
||||
extern ConnectStateInfo_e DeviceConnectState;
|
||||
extern ElectrodeStatusInfo_e ElectrodeStatusInfo;
|
||||
extern my_fds_info_t my_fds_info;
|
||||
extern SchemePara_t SchemePara;
|
||||
extern SchemeData_t SchemeData;
|
||||
extern uint8_t BLE_MAC[BLE_GAP_ADDR_LEN];
|
||||
extern AdapterStateInfo_e AdapterState;
|
||||
extern AdapterStateInfo_e LastAdapterState;
|
||||
extern SchemeData_t PreStorageSchemeData;
|
||||
extern ElectrodeStatusInfo_e LastElectrodeStatusInfo;
|
||||
extern uint16_t ccrvaluebuf[70];
|
||||
extern uint8_t eegflag;
|
||||
/* Public function prototypes ------------------------------------*/
|
||||
void service_nus_init(void);
|
||||
void StartManage(void);
|
||||
void PauseManage(void);
|
||||
void RecoverManage(void);
|
||||
void StopManage(void);
|
||||
void CloseOutput(void);
|
||||
void SetStandardCurrent(uint8_t* AnalysisDataBfferIn_t);
|
||||
void RunRoll(void);
|
||||
void CheckVersion(void);
|
||||
void UpdateCurrent(uint8_t CurrentSend);
|
||||
void JudgeLedMode(void);
|
||||
void DisconnectControl(void);
|
||||
void SchemeQuery(uint8_t idMSB,uint8_t idLSB);
|
||||
void UpdateControlStatus(uint8_t ControlStatus);
|
||||
void StateUpLoad(AdapterStateInfo_e AdapterStateTemp , ElectrodeStatusInfo_e ElectrodeStatusTemp);
|
||||
void EegDataSend(void);
|
||||
void user_ble_or_uart_send(char * txBufferP, uint16_t Length);
|
||||
|
||||
void ble_send_rms_data(uint16_t rms_data);
|
||||
#endif
|
||||
/*************************** END OF FILE ***************************/
|
||||
|
||||
|
||||
117
app/Inc/timer.h
Normal file
117
app/Inc/timer.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/********************************************************************
|
||||
Copyright (c) 2021 Xiangyu Medical Co.,Ltd. All rights reserved.
|
||||
FileName : timer.h
|
||||
Author : zhangdawei
|
||||
Version : V1.0
|
||||
Date :
|
||||
Note :
|
||||
History :
|
||||
********************************************************************/
|
||||
#ifndef TIMER_H__
|
||||
#define TIMER_H__
|
||||
/* Includes ------------------------------------------------------*/
|
||||
#include "app_timer.h"
|
||||
/* Public define -------------------------------------------------*/
|
||||
#define RAMP_TIM_TIME ( 1000 )
|
||||
/* 呼吸灯的步长 */
|
||||
#define M_STEP ( 100 )
|
||||
/* 频率对应的周期值 */
|
||||
#define CYCLE_CALUE ( 1000 )
|
||||
#define SIQU ( 200 )
|
||||
/* Public typedef ------------------------------------------------*/
|
||||
/*通道状态*/
|
||||
typedef enum
|
||||
{
|
||||
IdleState = 0, // 空闲态
|
||||
StimState, // 刺激态
|
||||
StimAdjState // 刺激调节态
|
||||
}ChannelState_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
E_RMS_STOP = 0x00,
|
||||
E_RMS_START = 0x01,
|
||||
E_RMS_PAUSE = 0x02,
|
||||
E_RMS_CONTINUE = 0x03,
|
||||
|
||||
E_STIM_STOP = 0x04,
|
||||
E_STIM_START = 0x05,
|
||||
E_STIM_PAUSE = 0x06,
|
||||
E_STIM_CONTINUE = 0x07
|
||||
|
||||
}E_WORK_STATE;
|
||||
|
||||
/* LED状态 */
|
||||
typedef enum
|
||||
{
|
||||
Disconnect_Highbattery = 0, //未连接有电
|
||||
Disconnect_Lowbattery, // 未连接低电
|
||||
Connect_Lowbattery, // 连接低电
|
||||
Connect_Highbattery, // 连接有电
|
||||
Null
|
||||
}LedModeInfo_e;
|
||||
/* 斜坡状态 */
|
||||
typedef enum
|
||||
{
|
||||
RampIdle = 0,
|
||||
RampUp,
|
||||
RampDown,
|
||||
RampSmooth,
|
||||
RampBreak
|
||||
}RampState_e;
|
||||
/* 通道工作状态 */
|
||||
typedef enum
|
||||
{
|
||||
Close,
|
||||
Open,
|
||||
Pause,
|
||||
Continue,
|
||||
Ready
|
||||
}ChannelWorkState_e;
|
||||
/* 刺激参数信息结构体 */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t usRampUpTime; // 上坡时间 单位为ms
|
||||
uint16_t usRampDownTime; // 下坡时间
|
||||
uint16_t usSmoothTime; // 平坡时间
|
||||
uint16_t usBreakTime; // 休息时间
|
||||
uint16_t usFreqBuf; // 频率
|
||||
ChannelWorkState_e ChannelWorkState; // 通道当前工作状态
|
||||
uint32_t usWidth; // 脉冲宽度
|
||||
uint32_t usCycle; // 脉冲周期
|
||||
RampState_e Ramp_e; // 斜坡状态
|
||||
uint8_t ucCurrent; // 标称电流值
|
||||
uint16_t usCcrValue; // 标称的CCR值
|
||||
}StimStateInfo_t;
|
||||
/* Public constants ----------------------------------------------*/
|
||||
/* Public variables ----------------------------------------------*/
|
||||
extern StimStateInfo_t ChannelStimStateInfo_t;
|
||||
|
||||
extern uint8_t PwmLedInit_Flag;
|
||||
extern bool LongPressEvent;
|
||||
extern bool BeepBeepOpenFlag;
|
||||
/* Public function prototypes ------------------------------------*/
|
||||
void AppTimersInit(void);
|
||||
void ApplicationTimersStart(void);
|
||||
void PwmDACInit(void);
|
||||
|
||||
void PwmDACStop(void);
|
||||
void PwmLedUnInit(void);
|
||||
|
||||
void PwmSubtractStop(void);
|
||||
void GpioteInit(void);
|
||||
void PPIPwmInit(void);
|
||||
void SetCurrent(uint16_t CcrIn);
|
||||
void OutputCurrentCtrl(void);
|
||||
void BlinkTwice(void);
|
||||
void pwm0_common_init(void);
|
||||
void SetPWMValues(uint16_t tempvalue);
|
||||
void pwm2common_init(void);
|
||||
void PwmDACPlay(void);
|
||||
void pwm2_play(void);
|
||||
void pwm0_play(void);
|
||||
#endif
|
||||
/*************************** END OF FILE ***************************/
|
||||
|
||||
|
||||
|
||||
31
app/Inc/user_config.h
Normal file
31
app/Inc/user_config.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/********************************************************************
|
||||
Copyright (c) 2021 Xiangyu Medical Co.,Ltd. All rights reserved.
|
||||
FileName :
|
||||
Author : xiaozhengsheng
|
||||
Version : V1.0
|
||||
Date :
|
||||
Note :
|
||||
History :
|
||||
********************************************************************/
|
||||
#ifndef _USER_CONFIG_H_
|
||||
#define _USER_CONFIG_H_
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SOFT_VERSION_MAX_LENGTH 50
|
||||
typedef struct {
|
||||
uint8_t major; // 主版本号 (V1)
|
||||
uint8_t minor; // 次版本号 (.0)
|
||||
uint8_t patch; // 修订号 (.0)
|
||||
uint8_t build; // 构建号 (.0)
|
||||
uint8_t testVersion[30];
|
||||
} version_t;
|
||||
extern char softWareVersion[SOFT_VERSION_MAX_LENGTH];
|
||||
|
||||
void read_config_user_config(void);
|
||||
|
||||
#endif
|
||||
|
||||
/*************************** END OF FILE ***************************/
|
||||
|
||||
201
app/Src/IoControl.c
Normal file
201
app/Src/IoControl.c
Normal 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
364
app/Src/drv_saadc.c
Normal 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_event:saadc事件
|
||||
* 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
817
app/Src/drv_uart.c
Normal 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
482
app/Src/timer.c
Normal 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
32
app/Src/user_config.c
Normal 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"} //内部测试版本,正式发布需要填0,alpha内部测试
|
||||
};
|
||||
|
||||
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");
|
||||
}
|
||||
883
app/main.c
Normal file
883
app/main.c
Normal file
@@ -0,0 +1,883 @@
|
||||
/****************************************Copyright (c)************************************************
|
||||
** [翔宇医疗]
|
||||
**--------------File Info-----------------------------------------------------------------------------
|
||||
** File name : main.c
|
||||
** Last modified Date:
|
||||
** Last Version :
|
||||
** Descriptions : 使用的SDK版本-SDK_17.0.2
|
||||
**----------------------------------------------------------------------------------------------------
|
||||
** Created by :
|
||||
** Created date :
|
||||
** Version : 1.0
|
||||
** Descriptions : 2021.4.6:添加配对管理器功能,在配对管理处理事件中添加PM_EVT_CONN_SEC_CONFIG_REQ,修改参数,
|
||||
实现取消配对后依然可以再次连接
|
||||
2021.4.7:添加广播3分钟后芯片休眠操作,广播间隔调整为187.5ms
|
||||
在BLE事件处理函数中添加pm_handler_secure_on_connection函数,实现连接成功后就绑定
|
||||
2021.4.9:在GATT初始化中加入nrf_ble_gatt_att_mtu_periph_set()函数设置默认MTU大小
|
||||
2021.4.12:在主函数中加入PWM初始化函数以及在定时器中调用PWM开始播放函数
|
||||
2021.5.12:将最大连接间隔改为300ms,改善了在连接过程中交换MTU不成功的情况
|
||||
**---------------------------------------------------------------------------------------------------*/
|
||||
//引用的C库头文件
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
//APP定时器需要引用的头文件
|
||||
#include "bsp_btn_ble.h"
|
||||
//电源管理需要引用的头文件
|
||||
#include "nrf_pwr_mgmt.h"
|
||||
//SoftDevice handler configuration需要引用的头文件
|
||||
#include "nrf_sdh.h"
|
||||
#include "nrf_sdh_soc.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
//排序写入模块需要引用的头文件
|
||||
#include "nrf_ble_qwr.h"
|
||||
//GATT需要引用的头文件
|
||||
#include "nrf_ble_gatt.h"
|
||||
//连接参数协商需要引用的头文件
|
||||
#include "ble_conn_params.h"
|
||||
//广播需要引用的头文件
|
||||
#include "ble_advdata.h"
|
||||
#include "ble_advertising.h"
|
||||
//串口透传需要引用的头文件
|
||||
#include "drv_uart.h"
|
||||
//引用FDS头文件
|
||||
#include "fds.h"
|
||||
//配对管理器包含头文件
|
||||
#include "peer_manager.h"
|
||||
#include "peer_manager_handler.h"
|
||||
//WDT头文件
|
||||
#include "nrfx_wdt.h"
|
||||
#include "nrf_drv_clock.h"
|
||||
#include "IoControl.h"
|
||||
#include "IIR.h"
|
||||
/***********************************************/
|
||||
#define DEVICE_NAME "HL-PDJ-A" // 设备名称字符串
|
||||
#define UARTS_SERVICE_UUID_TYPE BLE_UUID_TYPE_BLE // 串口透传服务UUID类型:厂商自定义UUID
|
||||
#define MIN_CONN_INTERVAL MSEC_TO_UNITS(20, UNIT_1_25_MS) // 最小连接间隔 (0.1 秒)
|
||||
#define MAX_CONN_INTERVAL MSEC_TO_UNITS(20, UNIT_1_25_MS) // 最大连接间隔 (0.2 秒)
|
||||
#define SLAVE_LATENCY 0 // 从机延迟
|
||||
#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) // 监督超时(4 秒)
|
||||
#define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000) // 定义首次调用sd_ble_gap_conn_param_update()函数更新连接参数延迟时间(5秒)
|
||||
#define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(30000) // 定义每次调用sd_ble_gap_conn_param_update()函数更新连接参数的间隔时间(30秒)
|
||||
#define MAX_CONN_PARAMS_UPDATE_COUNT 3 // 定义放弃连接参数协商前尝试连接参数协商的最大次数(3次)
|
||||
|
||||
#define APP_ADV_INTERVAL 160 // 广播间隔 (100 ms),单位0.625 ms
|
||||
#define APP_ADV_DURATION 0 // 广播持续时间,单位:10ms。设置为0表示不超时
|
||||
|
||||
#define SEC_PARAM_BOND 1 //是否支持绑定,1:支持,0:不支持
|
||||
#define SEC_PARAM_MITM 0 //是否支持MITM保护,1:支持,0:不支持
|
||||
#define SEC_PARAM_LESC 0 //是否使用安全连接配对(LESC),1:使用LESC,0:使用传统配对
|
||||
#define SEC_PARAM_KEYPRESS 0 //是否生成按键通知,1:生成,0:不生成
|
||||
#define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE //IO能力:无输入/输出能力
|
||||
#define SEC_PARAM_OOB 0 //是否支持OOB,1:支持,0:不支持
|
||||
#define SEC_PARAM_MIN_KEY_SIZE 7 //最小加密密钥大小
|
||||
#define SEC_PARAM_MAX_KEY_SIZE 16 //最大加密密钥大小
|
||||
|
||||
#define APP_BLE_OBSERVER_PRIO 3 //应用程序BLE事件监视者优先级,应用程序不能修改该数值
|
||||
#define APP_BLE_CONN_CFG_TAG 1 //SoftDevice BLE配置标志
|
||||
|
||||
//用于stack dump的错误代码,可以用于栈回退时确定堆栈位置
|
||||
#define DEAD_BEEF 0xDEADBEEF
|
||||
|
||||
//定义文件ID和该文件包含的记录的KEY
|
||||
#define DEVICE_FILE (0x1000)//文件ID
|
||||
#define DEVICE_SCHEME_KEY (0x1001)//记录KEY,该记录存放的文件ID=0X1001
|
||||
|
||||
ble_gap_addr_t addr_ios;
|
||||
uint8_array_t address_ios;
|
||||
|
||||
// 包含参数信息的记录
|
||||
fds_record_t const m_SchemePara =
|
||||
{
|
||||
.file_id = DEVICE_FILE,
|
||||
.key = DEVICE_SCHEME_KEY,
|
||||
.data.p_data = &SchemePara,
|
||||
//记录的长度必须以4字节(字)为单位
|
||||
.data.length_words = (sizeof(SchemePara) + 3) / sizeof(uint32_t),
|
||||
};
|
||||
|
||||
//BLE串口透传例程中服务UUID列表
|
||||
static ble_uuid_t m_adv_uuids[] =
|
||||
{
|
||||
{BLE_UUID_NUS_SERVICE,UARTS_SERVICE_UUID_TYPE}
|
||||
};
|
||||
|
||||
|
||||
//保存申请的喂狗通道
|
||||
nrfx_wdt_channel_id m_channel_id;
|
||||
|
||||
/*必须的观察者函数*/
|
||||
NRF_BLE_GATT_DEF(m_gatt); //定义名称为m_gatt的GATT模块实例
|
||||
NRF_BLE_QWR_DEF(m_qwr); //定义一个名称为m_qwr的排队写入实例
|
||||
BLE_ADVERTISING_DEF(m_advertising); //定义名称为m_advertising的广播模块实例
|
||||
|
||||
void WdtFeed(void);
|
||||
//GATT事件处理函数
|
||||
void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
|
||||
{
|
||||
//如果是MTU交换事件
|
||||
if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)) //如果主句发起MTU升级请求
|
||||
{
|
||||
//设置串口透传服务的有效数据长度(MTU-opcode-handle)
|
||||
m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;///247字节
|
||||
NRF_LOG_INFO("Data len is set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len);
|
||||
}
|
||||
NRF_LOG_DEBUG("ATT MTU exchange completed. central 0x%x peripheral 0x%x",
|
||||
p_gatt->att_mtu_desired_central,
|
||||
p_gatt->att_mtu_desired_periph);
|
||||
}
|
||||
//初始化日志打印模块
|
||||
static void log_init(void)
|
||||
{
|
||||
//初始化log程序模块
|
||||
ret_code_t err_code = NRF_LOG_INIT(NULL);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
//设置log输出终端(根据sdk_config.h中的配置设置输出终端为UART或者RTT)
|
||||
NRF_LOG_DEFAULT_BACKENDS_INIT();
|
||||
}
|
||||
//GAP Generic Access Profile参数初始化,该函数配置需要的GAP参数,包括设备名称,外观特征、首选连接参数
|
||||
static void gap_params_init(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
//定义连接参数结构体变量
|
||||
ble_gap_conn_params_t gap_conn_params;
|
||||
ble_gap_conn_sec_mode_t sec_mode;
|
||||
//设置GAP的安全模式,即设置设备名称特征的写权限,这里设置的是安全模式1等级1,即无安全性
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
|
||||
//设置GAP设备名称
|
||||
err_code = sd_ble_gap_device_name_set(&sec_mode,
|
||||
(const uint8_t *)DEVICE_NAME,
|
||||
strlen(DEVICE_NAME));
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
//如果需要设置外观特征,在这里使用如下的代码设置
|
||||
/* err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_);
|
||||
APP_ERROR_CHECK(err_code); */
|
||||
|
||||
//设置首选连接参数,设置前先清零gap_conn_params
|
||||
memset(&gap_conn_params, 0, sizeof(gap_conn_params));
|
||||
|
||||
gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;//最小连接间隔
|
||||
gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;//最小连接间隔
|
||||
gap_conn_params.slave_latency = SLAVE_LATENCY; //从机延迟
|
||||
gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT; //监督超时
|
||||
//调用协议栈API sd_ble_gap_ppcp_set配置GAP参数
|
||||
err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
//初始化GATT程序模块
|
||||
static void gatt_init(void)
|
||||
{
|
||||
//初始化GATT程序模块
|
||||
ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
|
||||
//检查函数返回的错误代码
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
//设置服务端的默认MTU大小
|
||||
err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
//空闲状态处理函数(该函数需要放到主循环里面执行)。如果没有挂起的日志操作,则睡眠直到下一个事件发生后唤醒系统
|
||||
static void idle_state_handle(void)
|
||||
{
|
||||
//处理挂起的log
|
||||
if (NRF_LOG_PROCESS() == false)
|
||||
{
|
||||
//运行电源管理
|
||||
nrf_pwr_mgmt_run();
|
||||
}
|
||||
}
|
||||
//删除绑定信息
|
||||
static void delete_bonds(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
err_code = pm_peers_delete();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
//初始化电源管理模块
|
||||
static void power_management_init(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
//初始化电源管理
|
||||
err_code = nrf_pwr_mgmt_init();
|
||||
//检查函数返回的错误代码
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
//连接参数协商模块错误处理事件,参数nrf_error包含了错误代码,通过nrf_error可以分析错误信息
|
||||
static void conn_params_error_handler(uint32_t nrf_error)
|
||||
{
|
||||
//检查错误代码
|
||||
APP_ERROR_HANDLER(nrf_error);
|
||||
}
|
||||
|
||||
//连接参数协商模块事件处理函数
|
||||
static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
//判断事件类型,根据事件类型执行动作
|
||||
//连接参数协商失败
|
||||
if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
|
||||
{
|
||||
err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
//连接参数协商成功
|
||||
if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_SUCCEEDED)
|
||||
{
|
||||
//功能代码;
|
||||
}
|
||||
}
|
||||
//连接参数协商模块初始化(用于启动和执行连接参数协商规程)
|
||||
static void conn_params_init(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
//定义连接参数协商模块初始化结构体
|
||||
ble_conn_params_init_t cp_init;
|
||||
//配置之前先清零
|
||||
memset(&cp_init, 0, sizeof(cp_init));
|
||||
//设置为NULL,从主机获取连接参数
|
||||
cp_init.p_conn_params = NULL;
|
||||
//连接或启动通知到首次发起连接参数更新请求之间的时间设置为5秒
|
||||
cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
|
||||
//每次调用sd_ble_gap_conn_param_update()函数发起连接参数更新请求的之间的间隔时间设置为:30秒
|
||||
cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
|
||||
//放弃连接参数协商前尝试连接参数协商的最大次数设置为:3次
|
||||
cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
|
||||
//连接参数更新从连接事件开始计时
|
||||
cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
|
||||
//连接参数更新失败不断开连接
|
||||
cp_init.disconnect_on_fail = false;
|
||||
//注册连接参数更新事件句柄
|
||||
cp_init.evt_handler = on_conn_params_evt;
|
||||
//注册连接参数更新错误事件句柄
|
||||
cp_init.error_handler = conn_params_error_handler;
|
||||
//调用库函数(以连接参数更新初始化结构体为输入参数)初始化连接参数协商模块
|
||||
err_code = ble_conn_params_init(&cp_init);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
//BLE事件处理函数
|
||||
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
//连接建立后立即启动安全(当接收到连接建立事件(BLE_GAP_EVT_CONNECTED)时启动安全性)
|
||||
pm_handler_secure_on_connection(p_ble_evt);
|
||||
//判断BLE事件类型,根据事件类型执行相应操作
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
//断开连接事件
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
//打印提示信息
|
||||
NRF_LOG_INFO("Disconnected.");
|
||||
DeviceConnectState = DisconnectState;
|
||||
|
||||
DisconnectControl();
|
||||
break;
|
||||
|
||||
//连接事件
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
NRF_LOG_INFO("Connected.");
|
||||
DeviceConnectState = ConnectState;
|
||||
|
||||
DisconnectControl();
|
||||
//保存连接句柄
|
||||
m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
//将连接句柄分配给排队写入实例,分配后排队写入实例和该连接关联,这样,当有
|
||||
//多个连接的时候,通过关联不同的排队写入实例,很方便单独处理各个连接
|
||||
err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
break;
|
||||
|
||||
//PHY更新事件
|
||||
case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
|
||||
{
|
||||
NRF_LOG_DEBUG("PHY update request.");
|
||||
ble_gap_phys_t const phys =
|
||||
{
|
||||
.rx_phys = BLE_GAP_PHY_AUTO,
|
||||
.tx_phys = BLE_GAP_PHY_AUTO,
|
||||
};
|
||||
//响应PHY更新规程
|
||||
err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
} break;
|
||||
|
||||
//GATT客户端超时事件
|
||||
case BLE_GATTC_EVT_TIMEOUT:
|
||||
NRF_LOG_DEBUG("GATT Client Timeout.");
|
||||
//断开当前连接
|
||||
err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
|
||||
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
break;
|
||||
|
||||
//GATT服务器超时事件
|
||||
case BLE_GATTS_EVT_TIMEOUT:
|
||||
NRF_LOG_DEBUG("GATT Server Timeout.");
|
||||
//断开当前连接
|
||||
err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
|
||||
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//初始化BLE协议栈
|
||||
static void ble_stack_init(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
//请求使能SoftDevice,该函数中会根据sdk_config.h文件中低频时钟的设置来配置低频时钟
|
||||
err_code = nrf_sdh_enable_request();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
//定义保存应用程序RAM起始地址的变量
|
||||
uint32_t ram_start = 0;
|
||||
|
||||
//使用sdk_config.h文件的默认参数配置协议栈,获取应用程序RAM起始地址,保存到变量ram_start
|
||||
err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
//使能BLE协议栈
|
||||
err_code = nrf_sdh_ble_enable(&ram_start);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
//注册BLE事件回调函数
|
||||
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
|
||||
}
|
||||
|
||||
//广播事件处理函数
|
||||
static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
//判断广播事件类型
|
||||
switch (ble_adv_evt)
|
||||
{
|
||||
//快速广播启动事件:快速广播启动后会产生该事件
|
||||
case BLE_ADV_EVT_FAST:
|
||||
NRF_LOG_INFO("Fast advertising.");
|
||||
//设置广播指示灯为正在广播(D1指示灯闪烁)
|
||||
// err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
|
||||
// APP_ERROR_CHECK(err_code);
|
||||
break;
|
||||
|
||||
//广播IDLE事件:广播超时后会产生该事件
|
||||
case BLE_ADV_EVT_IDLE:
|
||||
//断电
|
||||
NRF_LOG_INFO("BLE_ADV_EVT_IDLE");
|
||||
nrf_gpio_pin_clear(KEY_POWER);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
//广播初始化
|
||||
static void advertising_init(void)
|
||||
{
|
||||
uint32_t err_code;
|
||||
//定义广播初始化配置结构体变量
|
||||
ble_advertising_init_t init;
|
||||
|
||||
err_code = sd_ble_gap_addr_get(&addr_ios);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
address_ios.size = 6;
|
||||
address_ios.p_data = addr_ios.addr;
|
||||
|
||||
ble_advdata_manuf_data_t test;
|
||||
|
||||
test.company_identifier = 0x1122;
|
||||
test.data = address_ios;
|
||||
|
||||
|
||||
//配置之前先清零
|
||||
memset(&init, 0, sizeof(init));
|
||||
//设备名称类型:全名
|
||||
init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
|
||||
//是否包含外观:包含
|
||||
init.advdata.include_appearance = false;
|
||||
//包含ble设备地址
|
||||
// init.advdata.include_ble_device_addr = true;
|
||||
init.advdata.p_manuf_specific_data = &test;
|
||||
|
||||
init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids)/sizeof(m_adv_uuids[0]);
|
||||
init.srdata.uuids_complete.p_uuids = m_adv_uuids;
|
||||
|
||||
//Flag:一般可发现模式,不支持BR/EDR
|
||||
init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
|
||||
|
||||
//设置广播模式为快速广播
|
||||
init.config.ble_adv_fast_enabled = true;
|
||||
//设置广播间隔和广播持续时间
|
||||
init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
|
||||
init.config.ble_adv_fast_timeout = APP_ADV_DURATION;
|
||||
//广播事件回调函数
|
||||
init.evt_handler = on_adv_evt;
|
||||
//初始化广播
|
||||
err_code = ble_advertising_init(&m_advertising, &init);
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
//设置广播配置标记。APP_BLE_CONN_CFG_TAG是用于跟踪广播配置的标记,这是为未来预留的一个参数,在将来的SoftDevice版本中,
|
||||
//可以使用sd_ble_gap_adv_set_configure()配置新的广播配置
|
||||
//当前SoftDevice版本(S132 V7.2.0版本)支持的最大广播集数量为1,因此APP_BLE_CONN_CFG_TAG只能写1。
|
||||
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
|
||||
}
|
||||
|
||||
//启动广播,该函数所用的模式必须和广播初始化中设置的广播模式一样
|
||||
static void advertising_start(bool erase_bonds)
|
||||
{
|
||||
if(erase_bonds == true)
|
||||
{
|
||||
//删除flash中存储的配对信息,执行完删除后,会产生PM_EVT_PEERS_DELETE_SUCCEEDED事件,
|
||||
//在该事件下会启动广播
|
||||
delete_bonds();
|
||||
}
|
||||
else
|
||||
{
|
||||
//使用广播初始化中设置的广播模式启动广播
|
||||
ret_code_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
|
||||
//检查函数返回的错误代码
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
//排队写入事件处理函数,用于处理排队写入模块的错误
|
||||
static void nrf_qwr_error_handler(uint32_t nrf_error)
|
||||
{
|
||||
//检查错误代码
|
||||
APP_ERROR_HANDLER(nrf_error);
|
||||
}
|
||||
|
||||
//服务初始化,包含初始化排队写入模块和初始化应用程序使用的服务
|
||||
static void services_init(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
//定义排队写入初始化结构体变量
|
||||
nrf_ble_qwr_init_t qwr_init = {0};
|
||||
|
||||
//排队写入事件处理函数
|
||||
qwr_init.error_handler = nrf_qwr_error_handler;
|
||||
//初始化排队写入模块
|
||||
err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
//串口透传服务初始化
|
||||
service_nus_init();
|
||||
}
|
||||
|
||||
#if 1
|
||||
//配对管理器事件处理函数
|
||||
static void pm_evt_handler(pm_evt_t const * p_evt)
|
||||
{
|
||||
//1、打印日志 2、连接已绑定设备时启动加密 3、出现错误调用错误处理程序
|
||||
pm_handler_on_pm_evt(p_evt);
|
||||
//清理配对设备在flash中的保存的绑定信息,当flash存储空间不足时删除
|
||||
//排列最低的配对设备的信息
|
||||
pm_handler_flash_clean(p_evt);
|
||||
|
||||
switch(p_evt->evt_id)
|
||||
{
|
||||
//存储的绑定信息已成功删除
|
||||
case PM_EVT_PEERS_DELETE_SUCCEEDED:
|
||||
//若程序启动时执行了删除绑定信息操作,在该事件下启动广播
|
||||
advertising_start(false);
|
||||
break;
|
||||
|
||||
case PM_EVT_CONN_SEC_CONFIG_REQ:
|
||||
{
|
||||
// 拒绝来自已经绑定对等方的配对请求.
|
||||
pm_conn_sec_config_t conn_sec_config = {.allow_repairing = true};
|
||||
pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
|
||||
} break;
|
||||
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//配对管理器初始化
|
||||
static void peer_manager_init(void)
|
||||
{
|
||||
ble_gap_sec_params_t sec_param;
|
||||
ret_code_t err_code;
|
||||
|
||||
//初始化配对管理器软件库
|
||||
err_code = pm_init();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
//配置安全参数前先清零结构体sec_param
|
||||
memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
|
||||
|
||||
//初始化安全性参数结构体,
|
||||
sec_param.bond = SEC_PARAM_BOND; //支持绑定
|
||||
sec_param.mitm = SEC_PARAM_MITM; //无MITM保护
|
||||
sec_param.lesc = SEC_PARAM_LESC; //不支持安全连接配对,即使用传统配对
|
||||
sec_param.keypress = SEC_PARAM_KEYPRESS; //无按键通知
|
||||
sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES; //无IO能力
|
||||
sec_param.oob = SEC_PARAM_OOB; //不支持OOB
|
||||
sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE; //最小加密密钥大小:7字节
|
||||
sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE; //最大加密密钥大小:16字节
|
||||
//本地密钥分发配置
|
||||
sec_param.kdist_own.enc = 1; //分发本地LTK
|
||||
sec_param.kdist_own.id = 1; //分发本地IRK
|
||||
//对端密钥分发配置
|
||||
sec_param.kdist_peer.enc = 1; //要求对方分发LTK
|
||||
sec_param.kdist_peer.id = 1; //要求对方分发IRK
|
||||
|
||||
//配置安全参数
|
||||
err_code = pm_sec_params_set(&sec_param);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
//向配对管理器注册事件句柄
|
||||
err_code = pm_register(pm_evt_handler);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
//FDS事件处理函数
|
||||
static void fds_evt_handler(fds_evt_t const * p_evt)
|
||||
{
|
||||
//判断事件类型
|
||||
switch (p_evt->id)
|
||||
{
|
||||
case FDS_EVT_INIT://FDS初始化事件
|
||||
if (p_evt->result == NRF_SUCCESS)//初始化成功
|
||||
{
|
||||
my_fds_info.busy = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case FDS_EVT_WRITE://FDS写记录事件
|
||||
{
|
||||
if (p_evt->result == NRF_SUCCESS)//写记录成功
|
||||
{
|
||||
my_fds_info.busy = false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case FDS_EVT_UPDATE://FDS更新记录事件
|
||||
{
|
||||
if (p_evt->result == NRF_SUCCESS)//写记录成功
|
||||
{
|
||||
my_fds_info.busy = false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case FDS_EVT_GC://FDS碎片整理事件
|
||||
{
|
||||
if (p_evt->result == NRF_SUCCESS)//碎片整理成功
|
||||
{
|
||||
my_fds_info.busy = false;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
//等待FDS初始化完成
|
||||
static void wait_for_fds_ready(void)
|
||||
{
|
||||
while (my_fds_info.busy)
|
||||
{
|
||||
(void) sd_app_evt_wait();
|
||||
}
|
||||
}
|
||||
// 读取方案并且发送
|
||||
void read_scheme(void)
|
||||
{
|
||||
ret_code_t rc;
|
||||
//定义并初始化记录描述符结构体变量
|
||||
fds_record_desc_t desc = {0};
|
||||
//定义并初始化记录查找令牌结构体变量
|
||||
fds_find_token_t tok = {0};
|
||||
|
||||
uint16_t tempidvalue;
|
||||
//清零tok,从头查找
|
||||
memset(&tok, 0x00, sizeof(fds_find_token_t));
|
||||
//在DEVICE_FILE文件中查找记录m_version_record
|
||||
rc = fds_record_find(DEVICE_FILE, DEVICE_SCHEME_KEY, &desc, &tok);
|
||||
//查找到记录后,读取记录内容
|
||||
if(rc == NRF_SUCCESS)
|
||||
{
|
||||
fds_flash_record_t temp = {0};
|
||||
//打开记录读取记录内容
|
||||
rc = fds_record_open(&desc, &temp);
|
||||
APP_ERROR_CHECK(rc);
|
||||
//拷贝记录内容
|
||||
memcpy(&SchemeData, temp.p_data, sizeof(SchemeData_t));
|
||||
//读取后,关闭记录
|
||||
rc = fds_record_close(&desc);
|
||||
APP_ERROR_CHECK(rc);
|
||||
// 连接状态下发送方案ID
|
||||
if(DeviceConnectState == ConnectState)
|
||||
{
|
||||
SchemeQuery(SchemeData.SchemeIDMSB,SchemeData.SchemeIDLSB);
|
||||
}
|
||||
// 未连接状态下给默认的治疗方案
|
||||
else
|
||||
{
|
||||
StimStateInfoStructInit(SchemeData);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// 存储管理中断处理函数
|
||||
void FdsHandler(fds_record_desc_t *Desc,fds_find_token_t *Tok)
|
||||
{
|
||||
ret_code_t rc;
|
||||
if(my_fds_info.read == true)//读取记录
|
||||
{
|
||||
my_fds_info.read = false;
|
||||
read_scheme();//读取记录数据,并发送
|
||||
}
|
||||
//更新记录m_fw_record
|
||||
if((my_fds_info.scheme_update == true) && (my_fds_info.busy == false))
|
||||
{
|
||||
//清零tok,从头查找
|
||||
memset(Tok, 0x00, sizeof(fds_find_token_t));
|
||||
//在DEVICE_FILE文件中查找记录m_fw_record
|
||||
rc = fds_record_find(DEVICE_FILE, DEVICE_SCHEME_KEY, Desc, Tok);
|
||||
if (rc == NRF_SUCCESS)
|
||||
{
|
||||
my_fds_info.busy = true;
|
||||
my_fds_info.scheme_update = false;
|
||||
//更新记录m_fw_record
|
||||
rc = fds_record_update(Desc, &m_SchemePara);
|
||||
APP_ERROR_CHECK(rc);
|
||||
wait_for_fds_ready();
|
||||
NRF_LOG_INFO("fds_record_update");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wdt_event_handler(void)
|
||||
{
|
||||
|
||||
}
|
||||
void WdtInit(void)
|
||||
{
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
|
||||
//定义WDT配置结构体并使用
|
||||
nrfx_wdt_config_t config = NRFX_WDT_DEAFULT_CONFIG;
|
||||
//初始化WDT
|
||||
err_code = nrfx_wdt_init(&config, wdt_event_handler);
|
||||
//申请喂狗通道,也就是使用哪个
|
||||
err_code = nrfx_wdt_channel_alloc(&m_channel_id);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
//启动WDT
|
||||
nrfx_wdt_enable();
|
||||
}
|
||||
//喂狗函数
|
||||
void WdtFeed(void)
|
||||
{
|
||||
//喂狗
|
||||
nrfx_wdt_channel_feed(m_channel_id);
|
||||
}
|
||||
|
||||
void clocks_start(void)
|
||||
{
|
||||
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;//清零高频时钟启动事件
|
||||
NRF_CLOCK->TASKS_HFCLKSTART = 1; //启动高频时钟
|
||||
//等待高频时钟启动完成
|
||||
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
|
||||
}
|
||||
|
||||
//驱动初始化
|
||||
void DeviceInit(void)
|
||||
{
|
||||
/* 初始化控制gpio */
|
||||
GpioInit();
|
||||
clocks_start();
|
||||
EXIT_KEY_Init();
|
||||
/* 初始化APP定时器 */
|
||||
AppTimersInit();
|
||||
timer3_rms_init();
|
||||
/* DACPWM初始化 */
|
||||
// PwmDACInit();
|
||||
|
||||
/* SAADC初始化 */
|
||||
battery_adc_init();
|
||||
rms_saadc_init();
|
||||
|
||||
/* 采样的PPI初始化 */
|
||||
//PPIPwmInit();
|
||||
PPIEegAdcInit();
|
||||
/* GPIOTE初始化 */
|
||||
GpioteInit();
|
||||
// nrf_gpio_pin_clear(H_CTL1_PWM);
|
||||
// nrf_gpio_pin_clear(H_CTL2_PWM);
|
||||
/* 刺激PWM初始化 */
|
||||
pwm0_common_init();
|
||||
|
||||
pwm2common_init();
|
||||
//timer1_output_ctrl_init();
|
||||
/* 喂狗初始化 */
|
||||
WdtInit();
|
||||
}
|
||||
|
||||
|
||||
//广播中添加MAC地址
|
||||
void MacSet(void)
|
||||
{
|
||||
ble_gap_addr_t addr;
|
||||
|
||||
uint32_t err_code = sd_ble_gap_addr_get(&addr);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
memcpy(BLE_MAC,addr.addr,BLE_GAP_ADDR_LEN);
|
||||
err_code = sd_ble_gap_addr_set(&addr);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
void StartAdv(void)
|
||||
{
|
||||
//启动广播
|
||||
advertising_start(false);
|
||||
}
|
||||
|
||||
// 关闭广播
|
||||
void StopAdv(void)
|
||||
{
|
||||
NRF_LOG_INFO("StopAdv!");
|
||||
|
||||
sd_ble_gap_adv_stop(m_advertising.adv_handle);
|
||||
}
|
||||
|
||||
void user_ble_init(void)
|
||||
{
|
||||
|
||||
//初始化协议栈
|
||||
ble_stack_init();
|
||||
|
||||
//变量初始化
|
||||
VariableInit();
|
||||
|
||||
//配置GAP参数
|
||||
gap_params_init();
|
||||
//初始化GATT
|
||||
gatt_init();
|
||||
|
||||
//初始化服务
|
||||
services_init();
|
||||
//在广播数据中添加MAC地址
|
||||
MacSet();
|
||||
//初始化广播
|
||||
advertising_init();
|
||||
|
||||
//连接参数协商初始化
|
||||
conn_params_init();
|
||||
//配对管理器初始化
|
||||
peer_manager_init();
|
||||
//LOG打印信息
|
||||
NRF_LOG_INFO("BLE started.");
|
||||
}
|
||||
|
||||
|
||||
//fds存储管理初始化
|
||||
void fdsInit(ret_code_t rec,fds_record_desc_t desct,fds_find_token_t token)
|
||||
{
|
||||
|
||||
//注册FDS事件回调函数接收FS事件
|
||||
(void)fds_register(fds_evt_handler);
|
||||
|
||||
my_fds_info.busy = true;
|
||||
rec = fds_init();//初始化FDS
|
||||
APP_ERROR_CHECK(rec);//用错误处理模块检查函数返回值
|
||||
//FDS初始化是异步的,因此要等待FDS初始化完成
|
||||
wait_for_fds_ready();
|
||||
//清零tok,从头查找
|
||||
memset(&token, 0x00, sizeof(fds_find_token_t));
|
||||
//在DEVICE_FILE文件中查找记录m_desp_record
|
||||
rec = fds_record_find(DEVICE_FILE, DEVICE_SCHEME_KEY, &desct, &token);
|
||||
|
||||
NRF_LOG_INFO("rec = %d",rec);
|
||||
|
||||
//没有查找到m_desp_record记录,写入记录
|
||||
if (rec != NRF_SUCCESS)
|
||||
{
|
||||
my_fds_info.busy = true;
|
||||
StimStateInfoStructInit(PreStorageSchemeData); // 用预存的信息给刺激参数赋值
|
||||
memcpy(SchemePara.text,&PreStorageSchemeData,sizeof(PreStorageSchemeData));
|
||||
rec = fds_record_write(&desct, &m_SchemePara);
|
||||
APP_ERROR_CHECK(rec);
|
||||
wait_for_fds_ready();
|
||||
}
|
||||
else
|
||||
{
|
||||
my_fds_info.read = true;
|
||||
}
|
||||
}
|
||||
//主函数
|
||||
int main(void)
|
||||
{
|
||||
ret_code_t rc;
|
||||
//定义并初始化记录描述符结构体变量
|
||||
fds_record_desc_t desc = {0};
|
||||
//定义并初始化记录查找令牌结构体变量
|
||||
fds_find_token_t tok = {0};
|
||||
|
||||
//初始化log程序模块
|
||||
log_init();
|
||||
//滤波器初始化
|
||||
FilterInit();
|
||||
// 设备预存信息初始化ID :101 腹直肌分离
|
||||
PreStorageSchemeDataInit();
|
||||
//fds存储管理初始化
|
||||
fdsInit(rc,desc,tok);
|
||||
//器件初始化
|
||||
DeviceInit();
|
||||
|
||||
//初始化电源管理
|
||||
power_management_init();
|
||||
user_ble_init();
|
||||
|
||||
//启动已经创建的APP定时器
|
||||
ApplicationTimersStart();
|
||||
//主循环
|
||||
while(true)
|
||||
{
|
||||
// 存储事件处理函数
|
||||
FdsHandler(&desc,&tok);
|
||||
//处理挂起的LOG和运行电源管理
|
||||
idle_state_handle();
|
||||
WdtFeed();
|
||||
if(POWER_CLOSE == DeviceState)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
KeyPinHandler();// 按键中断处理
|
||||
//输出电流控制
|
||||
|
||||
|
||||
/* 适配器和电极片脱落状态变化上传 */
|
||||
if(AdapterState == LastAdapterState)
|
||||
{
|
||||
StateUpLoad(AdapterState,ElectrodeStatusInfo);
|
||||
if(AdapterState == AdapterConnected)
|
||||
{
|
||||
LastAdapterState = AdapterNotConnected;
|
||||
}
|
||||
else
|
||||
{
|
||||
LastAdapterState = AdapterConnected;
|
||||
}
|
||||
}
|
||||
|
||||
if(ElectrodeStatusInfo == LastElectrodeStatusInfo)
|
||||
{
|
||||
StateUpLoad(AdapterState,ElectrodeStatusInfo);
|
||||
if(ElectrodeStatusInfo == ElectrodeFalloff)
|
||||
{
|
||||
LastElectrodeStatusInfo = ElectrodeConnectted;
|
||||
}
|
||||
else
|
||||
{
|
||||
LastElectrodeStatusInfo = ElectrodeFalloff;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user