HL-PDJ-1/app/Src/drv_saadc.c
xiaozhengsheng 6df0f7d96e 初始版本
2025-08-19 09:49:41 +08:00

365 lines
12 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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