nordic的nrf52系列——ADC在使用时如何校准增益误差(基于SDK)
简介: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)的更多相关文章
- Nordic nRF52系列/nRF5340硬件设计(一)选型及原理图设计
Nordic 的BLE系列芯片从第一代的nRF51系列,到第二代的nRF52系列,发展到目前最新的第三代的nRF5340.目前市场中使用最多的nRF52系列一共有七款芯片,它们是:nRF52805.n ...
- nRF52系列来袭,Nordic的低功耗蓝牙方案大有可为
坐落在北欧的挪威不像他的邻居芬兰那样,可以先后依靠NOKIA和愤怒的小鸟在世界科技界享有盛名.在一般人看来,挪威除了一个逐渐式微的Opera浏览器以外,并没有更多拿得出手的科技企业.而事实证明这只 ...
- nordic——nrf52系列SWD设置回读保护
在开发时可能需要回读保护功能,在产品出厂后这个功能可以让你的代码更加安全,无法用SEGGER或者其余方式读取你的代码HEX文件,也就是禁用SWD下载接口.但是SWD锁住了,还想使用(从新下载代码)也是 ...
- nRF52系列——nRF52832来袭
nRF52系列——nRF52832来袭 Nordic凭借着在无线技术的数十年深耕,推出第一个μBlue芯片-- nRF8001.其低功耗等特性在当时吸引了无数厂商的目光,并将这产品应用到多个领域,再之 ...
- NRF52840相对于之前的NRF52系列、NRF51系列增加了什么功能
现在广大客户的蓝牙采用NORDIC越来越多了,NORDIC一直在不断进行技术改进更好的满足市场需求 推出了新款NRF52840.NRF52840更为先进些,支持的功能也多点,比如IEEE802.15. ...
- Nordic nRF51/nRF52开发环境搭建
本文将详述Nordic nRF51系列(包括nRF51822/nRF51802/nRF51422等)和nRF52系列(包括nRF52832/nRF52810/nRF52840)开发环境搭建. 1. 强 ...
- Nordic nRF51/nRF52开发流程说明
Nordic nRF51系列包括nRF51822/nRF51422/nRF51802等芯片,nRF52系列包括nRF52832/nRF52840/nRF52810等芯片,硬件工程师可以按照如下流程去评 ...
- Cookie使用时需要注意个数及大小限制
各浏览器对Cookie有一定的限制,在使用时需要格外注意. 各浏览器之间对cookie的不同限制: IE6.0 IE7.0/8.0/9.0+ Opera FF Safari Chrome cook ...
- EntityFrameWork 使用时碰到的小问题
EntityFrameWork 使用时碰到的小问题 1,在使用orm访问数据库的相目里,也要引用EntityFrameWork.dll,否则无法使用orm 否则,编译错误 错误 5 "Sys ...
- MySQL 安装和启动服务,“本地计算机 上的 MySQL 服务启动后停止。某些服务在未由其他服务或程序使用时将自动停止。”
MySQL 安装和启动服务,以及遇到的问题 MySQL版本: mysql-5.7.13-winx64.zip (免安装,解压放到程序文件夹即可,比如 C:\Program Files\mysql-5. ...
随机推荐
- 阿里云架构师梁旭:MES on 云盒,助力客户快速构建数字工厂
简介: 四大优势:一站式交付.业务低延时.数据本地驻留.多工厂统一运维 2022年5月18日,在"云上数字工厂与中小企业数字化转型创新论坛"暨"鼎捷MES & 阿 ...
- 云效DevOps实践-如何基于云效实现测试自动化集成和分析
简介: 对于现代软件研发来说,持续.快速.高质量.低风险地交付需求特性,是业务对研发的主要诉求.而要做到这一点,除了要有良好的架构设计.卓越的工程能力,快速可靠的测试反馈也是其非常重要的一环,达到这一 ...
- Spring Boot Serverless 实战系列“架构篇” | 光速入门函数计算
简介:如何以 Serverless 的方式运行 Spring Boot 应用? 作者:西流(阿里云函数计算专家) Spring Boot 是基于 Java Spring 框架的套件,它预装了 S ...
- 为什么Spring仍然会是云原生时代最佳平台之一?
简介: 基于Java语言的Spring生态,还能否适应新的开发方式,比如Cloud Native.Serverless.Faas等,它还会是云原生时代的最佳平台的选择吗?本文将从5个角度来为你分析一下 ...
- PolarDB-X 2.0:使用一个透明的分布式数据库是一种什么体验
简介: 透明分布式,是PolarDB-X即将发布的能力,它能让应用在使用PolarDB-X的过程中,犹如使用单机数据库一般的体验.与传统的中间件类型的"分布式数据库"相比,有了透明 ...
- [Mobi] MacOS 安装设置 ADB (Android Dedug Bridge)
adb (Android Dedug Bridge) 是 Google 提供的一个工具,用于调试 Android 应用程序和系统的各个部分. 在 MacOS 平台,调试安卓应用 首先需要安装 Andr ...
- [PHP] 浅谈 Laravel auth:api 不同驱动 token 和 passport 的区别
token 驱动使用 TokenGuard 用传递的值去用户表中查询 member_token 字段的值,看是否有匹配的. 服务端需要在用户表 member_token 字段中存储 access_to ...
- WPF dotnet core 的 Blend SDK Behaviors 库
之前版本是通过安装 Blend SDK 支持 Behaviors 库的,但是这个方法都是通过引用 dll 的方式,不够优雅.在升级到 dotnet core 3.0 的时候就需要使用 WPF 官方团队 ...
- Canvas简历编辑器-我的剪贴板里究竟有什么数据
Canvas图形编辑器-我的剪贴板里究竟有什么数据 在这里我们先来聊聊我们究竟应该如何操作剪贴板,也就是我们在浏览器的复制粘贴事件,并且在此基础上聊聊我们在Canvas图形编辑器中应该如何控制焦点以及 ...
- Gem离线包安装
Gem离线包安装 项目环境 以 rest-client 为例 本地如果是rails项目环境: ruby '2.7.0' gem 'rails', '~> 6.0.3', '>= 6.0.3 ...