一、开篇

Write programs that do one thing and do it well ~~~~~

发现非常多人关于使用CC2640/CC2650的过程中比較难以应对的问题就是实现ADC。为了方便大家,所以有了本篇博客,都是一些自己的理解。不正确的地方请大家指正。

TI的这款新品上市不久,还有须要须要更新的地方,尤其是以往以其文档多为优势。而现在到了CC26xx这却差点儿没什么可參考的文档了,大家就等等吧。肯定会越来越完好的。

本篇主要介绍怎样使用TI官方给的driverlib实现ADC的使用,SCS也能控制ADC的实现,可是这个过于复杂。生产的代码也比較难以理解,所以还是使用driverlib吧。

三、试验平台

Software Version:BLE_STACK_CC26XX_2.1.0

Hardware Version:CC2640/CC2650

IDE:IAR 7.40

四、基础知识

1) ADC模数转换器,顾名思义也就是输入模拟量输出数字量。我们感知世界上的不论什么事物都是感知的模拟量,可是相应于CPU而言仅仅能识别非0即1的数字量,所以产生了ADC,ADC的实现过程中基本的两个过程就是採用保持和量化(感觉在讲废话)。在外设接口中ADC属于较难得部分了,关于ADC的一些基本概念还是比較多的,当中INL和DNL须要特别注意一下(Ps:我旁边坐了一位专门研究ADC的beauty,是她讲的。平时实验室关于ADC不懂得都找她解决)。由于本篇博文主要是解说关于CC26xx的ADC实现的,它的ADC是内部集成的12位ADC,採样速率高达200Ks/s,所以本篇博文不再具体介绍在ADC芯片选型方面要考虑的參数了,可是本篇涉及的參数肯定是选型时须要考虑的。

2)以下结合CC26xx的Datasheet介绍一些关于ADC的基本參数,下图是ADC在整个IC内部的位置。由下图可知CC26xx的ADC在RF core内部。由M0核控制,在实现ADC时能够使用官方的driverlib也能够使用官方特有的SCS平台去控制实现ADC的基本功能。CC26xx的Sensor
controller的功能还是相当强大的,可惜我还不会使用。在低功耗中使用UART就是靠的它用流控控制的。

3)例如以下图中所看到的。因为INL和DNL(详细含义去百度吧)以及offset的原因,在採集数据时就会存在一个偏差。这个是不可避免的,这个採集数据的偏差还是自行软件处理吧,内部ADC的功耗还是比較低的。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" align="middle" alt="">

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" align="middle" alt="">

五、怎样在project中实现ADC

1、首先你要知道有一个driverlib库的存在。这个里面TI官方给出了使用时调用的API,此处就不在赘述了。路径太长不方便写。

2、然后CC26xx芯片不是全部的IO口都能够作为的ADC接口使用的。官方在TRM中也给出了介绍。例如以下图。

3、include库文件

在simpleBLEPeripheral.c文件里加入例如以下头文件。

#include <driverlib/aux_adc.h>
#include <driverlib/aux_wuc.h>

4、配置ADC(最关键的一步)

        代码实现部分,放在simpleBLEPeripheral.c就可以。ADC不须要像使用UART那样再去配置IO口映射。

