简介:ADC在实际使用的时候都要进行误差校准,那Nordic的nrf52系列如何进行校准,如果不校准又有什么影响尼,接下来我将通过实验进行测试,验证不校准和校准的影响(本测试的基础是,默认输入阻抗和采样时间都是合理范围的,没有超标)。

测试环境:

硬件:nrf52DK(nrf52832)

软件:基于nRF5_SDK_17.1.0_ddde560中的SAADC例子进行修改

一、误差确定

  在数据手册ADC的电器章节有这样一个数据表,这个表中对应不同的增益模式有不同的误差范围,如我本次测试采用的就是1/6增益,那么对于芯片来说,误差范围在3%以内都是正常的

上面提到了误差,那这个误差影响什么值尼,主要影响了采样精度,如配置一个1/6增益,然后12bit分辨率的ADC然后进行采样,2^12=4096,也就是说在满量程也就是采样电压等于VCC的时候,理论值的采样值应该为4096,也就是说如果我给芯片供电为3.3V,那么我去采样一个3.3V的电源(公地)是采样值应该是4096,采样GND时应该是0,这都是理论值,实际情况是肯定有偏差的,而且没一个芯片的偏差还不一样,但是对于正常的芯片这个偏差都在一个范围,也就是我上表截图的范围。根据表格有这样一个计算,4096*3%=90 ,也就是说在采集3.3V时,值可以为4006~4096都是正常的,因为有90的偏差。

而我们进行校准就是减小这个误差,为什么是减小,是因为误差是不可能消除的。

二、代码

1、测试方式

  添加校准代码,在校准ADC后启动单次采样,单次采样使用定时器触发,每采样10次就进行一次校准,校准期间不进行采样,如果有转换也先进行停止。保证结果的准确性。

2、代码添加

由于是基于历程:SDK\examples\peripheral\saadc 进行测试,已经有想过的timer源文件加入,所以不用再加入timer相关的源文件了,如果你不是用这个例子,是使用自己的工程代码进行添加,那么应该注意timer的选择,如果是ble的项目,ble默认使用的timer0,timer0就不能用了,需要使用timer1,需要启动sdk_config中的关于timer1的所有宏定义,不然就会编译报错。

