365 lines
12 KiB
C
365 lines
12 KiB
C
/********************************************************************
|
||
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 ***************************/
|