//*****************************************************************************
//! \brief Selects internal or external input for the ADC
//! Note that calling this function also selects the same input for AUX_COMPB.
//! \param input
//! Internal/external input selection:
//! - \ref ADC_COMPB_IN_VDD1P2V
//! - \ref ADC_COMPB_IN_VSSA
//! - \ref ADC_COMPB_IN_VDDA3P3V
//! - \ref ADC_COMPB_IN_AUXIO7 //DIO9
//! - \ref ADC_COMPB_IN_AUXIO6 //DIO8
//! - \ref ADC_COMPB_IN_AUXIO5 //DIO7
//! - \ref ADC_COMPB_IN_AUXIO4 //DIO6
//! - \ref ADC_COMPB_IN_AUXIO3 //DIO5
//! - \ref ADC_COMPB_IN_AUXIO2
//! - \ref ADC_COMPB_IN_AUXIO1
//! - \ref ADC_COMPB_IN_AUXIO0
//*****************************************************************************
uint32_t AdcOneShotRead(uint8_t auxIo)
{
uint32_t turnedOnClocks = 0;
//////////// Config clock/////////////////////
// Only turn on clocks that are not already enabled. Not thread-safe, obviously.
turnedOnClocks |= AUXWUCClockStatus(AUX_WUC_ADC_CLOCK) ? 0 : AUX_WUC_ADC_CLOCK;
turnedOnClocks |= AUXWUCClockStatus(AUX_WUC_ADI_CLOCK) ? 0 : AUX_WUC_ADI_CLOCK;
turnedOnClocks |= AUXWUCClockStatus(AUX_WUC_SOC_CLOCK) ? 0 : AUX_WUC_SOC_CLOCK;
// Enable clocks and wait for ready
AUXWUCClockEnable(turnedOnClocks);
while(AUX_WUC_CLOCK_OFF == AUXWUCClockStatus(turnedOnClocks));
/////// Seclect auxIO /////////////
AUXADCSelectInput(auxIo);
////////// Enable ///////////
AUXADCEnableSync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US, AUXADC_TRIGGER_MANUAL);
delay(10);
//Scaling disable
AUXADCDisableInputScaling();
AUXADCGenManualTrigger(); // Trigger sample
uint32_t adcValue = AUXADCReadFifo();
AUXADCDisable();//Power_Saving
return adcValue;
}

在上述实现代码中所涉及的一些问题,讲述一下自己的理解,假设不过为了实现ADC功能那么以下能够不用看了,以下讲的比較细了。

1)首先是ADC使能函数

跟踪查看函数原型例如以下。

//*****************************************************************************
// Enables the ADC for synchronous operation
//*****************************************************************************
void AUXADCEnableSync(uint32_t refSource, uint32_t sampleTime, uint32_t trigger)
{
// Enable the ADC reference, with the following options:
// - SRC: Set when using relative reference
// - REF_ON_IDLE: Set when using fixed reference and sample time < 21.3 us
uint8_t adcref0 = refSource | ADI_4_AUX_ADCREF0_EN_M;
if (!refSource && (sampleTime < AUXADC_SAMPLE_TIME_21P3_US)) {
adcref0 |= ADI_4_AUX_ADCREF0_REF_ON_IDLE_M;
}
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADCREF0, adcref0); // Enable the ADC clock
HWREG(AUX_WUC_BASE + AUX_WUC_O_ADCCLKCTL) = AUX_WUC_ADCCLKCTL_REQ_M;
while (!(HWREG(AUX_WUC_BASE + AUX_WUC_O_ADCCLKCTL) & AUX_WUC_ADCCLKCTL_ACK_M)); // Enable the ADC data interface
if (trigger == AUXADC_TRIGGER_MANUAL) {
// Manual trigger: No need to configure event routing from GPT
HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = AUX_ANAIF_ADCCTL_START_SRC_NO_EVENT0 | AUX_ANAIF_ADCCTL_CMD_EN;
} else {
// GPT trigger: Configure event routing via MCU_EV to the AUX domain
HWREG(EVENT_BASE + EVENT_O_AUXSEL0) = trigger;
HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = AUX_ANAIF_ADCCTL_START_SRC_MCU_EV | AUX_ANAIF_ADCCTL_CMD_EN;
}
// Release reset and enable the ADC
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC0, ADI_4_AUX_ADC0_EN_M | ADI_4_AUX_ADC0_RESET_N_M |
(sampleTime << ADI_4_AUX_ADC0_SMPL_CYCLE_EXP_S));
}