在下面这份代码中通过设置宏 Y_and_N_calibrate_change 来确定是否启用校准功能。

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "app_util_platform.h"
#include "nrf_pwr_mgmt.h" #include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h" /*是否启用校准代码*/
#define Y_and_N_calibrate_change 0 nrf_saadc_value_t test_value; //ADC原始采样值 float V_test=0; //ADC转换后的采样值 static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(0); typedef struct{
#if Y_and_N_calibrate_change
bool offset_calibrate_flag; //校准标志
#endif
bool adc_sample_flag; //采样标志
uint32_t adc_sample_timer; //采样时间
}ADC_sample_t; ADC_sample_t m_ADC; #if Y_and_N_calibrate_change
void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
switch(p_event->type)
{
case NRF_DRV_SAADC_EVT_CALIBRATEDONE:
m_ADC.offset_calibrate_flag = true;//校准完成回调
break; default:
break;
}
} /*确保要在ADC模块初始化完成后调用校准函数*/
void adc_offset_calibrate(void)
{
ret_code_t err_code; /*检查是否使能的ADC,如果没有就直接返回,不能进行校准*/
if(!nrf_saadc_enable_check())
{
NRF_LOG_INFO("Cannot be calibrated without ADC enabled");
return;
}
err_code = nrf_drv_saadc_calibrate_offset();
APP_ERROR_CHECK(err_code); while(!m_ADC.offset_calibrate_flag)
{
__WFE();
};
NRF_LOG_INFO("End of calibration");
} #endif void timer_handler(nrf_timer_event_t event_type, void * p_context)
{
#if Y_and_N_calibrate_change
static uint8_t counter=0;
#endif
switch(event_type)
{
case NRF_TIMER_EVENT_COMPARE0:
#if Y_and_N_calibrate_change
if(counter<10)
{
counter++;
#endif
m_ADC.adc_sample_flag = true;
NRF_LOG_INFO("ADC sample start");
#if Y_and_N_calibrate_change
}
else
{
counter=0;
/*定时时间到开始校验*/
NRF_LOG_INFO("offset starting....");
nrf_drv_timer_disable(&m_timer);
/*如果有转化,终止转化准备开始校验*/
nrfx_saadc_abort();
/*校准标志位*/
m_ADC.offset_calibrate_flag =false;
}
#endif
break;
default:
break;
} } void saadc_init(void)
{
/*本次配置为使用了单端模式,使用了AIN0通道*/
ret_code_t err_code;
nrf_saadc_channel_config_t channel_config =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0); /*ADC采样配置,配置为12bit,不使用过采样,中断优先级,低功耗模式*/
nrf_drv_saadc_config_t config;
config.resolution = NRF_SAADC_RESOLUTION_12BIT;
config.oversample = NRF_SAADC_OVERSAMPLE_DISABLED;
config.low_power_mode = NRFX_SAADC_CONFIG_IRQ_PRIORITY;
config.low_power_mode = NRFX_SAADC_CONFIG_LP_MODE;
#if Y_and_N_calibrate_change
/*nrf_drv_saadc_init的第一个参数为NULL的话将使用默认配置(NRFX_SAADC_DEFAULT_CONFIG),这将使用10bit的分辨率*/
err_code = nrf_drv_saadc_init(&config, saadc_callback);
APP_ERROR_CHECK(err_code);
#else
/*nrf_drv_saadc_init的第一个参数为NULL的话将使用默认配置(NRFX_SAADC_DEFAULT_CONFIG),这将使用10bit的分辨率*/
err_code = nrf_drv_saadc_init(&config, NULL);
APP_ERROR_CHECK(err_code);
#endif
/*配置AIN0通道*/
err_code = nrf_drv_saadc_channel_init(0, &channel_config);
APP_ERROR_CHECK(err_code); } void offset_timer_init(void)
{
ret_code_t err_code; nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32; err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
APP_ERROR_CHECK(err_code); /* 通道0作为采样定时*/
uint32_t adc_sample_ticks = nrf_drv_timer_ms_to_ticks(&m_timer, m_ADC.adc_sample_timer);
nrf_drv_timer_extended_compare(&m_timer,
NRF_TIMER_CC_CHANNEL0,
adc_sample_ticks,
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
true); nrf_drv_timer_enable(&m_timer);
} void adc_sample(void)
{
m_ADC.adc_sample_flag = false;
/*采样通道1的值并给到 test_value*/
nrfx_saadc_sample_convert(0,&test_value);
/*
根据数据手册有如下的转换公式: V =[V(P)-V(N)]* GAIN / reference *2^(resolution - m)
V : 采样的实际电压
V(P): 使用采用函数获取到的值
V(N): 使用采用函数获取到的值(只在差分采样才有,如果是单端采样,这为0)
GAIN: 增益值,本例程看channel_config,配置为1/6
reference:参考电压,可以为0.6V的内部电压,或者为VCC/4(四分之一的VCC),
本例程看channel_config(NRF_SAADC_REFERENCE_INTERNAL),配置为0.6V
resolution:采样精度,
m: 单端输入为0,差分输入为1
*/ V_test=test_value* 3.6/4096;
//串口查看打印值
NRF_LOG_INFO("%d",test_value);
NRF_LOG_INFO("V=" NRF_LOG_FLOAT_MARKER "\r\n", NRF_LOG_FLOAT(V_test));
NRF_LOG_FLUSH();
} /**
* @brief Function for main application entry.
*/
int main(void)
{
ret_code_t err_code; /*添加了log*/
err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT(); /*清零实体*/
memset(&m_ADC,0,sizeof(m_ADC));
/*设置轮训采样时间,当前为1s*/
m_ADC.adc_sample_timer = 1000; saadc_init(); /*开启定时器,启动采样*/
offset_timer_init(); NRF_LOG_INFO("adc test");
while (1)
{
if(m_ADC.adc_sample_flag)
{
adc_sample();
}
#if Y_and_N_calibrate_change
if(!m_ADC.offset_calibrate_flag)
{
adc_offset_calibrate();
/* 校准过程中停止采样,校准完毕后开始采样 */
nrf_drv_timer_enable(&m_timer);
}
#endif
NRF_LOG_FLUSH();
}
}

