SAADC部分思維導圖
1ADC原理
1.1主要特點
1)8/10/12分辨率,使用過采樣可達到14位分辨率
2)多達8個通道
單端輸入時使用1個通道,2個通道可組成差分輸入
單端和差分輸入時均可配置為掃描模式
3)滿量程輸入范圍(0 to VDD)
參考芯片數據手冊
1.2功能概述
參考芯片數據手冊
1.3工作模式
1)單次模式
2)連續模式
使用ADC內部定時器實現定時采樣
使用nRF52832的通用定時器定時同PPI觸發采樣,實現連續采樣
3)掃描模式
當使能一個ADC通道,ADC工作於單次模式,當使能的通道數量大於1個,ADC進入掃描模式
2SAADC的應用步驟
2.1SAADC庫文件
2.2SAADC驅動的應用
1)阻塞模式
2)非阻塞模式
3)門限監測
3相關寄存器
4重要的庫函數
5DEMO
5.1阻塞模式-單端輸入采樣
SAADC初始化
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "app_uart.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "nrf.h"
#include "bsp.h"
#include "app_uart.h"
#include "nrf_drv_saadc.h"
#define UART_TX_BUF_SIZE 256 //uart 發送軟件緩存大小(字節數)
#define UART_RX_BUF_SIZE 256 //uart 接收軟件緩存大小(字節數)
//saadc回調函數
void saadc_callback(nrf_drv_saadc_evt_t const *p_event){}
//saadc初始化函數
void saadc_init(void)
{
ret_code_t err_code;
//定義SAADC初始化結構體
//使用默認的宏初始化時需要指定該通道的模擬輸入引腳
//具體的引腳分布參考數據手冊
nrf_saadc_channel_config_t mmysaadc=
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
//初始化SAADC,注冊事件回調函數,注意因為使用了阻塞模式
//所以可以不用回調函數,但是nrf_drv_saadc_init()要求必須提供回調函數
//所以這里要注冊回調函數,無論有沒有用到
err_code=nrf_drv_saadc_init(NULL,saadc_callback);
APP_ERROR_CHECK(err_code);
//初始化SAADC通道0
err_code = nrf_drv_saadc_channel_init(0, &mmysaadc);
APP_ERROR_CHECK(err_code);
}
//uart事件回調函數
void uart_error_handle(app_uart_evt_t * p_event)
{
if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)
{
APP_ERROR_HANDLER(p_event->data.error_communication);
}
else if (p_event->evt_type == APP_UART_FIFO_ERROR)
{
APP_ERROR_HANDLER(p_event->data.error_code);
}
}
//初始化串口
void usart_init()
{
uint32_t err_code;
//定義一個uart配置結構體
const app_uart_comm_params_t comm_params =
{
RX_PIN_NUMBER, //定義uart接收引腳
TX_PIN_NUMBER, //定義uart發送引腳
RTS_PIN_NUMBER, //定義uart RTS引腳,注意流控關閉后雖然定義了RTS和CTS引腳,但是不起作用
CTS_PIN_NUMBER, //定義uart CTS引腳
APP_UART_FLOW_CONTROL_DISABLED, //關閉uart流控
false,
UART_BAUDRATE_BAUDRATE_Baud115200 //uart波特率
};
//初始化app uart,注冊uart事件回調函數
APP_UART_FIFO_INIT(&comm_params,
UART_RX_BUF_SIZE,
UART_TX_BUF_SIZE,
uart_error_handle,
APP_IRQ_PRIORITY_LOWEST,
err_code);
APP_ERROR_CHECK(err_code);
}
/**********************************************************************************************
* 描 述 : main函數
* 入 參 : 無
* 返回值 : 無
***********************************************************************************************/
int main(void)
{
nrf_saadc_value_t saadc_val;
float voltage=9.99;; //轉化后的電壓值
usart_init(); //初始化串口
saadc_init(); //初始化SAADC
while(true)
{
//啟動一次ADC采樣
nrf_drv_saadc_sample_convert(0,&saadc_val);
voltage=(float)saadc_val*3.6/1024;
printf("voltage=%f\n",voltage);
nrf_delay_ms(300); //延時300ms
printf("saadc_val=V%d\n", saadc_val);
}
}
SAADC初始化包括兩部分:SAADC驅動程序初始化,SAADC通道配置。nrf_drv_saadc.h中定義了兩個帶輸入參數的初始化宏
#define NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(PIN_P) \
{ \
.resistor_p = NRF_SAADC_RESISTOR_DISABLED, \
.resistor_n = NRF_SAADC_RESISTOR_DISABLED, \
.gain = NRF_SAADC_GAIN1_6, \
.reference = NRF_SAADC_REFERENCE_INTERNAL, \
.acq_time = NRF_SAADC_ACQTIME_10US, \
.mode = NRF_SAADC_MODE_SINGLE_ENDED, \
.pin_p = (nrf_saadc_input_t)(PIN_P), \
.pin_n = NRF_SAADC_INPUT_DISABLED \
}
注意1
初始化宏配置SAADC通道的參數如下
ADC輸入正極電阻配置:旁路電阻梯
ADC輸入負極電阻配置:旁路電阻梯
增益:1/6
參考電壓:內部0.6V
采樣時間:10US
模式:單端輸入
突發模式:禁止
ADC輸入正極連接的模擬輸入引腳
ADC輸入負極連接的模擬輸入引腳:不連接
注意2
err_code=nrf_drv_saadc_init(NULL,saadc_callback);
SAADC初始化函數nrf_drv_saadc_init(),如果沒有提供SAADC配置結構體即第一個參數為NULL,這時驅動會使用“sdk_config.h”文件默認參數配置SAADC
5.2阻塞模式-差分輸入采樣
SAADC初始化
//saadc初始化函數
void saadc_init(void)
{
ret_code_t err_code;
//定義SAADC初始化結構體
//使用默認的宏初始化時需要指定該通道的模擬輸入引腳
//具體的引腳分布參考數據手冊
nrf_saadc_channel_config_t mmysaadc=
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_DIFFERENTIAL(NRF_SAADC_INPUT_AIN2,NRF_SAADC_INPUT_AIN0);
//初始化SAADC,注冊事件回調函數,注意因為使用了阻塞模式
//所以可以不用回調函數,但是nrf_drv_saadc_init()要求必須提供回調函數
//所以這里要注冊回調函數,無論有沒有用到
err_code=nrf_drv_saadc_init(NULL,saadc_callback);
APP_ERROR_CHECK(err_code);
//初始化SAADC通道0
err_code = nrf_drv_saadc_channel_init(0, &mmysaadc);
APP_ERROR_CHECK(err_code);
}
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_DIFFERENTIAL宏有兩個輸入參數,對應通道的正極模擬輸入引腳和負極模擬輸入引腳
#define NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_DIFFERENTIAL(PIN_P, PIN_N) \
{ \
.resistor_p = NRF_SAADC_RESISTOR_DISABLED, \
.resistor_n = NRF_SAADC_RESISTOR_DISABLED, \
.gain = NRF_SAADC_GAIN1_6, \
.reference = NRF_SAADC_REFERENCE_INTERNAL, \
.acq_time = NRF_SAADC_ACQTIME_10US, \
.mode = NRF_SAADC_MODE_DIFFERENTIAL, \
.pin_p = (nrf_saadc_input_t)(PIN_P), \
.pin_n = (nrf_saadc_input_t)(PIN_N) \
}
主函數:
int main(void)
{
nrf_saadc_value_t saadc_val;
float voltage=9.99;; //轉化后的電壓值
usart_init(); //初始化串口
saadc_init(); //初始化SAADC
while(true)
{
//啟動一次ADC采樣
nrf_drv_saadc_sample_convert(0,&saadc_val);
//這里saadc_val變成了差分值
voltage=(float)saadc_val*3.6/1024;
printf("voltage=%f\n",voltage);
nrf_delay_ms(300); //延時300ms
printf("saadc_val=V%d\n", saadc_val);
}
}
5.3非阻塞模式-單緩存采樣
//定義SAADC采樣數據緩存
//定義SAADC采樣緩存數組大小
//只有采樣結果存滿該緩存之后,才會產生SAADC采樣完成事件
#define SAMPLES_IN_BUFFER 1
//定義SAADC采樣緩存數組大小
nrf_saadc_value_t m_buffer_pool[SAMPLES_IN_BUFFER];
//定義該變量用來保存SAADC采樣的次數
static uint32_t m_adc_evt_counter;
//SAADC初始化函數
void saadc_init(void)
{
ret_code_t err_code;
//定義SAADC初始化結構體
//使用默認的宏初始化時需要指定該通道的模擬輸入引腳
//具體的引腳分布參考數據手冊
nrf_saadc_channel_config_t mmysaadc=
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
//初始化SAADC,注冊事件回調函數,
//注意,本例使用的是非阻塞模式,非阻塞模式下,采樣完成后以事件
//的方式通知應用程序,應用程序在事件回調函數中讀取采樣數據
err_code=nrf_drv_saadc_init(NULL,saadc_callback);
APP_ERROR_CHECK(err_code);
//初始化SAADC通道0
err_code = nrf_drv_saadc_channel_init(NULL, &mmysaadc);
APP_ERROR_CHECK(err_code);
//設置好緩存,等待應用程序啟動采樣
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool, SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
}
nrf_drv_saadc_buffer_convert函數將SAADC工作於非阻塞模式,可將SAADC配置為就緒狀態,但是不會觸發采樣
ret_code_t nrf_drv_saadc_buffer_convert (
nrf_saadc_value_t * buffer,
uint16_t size
)
Function for issuing conversion of data to the buffer.
Parameters:
[in] buffer Result buffer.
[in] size Buffer size in words.
//saadc回調函數
void saadc_callback(nrf_drv_saadc_evt_t const *p_event)
{
float val; //保存SAADC采樣數據計算的實際電壓值
if(p_event->type == NRF_DRV_SAADC_EVT_DONE) //Event generated when the buffer is filled with samples
{
ret_code_t err_code;
//設置好緩存,為下一次采樣准備
err_code=nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer,
SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
int i;
//串口打印采樣次數
printf("ADC event number:%d\r\n",(int)m_adc_evt_counter);
for(i=0;i<SAMPLES_IN_BUFFER;i++)
{
val=p_event->data.done.p_buffer[i]*3.6/1024;
printf("Voltage = %.3fV\r\n", val);
}
//采樣次數加1
m_adc_evt_counter++;
}
}
5.4非阻塞模式-雙緩存采樣
5.5電池電壓采樣
5.6三個通道同時采樣-定時器觸發
//定義SAADC采樣緩存數組大小
#define SAMPLES_IN_BUFFER 3
//定義SAADC采樣緩存數組
static nrf_saadc_value_t m_buffer_pool[SAMPLES_IN_BUFFER];
/***********************************************************
*函數介紹:初始化SAADC
通道0 采集電位器電壓 P004
通道1 采集光敏電阻電壓 P002
通道2 采樣芯片供電電壓 不需要外接引腳
*輸入參數:
*輸出參數:
*返回值:無
************************************************************/
void saadc_init(void)
{
ret_code_t err_code;
//定義SAADC采樣通道0初始化配置結構體變量,並用默認參數初始化
nrf_saadc_channel_config_t channel_0_config=
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
channel_0_config.gain=NRF_SAADC_GAIN1_6;
channel_0_config.reference=NRF_SAADC_REFERENCE_INTERNAL; //使用內部的0.6V作為參考電壓
//定義SAADC采樣通道1初始化配置結構體,並用默認參數初始化
nrf_saadc_channel_config_t channel_1_config=
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);
channel_1_config.gain=NRF_SAADC_GAIN1_6;
channel_1_config.reference=NRF_SAADC_REFERENCE_INTERNAL; //使用內部的0.6V作為參考電壓
//定義SAADC采樣通道2初始化配置結構體
nrf_saadc_channel_config_t channel_2_config=
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(SAADC_CH_PSELP_PSELP_VDD);
channel_2_config.gain=NRF_SAADC_GAIN1_6;
channel_2_config.reference=NRF_SAADC_REFERENCE_INTERNAL; //使用內部的0.6V作為參考電壓
//初始化SAADC
err_code=nrf_drv_saadc_init(NULL,saadc_callback);
APP_ERROR_CHECK(err_code);
//初始化SAADC的通道0
err_code = nrf_drv_saadc_channel_init(0, &channel_0_config);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_channel_init(1, &channel_1_config);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_channel_init(2, &channel_2_config);
APP_ERROR_CHECK(err_code);
//使用雙緩存
//設置好第一個緩存
err_code=nrf_drv_saadc_buffer_convert(m_buffer_pool,SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
// //設置好第二個緩存
// err_code=nrf_drv_saadc_buffer_convert(m_buffer_pool[1],SAMPLES_IN_BUFFER);
// APP_ERROR_CHECK(err_code);
}
注意
三個通道采樣,分別配置為通道0,1,2
//saadc回調函數
void saadc_callback(nrf_drv_saadc_evt_t const *p_event)
{
ret_code_t err_code;
float val; //保存SAADC采樣數據計算的實際電壓值
if(p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
//設置好緩存,為下一次采樣做准備
err_code=nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer,
SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
//讀取采樣結果,使用串口發送
for(uint32_t i=0;i<SAMPLES_IN_BUFFER;i++)
{
val=p_event->data.done.p_buffer[i]*3.6/1024;
// printf("Voltage = %.3fV\r\n", val);
switch(i)
{
case 0:printf("AIN2=%f\r\n",val); break;
case 1:printf("AIN0=%f\r\n",val); break;
case 2:printf("VDD=%f\r\n",val); break;
default:break;
}
}
}
}
/**********************************************************************************************
* 描 述 : main函數
* 入 參 : 無
* 返回值 : 無
***********************************************************************************************/
int main(void)
{
nrf_saadc_value_t saadc_val;
usart_init(); //初始化串口
saadc_init(); //初始化SAADC
timers_init(); //定時器初始化函數
while(true)
{
}
}