用法:AUXADCEnableSync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US, AUXADC_TRIGGER_MANUAL)。比較重要的就是第一和第二个參数。

当中第一个參数AUXADC_REF_FIXED是4.3V,关于这个4.3的由来,TI一直没有给相关的介绍。我认为应该是由电源端引入然后经过内部的boost电路升压到4.3V作为这个參考电压的。当中还有几个能够作为參考电压的,我没有试过。仅仅是用了AUXADC_REF_FIXED这一个,不敢妄下结论,大家能够去实測一下。第二个參数就是所谓的採样时间,其倒数就是採样频率,由于这套代码配置是使用的同步採样(Sync)。所以採样频率的配置就不能像用单独的用timer去尾随实现非同步採样(Async)产生的採样频率多了。仅仅有官方给的几个能够用,感觉这个影响不大。接近即可了,例如以下。

*****************************************************************************
// Defines for ADC sampling type for synchronous operation.
*****************************************************************************
#define AUXADC_SAMPLE_TIME_2P7_US 3
#define AUXADC_SAMPLE_TIME_5P3_US 4
#define AUXADC_SAMPLE_TIME_10P6_US 5
#define AUXADC_SAMPLE_TIME_21P3_US 6
#define AUXADC_SAMPLE_TIME_42P6_US 7
#define AUXADC_SAMPLE_TIME_85P3_US 8
#define AUXADC_SAMPLE_TIME_170_US 9
#define AUXADC_SAMPLE_TIME_341_US 10
#define AUXADC_SAMPLE_TIME_682_US 11
#define AUXADC_SAMPLE_TIME_1P37_MS 12
#define AUXADC_SAMPLE_TIME_2P73_MS 13
#define AUXADC_SAMPLE_TIME_5P46_MS 14
#define AUXADC_SAMPLE_TIME_10P9_MS 15

假设使用使用非同步採样(Async)的话。CC26xx就不能进入standby状态了,官方解释例如以下图(应该没有理解错吧)。

2)Scaling disable

作用就是缩小ADC的IO口的採样电压的范围。disable以后最大输入电压1.49就达到满量程了(实測),所以这样能够提升单位电压内的分辨率(1.49/4096)。

函数原型:

//*****************************************************************************
// Disables scaling of the ADC input
//*****************************************************************************
// Register: ADI_4_AUX_O_ADC1
// Field: [0] SCALE_DIS
// Disable capacitive input voltage scaling. Should only be 1 for test
// purposes.
// 0: ADC input is scaled from 0-4.3V to 0-1.4V internally
// 1: ADC input is not scaled. Do not exceed 1.4V on input
#define ADI_4_AUX_ADC1_SCALE_DIS 0x00000001
#define ADI_4_AUX_ADC1_SCALE_DIS_BITN 0
#define ADI_4_AUX_ADC1_SCALE_DIS_M 0x00000001
#define ADI_4_AUX_ADC1_SCALE_DIS_S 0 */
//*****************************************************************************
void
AUXADCDisableInputScaling(void)
{
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC1, ADI_4_AUX_ADC1_SCALE_DIS_M);
}

六、关于精度和測试结果

        TI的 R&D给出了一份他们在实验的測试结果,大家能够依照这个作为比較,实測和这份数据差点儿相同。

七、附加题(你肯定懂得它的含义)

        什么?不知道“附加题”的意义何在?

那你肯定没经历过高考的洗礼~~~~

原本想再单独写一篇博文介绍关于供电电压採集的。可是感觉比較简单就和ADC放在一起讲吧,它俩比較接近。首先,非常多project师在做类似于手环、心率计、HCG等等时可能都须要使用到芯片的ADC功能。又想实时的获取供电电压。可是内部ADC的数量又是有限的。怎样实现多路使用ADC呢,大家首先想到的应该就是切换使用内部ADC,可是在一路正在使用的时候直接切换掉是不是对正在ADC採集的数据导致错误呢。或者说这个切换的时间怎样把握呢。所以CC26xx有了这个Battery
Monitor的功能。让project师測量供电电压时不再占用外部adc_io接口。

