本博客参考https://blog.youkuaiyun.com/qq_36347513/article/details/103853796
本博客基于NRF——SDK17.0.0协议栈的ble_app_template工程添加SAADC功能。
直接上代码,下面会有ADC的介绍:
/*********************************************************************
* INCLUDES
*/
#include "nrfx_saadc.h"
#include "nrf_drv_saadc.h"
#include "app_error.h"
#include "board_adc.h"
#include "nrf_log.h"
static void adcCallbackFunc(nrf_drv_saadc_evt_t const* pEvent);
/*********************************************************************
* LOCAL VARIABLES
*/
static nrf_saadc_value_t s_bufferPool[SAMPLES_IN_BUFFER];
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/**
@brief ADC的初始化函数
@param 无
@return 无
*/
void ADC_Init(void)
{
ret_code_t errCode;
// ADC初始化
errCode = nrf_drv_saadc_init(NULL, adcCallbackFunc);
APP_ERROR_CHECK(errCode);
// ADC通道配置
nrf_saadc_channel_config_t channelConfig = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0); // 单端输入
// ADC通道初始化
errCode = nrf_drv_saadc_channel_init(0, &channelConfig);
APP_ERROR_CHECK(errCode);
// 缓冲配置
errCode = nrf_drv_saadc_buffer_convert(s_bufferPool, SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(errCode);
}
/**
@brief ADC读取
@param 无
@return 结果在回调函数的缓冲区中
*/
void ADC_Read(void)
{
ret_code_t errCode;
errCode = nrf_drv_saadc_sample();
APP_ERROR_CHECK(errCode);
}
/**
@brief 开启ADC,与初始化没有区别,为了与Disable成对出现
@param 无
@return 无
*/
void ADC_Enable(void)
{
ADC_Init();
}
/**
@brief 禁用ADC
@param 无
@return 无
*/
void ADC_Disable(void)
{
nrfx_saadc_uninit();
}
/*********************************************************************
* LOCAL FUNCTIONS
*/
/**
@brief ADC中断处理回调函数
@param 无
@return 无
*/
static void adcCallbackFunc(nrf_drv_saadc_evt_t const* pEvent)
{
if (pEvent->type == NRF_DRV_SAADC_EVT_DONE) // 采样完成
{
nrf_saadc_value_t adcResult;
uint16_t batteryVoltage;
uint8_t batteryPercentage;
ret_code_t errCode;
// 设置好缓存,为下次转换缓冲做准备,并且把导入到缓冲的值提取出来
errCode = nrf_drv_saadc_buffer_convert(pEvent->data.done.p_buffer, SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(errCode);
adcResult = pEvent->data.done.p_buffer[0];
// 电池电压转换计算
batteryVoltage = ADC_RESULT_IN_MILLI_VOLTS(adcResult);
}
}
/****************************************************END OF FILE****************************************************/
#ifndef _BOARD_ADC_H_
#define _BOARD_ADC_H_
/*********************************************************************
* INCLUDES
*/
#include "nordic_common.h"
/*********************************************************************
* DEFINITIONS
*/
#define ADC_REF_VOLTAGE_IN_MILLIVOLTS 600 /**< Reference voltage (in milli volts) used by ADC while doing conversion. */
#define ADC_PRE_SCALING_COMPENSATION 6 /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/
#define DIODE_FWD_VOLT_DROP_MILLIVOLTS 1000 /**< Typical forward voltage drop of the diode . */
#define ADC_RES_10BIT 1024 /**< Maximum digital value for 10-bit ADC conversion. */
// VP = (RESULT * REFERENCE / 2^10) * 6
#define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE)\
((((ADC_VALUE) * ADC_REF_VOLTAGE_IN_MILLIVOLTS) / ADC_RES_10BIT) * ADC_PRE_SCALING_COMPENSATION)
#define SAMPLES_IN_BUFFER 1
/*********************************************************************
* API FUNCTIONS
*/
void ADC_Init(void);
void ADC_Read(void);
void ADC_Enable(void);
void ADC_Disable(void);
#endif /* _BOARD_ADC_H_ */
int main(void)
{
bool erase_bonds;
// Initialize.
/***********************************************************************************/
log_init();
timers_init();
buttons_leds_init(&erase_bonds);
Board_LED0Init();
SPI_Init();
ADC_Init();
/***********************************************************************************/
power_management_init();
ble_stack_init();
gap_params_init();
gatt_init();
advertising_init();
services_init();
conn_params_init();
peer_manager_init();
/**********************************************************************************/
// Start execution.
NRF_LOG_INFO("Template example started.");
application_timers_start();
advertising_start(erase_bonds);
ADC_Disable();
// Enter main loop.
for (;;)
{
idle_state_handle();
}
}
我们在卖弄函数中对ADC进行初始化操作。
接下来我们还需要打开关于ADC的宏定义
同时并在工程中添加关于SAADC的驱动库:
这两个文件分别在SDK包中的integration与modules文件夹下面
不然就会报错,说明找不到ADC初始化的某些函数
NRF52832 中 ADC 为一个 逐次逼近(SAADC) 模拟数字转换器
- 8/10/12 位分辨率,采用过采样可以达到 14 位分辨率。
- 多达 8 个输入通道:
单端输入时有 1 个通道,2 个通道组成差分输入。
单端和差分输入时可以配置成扫描模式。 - 满量程输入范围为 0 和 VDD
- 可以通过软件触发采样任务启动采样,也可以使用低功耗 32.768KHz 的 RTC 定时器或更精确的 1/16MHz 定时器通过 PPI 来触发采样任务。
- NRF52832 的 SAADC 支持 单次模式和扫描模式:
单次的采集模式只使用一个采集通道。
扫描模式是按照顺序采样一系列通道。Sample delay between channels is tack + tconv
which may vary between channels according to user configuration of tack. - 通过 EasyDMA 可以直接将采样结果保存到 RAM。
- 无需外部定时器即可实现连续采样。
- 可配置通道输入负载电阻。
- 具备采样值门限检测功能。
nrf_saadc_channel_config_t channelConfig = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0); // 单端输入
用来进行ADC通道的配置
void ADC_Read(void)
此函数用来读取adc转换的结果,结果存放在回调函数的缓冲区中
adcCallbackFunc(nrf_drv_saadc_evt_t const* pEvent)
为ADC中断处理回调函数
nrf_drv_saadc_sample()启动一次ADC转换,这一次的转换包括配置的所有ADC通道的转换。
(1)在回调函数中,我们首先判断事件类型,如果时缓存区有数据事件类型才开始处理数据。
(2)p_event-> data.done.p_buffer实质就是我们开始定义的ADC数据缓冲区adc_buffer [2] [SAMPLES_IN_BUFFER],通过nrf_drv_saadc_buffer_convert()函数在初始化时绑定。
(3)不同的通道采集的数据,存放在缓存数组的不同下标元素位上存放顺序与我们使用的通道有关,低通道采集的数据存在低下标元素位上例如:。我们使用的channel_7采集电池电压,CHANNEL_1采集温度电阻,p_event-> data.done.p_buffer [0]就时CHANNEL_1转换完成的数据,p_event-> data.done.p_buffer [1]是channel_7转换完成的数据。