初始版本
This commit is contained in:
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 ***************************/
|
||||
Reference in New Issue
Block a user