关于IO口重映射是怎样实现的,我也不了解(who knows? tell me.),反正认为比較牛掰,用起来很顺手,尤其是在layout布局布线的时候。个人臆測可能是使用电子开关之类的方法切换的吧,电子开关的功耗也很小,搞硬件的就是牛掰。

为什么这些高科技都是国外的。那么有哪些是“黑科技”掌握在国人手里呢?例如以下就是。国人之骄傲~~~

好吧,废话不多说。

关于供电电压的測试问题,这个能够不使用ADC測试了,CC26xx内部有专门測试芯片供电电压的(还有測试芯片温度的,不再赘述測试温度)。

1、代码实现

在simpleBLEPeripheral.c文件里加入例如以下头文件。

#include <driverlib/aon_batmon.h>

在须要的地方使用例如以下代码获取当前的电池电压。

 //BAT Monitor
AONBatMonEnable();
// <int.frac> format size <3.8> in units of volt
//返回值32位中[10:8]代表INT 。 [7:0]代表FRAC ,对于小数部分,一个单位代表0.00390625v,小数部分的分辨率仅仅有50mV(TYP)
batval = AONBatMonBatteryVoltageGet();

AONBatMonBatteryVoltageGet()的函数原型是:

__STATIC_INLINE uint32_t
AONBatMonBatteryVoltageGet(void)
{
uint32_t ui32CurrentBattery;
ui32CurrentBattery = HWREG(AON_BATMON_BASE + AON_BATMON_O_BAT);
// Return the current battery voltage measurement.
return (ui32CurrentBattery >> AON_BATMON_BAT_FRAC_S);
}

返回值是依据不同的位代表芯片供电电压的整数部分和小数部分的,具体介绍例如以下。

//*****************************************************************************
// Register: AON_BATMON_O_BAT
//*****************************************************************************
// Field: [10:8] INT
// Integer part:
// 0x0: 0V + fractional part
// ...
// 0x3: 3V + fractional part
// 0x4: 4V + fractional part
#define AON_BATMON_BAT_INT_M 0x00000700
#define AON_BATMON_BAT_INT_S 8
// Field: [7:0] FRAC
// Fractional part, standard binary fractional encoding.
// 0x00: .0V
// ...
// 0x20: 1/8 = .125V
// 0x40: 1/4 = .25V
// 0x80: 1/2 = .5V
// ...
// 0xA0: 1/2 + 1/8 = .625V
// ...
// 0xFF: Max
#define AON_BATMON_BAT_FRAC_M 0x000000FF
#define AON_BATMON_BAT_FRAC_S 0

測试结果:仅仅測试了0.1V的电压变化值。能够精确获取到。

八、结论

实在不知道写什么了,还是打个广告吧。

学挖掘机技术哪家强?