三、对比

直接对GND进行采样,对比采样偏差的大小。

1、不添加校准:

Y_and_N_calibrate_change 为 0时:

可以看到对于我的板载芯片偏差基本都在-10以上,部分芯片偏差可能更大如-15,-20或者以上,如果在大批量时出现有部分芯片采样值不对,那么可以添加校准,说不定问题就解决了。

2、添加校准:

Y_and_N_calibrate_change 为 1 时:

可以看到,误差减小了,经过上面测试在nrf52系列使用ADC时校准是很有必要的。

结论:

1、因为校准只会减少误差,并不是把误差消除,所以对于在实际应用中如果有些芯片增益误差达到了3%的临界值,那么就算添加了校准,可能也只校准到了2%,比如12bit的分辨率,满值是4096,那么极限误差是±90,校准后误差还可能是±60,这个时候只能说软件处理了。

2、校准只能在初始化ADC模块,但是在采样开始前,或者结束后进行,所以在代码中进行了是否采样和是否使能了ADC模块的判断。

3、ADC精度还可能和晶振的精度有关,在有些时候晶振偏差过大,也会都在ADC采样偏差大

nordic的nrf52系列——ADC在使用时如何校准增益误差(基于SDK)的更多相关文章

  1. Nordic nRF52系列/nRF5340硬件设计(一)选型及原理图设计

    Nordic 的BLE系列芯片从第一代的nRF51系列,到第二代的nRF52系列,发展到目前最新的第三代的nRF5340.目前市场中使用最多的nRF52系列一共有七款芯片,它们是:nRF52805.n ...

  2. nRF52系列来袭,Nordic的低功耗蓝牙方案大有可为

      坐落在北欧的挪威不像他的邻居芬兰那样,可以先后依靠NOKIA和愤怒的小鸟在世界科技界享有盛名.在一般人看来,挪威除了一个逐渐式微的Opera浏览器以外,并没有更多拿得出手的科技企业.而事实证明这只 ...

  3. nordic——nrf52系列SWD设置回读保护

    在开发时可能需要回读保护功能,在产品出厂后这个功能可以让你的代码更加安全,无法用SEGGER或者其余方式读取你的代码HEX文件,也就是禁用SWD下载接口.但是SWD锁住了,还想使用(从新下载代码)也是 ...

  4. nRF52系列——nRF52832来袭

    nRF52系列——nRF52832来袭 Nordic凭借着在无线技术的数十年深耕,推出第一个μBlue芯片-- nRF8001.其低功耗等特性在当时吸引了无数厂商的目光,并将这产品应用到多个领域,再之 ...

  5. NRF52840相对于之前的NRF52系列、NRF51系列增加了什么功能

    现在广大客户的蓝牙采用NORDIC越来越多了,NORDIC一直在不断进行技术改进更好的满足市场需求 推出了新款NRF52840.NRF52840更为先进些,支持的功能也多点,比如IEEE802.15. ...

  6. Nordic nRF51/nRF52开发环境搭建

    本文将详述Nordic nRF51系列(包括nRF51822/nRF51802/nRF51422等)和nRF52系列(包括nRF52832/nRF52810/nRF52840)开发环境搭建. 1. 强 ...

  7. Nordic nRF51/nRF52开发流程说明

    Nordic nRF51系列包括nRF51822/nRF51422/nRF51802等芯片,nRF52系列包括nRF52832/nRF52840/nRF52810等芯片,硬件工程师可以按照如下流程去评 ...

  8. Cookie使用时需要注意个数及大小限制

    各浏览器对Cookie有一定的限制,在使用时需要格外注意. 各浏览器之间对cookie的不同限制:   IE6.0 IE7.0/8.0/9.0+ Opera FF Safari Chrome cook ...

  9. EntityFrameWork 使用时碰到的小问题

    EntityFrameWork 使用时碰到的小问题 1,在使用orm访问数据库的相目里,也要引用EntityFrameWork.dll,否则无法使用orm 否则,编译错误 错误 5 "Sys ...

  10. MySQL 安装和启动服务,“本地计算机 上的 MySQL 服务启动后停止。某些服务在未由其他服务或程序使用时将自动停止。”

    MySQL 安装和启动服务,以及遇到的问题 MySQL版本: mysql-5.7.13-winx64.zip (免安装,解压放到程序文件夹即可,比如 C:\Program Files\mysql-5. ...

随机推荐

  1. 如何通过Graph+AI的方法打造高精度风控模型

    简介: 阿里云图智能平台在金融行业已经帮助银行.保险等领域客户构建了金融风控.商品推荐.循环担保检测.异常指标监控.违规团伙挖掘等场景,通过穿透行业应用场景,帮助客户基于多维数据做出精准决策. > ...

  2. WPF 通过 Windows Template Studio 快速搭建项目框架和上手项目

    本文对新手友好.在咱开始一个新项目的时候,可以利用 Windows Template Studio 快速搭建整个项目的框架.搭建出来的框架比较现代化,适合想要快速开发一个项目的大佬使用,也适合小白入门 ...

  3. 2019-4-12-VisualStudio-好用插件集合

    title author date CreateTime categories VisualStudio 好用插件集合 lindexi 2019-04-12 09:37:47 +0800 2019-0 ...

  4. Fastbin attack&&Double free和Unsortbin leak的综合使用

    Fastbin attack&&Double free和Unsortbin leak的综合使用 今天做一个综合题目,包括利用Fastbin attack实现多指针指向一个地址,以及利用 ...

  5. vue框架keepAlive缓存的坑

    页面跳转顺序index=>detail2=>detail3(三个页面不是单独请求数据,后两个页面是第一个页面数据的传递) detail2页面与methods同级: beforeRouteL ...

  6. All in One:Prometheus 多实例数据统一管理最佳实践

    01 引言 Prometheus 作为目前最主流的可观测开源项目之一,已经成为云原生监控的事实标准,被众多企业广泛应用.在使用 Prometheus 的时候,我们经常会遇到全局视图的需求,但是数据确分 ...

  7. ansible(2)--ansible的安装与配置文件管理

    目录 1 ansible的安装 1.1 yum安装 1.2 pip安装 2 ansible相关文件 2.1 ansible配置文件 2.2 ansible配置文件的优先级 2.3 ansible的主机 ...

  8. Git基本操作命令大全

    一.全局配置命令 ## 配置级别: –local(默认,高级优先):只影响本地仓库 –global(中优先级):只影响所有当前用户的git仓库 –system(低优先级):影响到全系统的git仓库 # ...

  9. postgresql性能优化2:sql语句和缓存配置

    1.看执行计划 EXPLAIN, 此命令用于查看SQL的执行计划 总的来说sql的执行计划是一个树形层次结构, 一般来说阅读上遵从层级越深越优先, 同一层级由上到下的原则. 来跟着铁蛋老师读: 层级越 ...

  10. ElasticSearch使用经验总结

    ElasticSearch总结 1.ElasticSearch的查询原理 Elasticsearch底层使用的Lucene的倒排索引技术来实现比关系型数据库更快的过滤的.所以要想了解Es的擦查询原理, ...