[BLE]CC2640之ADC功能实现和供电电压的採集的更多相关文章

  1. mtools 是由MongoDB 官方工程师实现的一套工具集,可以很快速的日志查询分析、统计功能,此外还支持本地集群部署管理.

    mtools 是由MongoDB 官方工程师实现的一套工具集,可以很快速的日志查询分析.统计功能,此外还支持本地集群部署管理 https://www.cnblogs.com/littleatp/p/9 ...

  2. BLE各版本新功能总结

    文章转载自:http://www.sunyouqun.com/2017/04/ 协议发布时间 协议版本 2016/12 Bluetooth 5 2014/12 Bluetooth 4.2 2013/1 ...

  3. row_number() over()分组排序功能 partition by 用于给结果集分组

    select * from ( select row_number() over(partition by Gid order by Gid ASC) as RowN, * from( select ...

  4. CesiumLab V1.1 新功能 (免费Cesium处理工具集)

    Cesiumlab 自从上周(3月20日)发布之后,赢得小伙伴一致好评. 本周继续推出重大更新: 建筑物矢量数据 转 3dtiles,  建筑物矢量数据 转 3dtiles,  建筑物矢量数据 转 3 ...

  5. 开源 java CMS - FreeCMS2.3 Web页面信息採集

    原文地址:http://javaz.cn/site/javaz/site_study/info/2015/23312.html 项目地址:http://www.freeteam.cn/ Web页面信息 ...

  6. 开源 java CMS - FreeCMS2.1公布

    项目地址:http://www.freeteam.cn/ FreeCMS商业版V2.1更新功能 1.web页面信息採集:通过简单配置就可以抓取目标网页信息,支持增量式採集.keyword替换.定时採集 ...

  7. C++开发人脸性别识别教程(19)——界面美化

    在这篇博文中将完毕<C++开发人脸性别识别>的收尾工作.主要内容分为两部分:加入视频暂定功能.界面规范化. 一 视频暂停功能 严格来说这个视频暂定功能算是视频人脸性别识别的一个遗留问题,本 ...

  8. 日志系统之基于Zookeeper的分布式协同设计

    近期这段时间在设计和实现日志系统.在整个日志系统系统中Zookeeper的作用非常重要--它用于协调各个分布式组件并提供必要的配置信息和元数据.这篇文章主要分享一下Zookeeper的使用场景. 这里 ...

  9. ADC自动转接功能Lua实现

    一.背景介绍: 虽然使用Mod_fifo和mod_callcenter可以做呼叫中心的应用,但在实现应用中,这两个模块很难客制化需求,再此我用Lua实现了5路客服(1000-1004),一个呼叫中心号 ...

随机推荐

  1. 【mysql】配置 选项文件

    在Windows中,MySQL程序从以下文件读取启动选项: 文件名 目的 WINDIR\my.ini 全局选项 C:\my.cnf 全局选项 INSTALLDIR\my.ini 全局选项 defaul ...

  2. python爬虫入门七:pymysql库

    我们使用python爬取得到的数据,有时候会数据量特别大,需要存入数据库. 需要注意的是,MySQL是一种关系型数据库管理系统,利用MySQL可以对数据库进行操作,而MySQL并不是一个数据库. 而p ...

  3. Lex与Yacc学习(七)之环境配置另一种方式

    必备工具 flex-2.5.4a-1.exe   和  bison-2.4.1-setup.exe   以及 cygwin2.738 的安装文件,下载地址 http://download.csdn.n ...

  4. 循环链表的C风格实现(单向)

    头文件: #ifndef _CIRCLELIST_H_ #define _CIRCLELIST_H_ typedef void CircleList; // typedef struct _tag_C ...

  5. sublime text 3搭建python 的ide

    感谢大佬-->原文链接 1. 打开Sublime text 3 安装package control Sublime Text 3 安装Package Control 2. 安装 SublimeR ...

  6. Repo command reference

    Repo command reference In this document init sync upload diff download forall prune start status Rep ...

  7. python基础学习笔记——文件操作

    文件操作 初始文件操作 使用Python来读写文件是非常简单的操作,我们使用open()函数来打开一个文件,获取到文件句柄,然后通过文件句柄就可以进行各种各样的操作了 根据打开方式的不同能够执行的操作 ...

  8. Debian7安装msf

      安装metasploit curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templa ...

  9. WordPress添加前台注册功能

    一.添加注册表单 1.首先在当前主题的目录下新建一个php文件,命名为reg-page.php,然后将page.php中的所有代码复制到reg-page.php中: 2.删除reg-page.php开 ...

  10. 洛谷P2522 - [HAOI2011]Problem b

    Portal Description 进行\(T(T\leq10^5)\)次询问,每次给出\(x_1,x_2,y_1,y_2\)和\(d\)(均不超过\(10^5\)),求\(\sum_{i=x_1} ...