cc2650 例程adc应该放到主函数的哪个地方

CC2541蓝牙学习——ADC - 推酷
CC2541蓝牙学习——ADC
CC2541的ADC支持多达14位的模拟数字转换与高达12位的有效位数。它包括一个模拟多路转换器,具有多达8个各自可独立配置的通道,一个参考电压发生器。转换结果通过DMA写入存储器。还具有若干运行模式。
ADC主要特性如下:
可选的抽取率,设置了7~12位的分辨率;
8个独立输入通道,可接受单端或差分信号;
参考电压可选为内部,外部单端,外部差分,或AVDD5;
产生中断请求;
转换结束时的DMA触发;
温度传感器输入;
电池测量功能。
P0引脚上的信号可以作为ADC输入来使用。在下面,这些引脚叫做AIN0—AIN7引脚,输入脚AIN0—AIN7与ADC连接。
输入脚可配置成单端或差动输入。如选择差动输入,包含成对输入AIN0-AIN1,AIN2-AIN3,AIN4-AIN5和AIN6-AIN7;注意这些引脚既不能加载负电压,也不能加载大于VDD的电压。
除了输入脚AIN0-AIN7外,片上的温度传感器也可以用来作为ADC温度测量的输入。如要实现这个功能,需设置寄存器TR0.ADCTM和ATEST.ATESTCTRL。
单端输入AIN0至AIN7可代表通道号0至7,通道号8至11分别代表差动输入AIN0-AIN1,AIN2-AIN3,AIN4-AIN5,AIN6-AIN7;通道12表示GND,通道13表示温度传感器,通道15表示AVDD5/3。这些值在ADCCON2.SCH和ADCCON3.SCH中设置。
我们看到ADCCON2和ADCCON3这两个寄存器的定义基本相同,但是用法不同, ADCCON2用于ADC序列转换的配置,而ADCCON3则用于单个ADC通道的配置 。所谓ADC序列就是多个ADC通道按照次序分别转换。注意: 不是同时转换的,从图1我们也可以看出,ADC的模拟输入接一个选择器,同一时刻只能选择一个通道接入进行ADC转换 。
如果选择片上的温度传感器作为ADC温度测量的输入,则需要通过配置寄存器TR0和ATEST来获得片上温度,不过这个温度测量误差很大,我们一般不用,这里也就不给出例程了。
启用片内温度采集配置寄存器:
1 TR0 |= 0x01;
2 ATEST |= 0x01;
1、ADC序列转换
ADC序列转换无需CPU的参与,ADC能够完成一个序列的转换,并通过DMA把结果写入内存。
寄存器APCFG影响转换序列,来自I/O引脚的8位模拟输入不一定是程序设置的模拟输入。如某一通道是序列的一部分,但在APCFG中相应模拟输入是禁止的,那此通道将被跳过。当使用差动输入时,两个输入脚在APCFG寄存器中必须被设置成模拟输入。
ADCCON2.SCH用来定义ADC输入的转换序列。如ADCCON2.SCH被设为小于8,转换序列包含一个通道(从0到ADCCON2.SCH中设置的通道号),当ADCCON2.SCH值设为8至12时,序列是差动输入,从通道8至程序设置的通道号;当大于12时,序列包含只选择的通道。
2、单个ADC转换
除了序列转换外,ADC可以通过编程执行单个转换。 通过写入ADCCON3寄存器可以触发一个转换,转换立即启动 ,除非一个转换序列正在进行中,这种情况下,当序列完成后,马上执行单个转换。
3、寄存器ADCCON1
ADC的数字转换结果可以通过寄存器ADCCON1获得,寄存器ADCCON1的定义如下图所示。
ADCCON1.EOC:转换结束状态位,当转换结束时设高电平,当读取ADCH时低电平。
ADCCON1.ST位用来启动序列转换的,当这位设高电平、ADCCON1.STSEL是11且当前无转换运行时序列启动开始。当序列转换结束时,这位自动清除为低电平。
&ADCCON1.STSEL位用来选择哪个事件将启动一个新的序列转换。此项选择有:外部引脚P2.0上升沿事件,之前序列的结束事件,定时器通道0比较事件,或ADCCON1.ST设1事件。
4、ADC转换结果
数字转换结果以2进制补码形式表示的,最高位是符号位。
对于单端输入配置,由于ADC输入不能接负电压,转换结果总是正的当输入信号等于参考电压VREF时达到最大转换结果。
对于差分输入配置,ADC输入电压为两个引脚的电压之差,两脚的输入信号不同,结果可能是负的;当采样率为512,模拟输入Vconv=VREF时,12MSB的数字转换结果为2047,当模拟输入等于-VREF时,转换结果为-2048。
通过读ADCCON2.SCH位,知道正在转换的是哪个通道,在序列转换中,ADCL和ADCH中的结果是前一个通道ADC转换的值。如转换序列已结束,ADCCON2.SCH将有一个大于最后通道数一个以上的值,但如最后写入ADCCON2.SCH中的通道数是12或更大,读回的是相同的值。
5、ADC参考电压
模数转换的参考电压可选择于内部产生电压,AVDD5脚电压,应用于AIN7输入脚的外部电压,或应用于AIN6-AIN7输入的差动电压。
内部参考电压对于CC2541来说是 1.25V ,比较小,能转换的最大模拟电压最大也只能是1.25V,AVDD5脚电压一般为3.3V,精度也不是很高。
转换结果的准确度依靠于参考电压的稳定性和噪声度,所以对于要求较高的ADC转换建议从AIN7输入脚接入高精度的参考电压。
6、ADC转换时间
ADC只能运行于32MHZ XOSC 。执行一个转换的时间依靠于被选择的采样率,一般上,转换时间由以下公式所得:
Tconv=(decimation rate+16)*0.25us.
可见分辨率越高,转换时间越长。
7、ADC中断
只有单通道ADC转换才有ADC中断,序列ADC转换没有ADC中断。
The ADC generates an interrupt when a single conversion triggered by writing to ADCCON3 has completed.No interrupt is generated when a conversion from the sequence is completed.
8、ADC DMA触发
每完成一个序列转换,ADC将产生一个DMA触发。单独转换完成不产生DMA触发。
在ADCCON2.SCH中设置8个通道,每个通道都有一个DMA触发。当通道转换中准备好一个采样时,将激活一个DMA触发。DMA触发命名为ADC_CHsd,s是单端通道,d是差动通道。
另外,当ADC序列转换通道中准备好一个新数据时,一个DMA触发(ADC_CHALL)将激活。
单个ADC转换读取ADC值的程序如下:
1 /******************************************************************************
2 *函 数 名:InitADC
能:ADC初始化
4 *入口参数:参考电压 reference、转换通道 channel、分辨率resolution
5 *出口参数:ADC转换结果
6 ******************************************************************************/
7 uint Read_advalue(uchar reference, uchar channel, uchar
resolution)
uchar tmpADCCON3 = ADCCON3;
APCFG |= 1 && //设置ADC输入通道,模拟I/O使能
= (reference | resolution | channel);
ADCIF = 0;
while(!ADCIF);
//等待 AD 转换完成
ADCL && 2;
//ADCL 寄存器低 2 位无效
value |= ((uint)ADCH && 6);
//连接AD转换结果高位和低位
21 //根据分辨率获得ADC转换结果有效位
switch(resolution)
case ADC_7_BIT:
value &&= 7;break;
case ADC_9_BIT:
value &&= 5;break;
case ADC_10_BIT: value &&= 4;break;
case ADC_12_BIT: value &&= 2;break;
ADCCON3 = tmpADCCON3;
return (value);
主程序:采集VDD值。
1 /******************************************************************************
2 *程序入口函数
3 ******************************************************************************/
4 int main(void)
//ADC转换值
InitClock();
//32MHz时钟
InitUART();
//UART0串口初始化
13 //ADC参考电压AVDD5引脚电源电压:3.3V,分辨率12位,采集通道:VDD/3,VDD=3.3V
vddvalue = Read_advalue(ADC_REF_AVDD5, 0x0f, ADC_12_BIT);
vddvalue = (vddvalue*33) && 11;
vddvalue = vddvalue*3;
buf[0] = vddvalue/10 + '0';
buf[1] = '.';
buf[2] =vddvalue%10 + '0';
UartSendString(buf,strlen(buf));
//串口上传采样VDD值
Delay1ms(2000);
//每隔2s上传一次值
这里给出协议栈的adc转换函数参照对比。
1 #include &hal_adc.h&
2 uint16 u16cvalu=HalAdcRead(HAL_ADC_CHANNEL_4,HAL_ADC_RESOLUTION_12);
3 分辨率设置为12位时,从源码可以看出,可用位是ADCH 8位+ADCH高4位,其中ADCH最高位是符号位,所以有11位的分辨率,0-2047
4 默认基准电压3.3V
5 uint16 HalAdcRead (uint8 channel, uint8 resolution)
reading = 0;
9 #if (HAL_ADC == TRUE)
adcChannel = 1;
/* store the previously set reference voltage selection */
reference = ADCCON3 & HAL_ADC_REF_BITS;
* If Analog input channel is AIN0..AIN7, make sure corresponing P0 I/O pin is enabled.
* does NOT disable the pin at the end of this function.
I think it is better to leave the pin
* enabled because the results will be more accurate.
Because of the inherent capacitance on the
* pin, it takes time for the voltage on the pin to charge up to its steady-state level.
* HalAdcRead() has to turn on the pin for every conversion, the results may show a lower voltage
* than actuality because the pin did not have time to fully charge.
if (channel & 8)
for (i=0; i & i++)
adcChannel &&= 1;
/* Enable channel */
ADCCFG |= adcC
/* Convert resolution to decimation rate */
switch (resolution)
case HAL_ADC_RESOLUTION_8:
resbits = HAL_ADC_DEC_064;
case HAL_ADC_RESOLUTION_10:
resbits = HAL_ADC_DEC_128;
case HAL_ADC_RESOLUTION_12:
resbits = HAL_ADC_DEC_256;
case HAL_ADC_RESOLUTION_14:
resbits = HAL_ADC_DEC_512;
/* read ADCL,ADCH to clear EOC */
tmp = ADCL;
tmp = ADCH;
/* Setup Sample */
adctemp = ADCCON3;
adctemp &= ~(HAL_ADC_CHN_BITS | HAL_ADC_DEC_BITS | HAL_ADC_REF_BITS);
adctemp |= channel | resbits | (reference);
/* writing to this register starts the extra conversion */
/* Wait for the conversion to be done */
while (!(ADCCON1 & HAL_ADC_EOC));
/* Disable channel after done conversion */
ADCCFG &= (adcChannel ^ 0xFF);
/* Read the result */
reading = (int16) (ADCL);
reading |= (int16) (ADCH && 8);
/* Treat small negative as 0 */
if (reading & 0)
reading = 0;
switch (resolution)
case HAL_ADC_RESOLUTION_8:
reading &&= 8;
case HAL_ADC_RESOLUTION_10:
reading &&= 6;
case HAL_ADC_RESOLUTION_12:
reading &&= 4;
case HAL_ADC_RESOLUTION_14:
reading &&= 2;
// unused arguments
103 #endif
return ((uint16)reading);
调试结果:显示VDD值3.3V。
关于程序注意以下几点:
1、要配置一个端口0脚为一个ADC输入, APCFG寄存器中相应的位必须设置为1 。这个寄存器的默认值选择端口0引脚为非ADC,即数字输入输出。 APCFG寄存器的设置将覆盖P0SEL的设置,所以无需再配置P0SEL ,另外对于I/O口作为外设功能,都无需配置方向,即无需配置寄存器PxDIR。
2、对于单次ADC转换的配置,只需要配置寄存器ADCCON3,无需配置寄存器ADCCON1和ADCCON2。对于判断转换是否结束,还有一种判断方法:
ADCCON1 |=0X30;
//ADC启动方式选择为ADCCON1.ST=1事件
ADCCON1 |= 0x40;
//启动转换
while(!(ADCCON1 & 0x80));
//等待 AD 转换完成
ADCCON1.STSEL是用于启动转换序列的触发方式的,对于单次ADC转换,个人感觉这样配置不好,以后对于单次ADC转换,不采用这种判断方式。
单次转换判断是否转换结束:判断ADC中断标志ADCIF。
3、ADCH的最高位是符号位,对于单次测量,结果总是正的,所以符号位总是0。14位的ADC转换值有效值并不是14位的。
有效分辨率如下:
00: 64 decimation rate (7 bits ENOB)----ADCH低7位
01: 128 decimation rate (9 bits ENOB)---ADCH低7位+ADCH高2位
10: 256 decimation rate (10 bits ENOB)--ADCH低7位+ADCH高3位
11: 512 decimation rate (12 bits ENOB)--ADCH低7位+ADCL高5位
例如:采集VDD/3值时,使用12位分辨率,参考电压AVDD5:3.3V
VDD/3 = vddvalue*3.3/2^11扩大10倍
VDD/3 = vddvalue*33/2^11为什么是除以2^11而不是2^12,因为最高位是符号位,12位分辨率实际上只有11位。
VDD = (vddvalue*33/2^11) * 3
4、差分输入可以用来做比较器。比如通道ADCCON3.ECH=1000,对应差分输入AIN0-AIN1。如果要比较一个模拟信号和另一个模拟信号的大小关系,只需要将这两个信号分别接入AIN0和AIN1,然后判断ADCH的最高位,如果是1,则AIN0&AIN1,如果是0,则AIN0&=AIN1。
5、最大转换电压等于参考电压,而参考电压的选择不能大于芯片的电源电压,一般为3.3V。虽然差分输入可以转换负电压,但是每一个模拟输入引脚都必须是正电压且小于电源电压VDD,负电压是指两个输入通道的差值。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致CC2540的传输速度和ADC - 蓝牙Bluetooth 技术 - 德州仪器在线技术支持社区
CC2540的传输速度和ADC
发表于2年前
<input type="hidden" id="hGroupID" value="42"
&span style=&color:#0000font-size:&>大家好,我有两个问题想咨询一下。&/span>&/p>
&p>&span style=&color:#0000font-size:&>1。.我用&a href=&.cn/product/cn/CC2540& target=&extwin&>CC2540&/a>与手机传输数据,只能达到么1.8KB/S,再快就会丢包。&/span>&/p>
&p>&span style=&color:#0000font-size:&>数据手册上讲一次连接可以传输4个包,可是我测试的时候一次连接只能传1个包,传两个包都会丢数据。这是为什么呢?&/span>&/p>
&p>&span style=&color:#0000font-size:&>2。&a href=&.cn/product/cn/CC2540& target=&extwin&>CC2540&/a>的ADC输出数值有偏移(我用的是14位精度),虽然转换曲线是直线,但是直线的斜率变了&/span>&/p>
&p>&span style=&color:#0000font-size:&>我现在用的办法是找一个较大的值和一个较小的值,生成一个直线方程才能校准(见下方)。&/span>&/p>
&p>&span style=&color:#0000font-size:&>可是,后来发现每个芯片的偏移量和斜率都不一样,难道每个芯片都要用程序去校准?&/span>&/p>
&p>&span style=&color:#0000font-size:&>//ADC计算值应该为4407,实测为4212&/span>&br>&span style=&color:#0000font-size:&> //ADC计算值应该为3733,实测为3602&/span>&br>&span style=&color:#0000font-size:&> //据上两个点生成直线方程 (y=1.105x-247)&/span>&/p>&div style=&clear:&>&/div>" />
CC2540的传输速度和ADC
此问题尚无答案
All Replies
大家好,我有两个问题想咨询一下。
1。.我用与手机传输数据,只能达到么1.8KB/S,再快就会丢包。
数据手册上讲一次连接可以传输4个包,可是我测试的时候一次连接只能传1个包,传两个包都会丢数据。这是为什么呢?
2。的ADC输出数值有偏移(我用的是14位精度),虽然转换曲线是直线,但是直线的斜率变了
我现在用的办法是找一个较大的值和一个较小的值,生成一个直线方程才能校准(见下方)。
可是,后来发现每个芯片的偏移量和斜率都不一样,难道每个芯片都要用程序去校准?
//ADC计算值应该为4407,实测为4212 //ADC计算值应该为3733,实测为3602 //据上两个点生成直线方程 (y=1.105x-247)
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
榜眼38026分
想提高传输速度,请参考:http://processors./index.php/OverlappedProcessing
关于ADC,请看这个文档的第12章:/lit/ug/swru191f/swru191f.pdf
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
hello Yan,
你所说的两个文档,我之前都有看过。是因为我的测到的实际值与文档的理论值不一样才来此咨询的。
与否告知:
1,与手机的实时传输速度提高到3.5KB/S能否稳定工作不丢包?
2,ADC的偏差是否由硬件本身造成的?
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
ADC的精度问题还是没有解决,我测试了两块板情况都一样,测试情况如下:(我现在用AVDD5作参考电压,14位分辨率,ADC1口采样)
一块板AVDD5的电压为3.268V,ADC1的电压为1.634V,理论转换值应该是4096,
可是连续5次测到的值为:,,3931。
另一块板AVDD5的电压为3.269V,ADC1的电压为1.633V,理论转换值应该是4092,
可是连续5次测到的值为:,,4016。
如果每个都不一样,软件也没办法校准啊,请问如何解决?我试过不跑协议,只写一个简单的ADC采样程序,测试情况都差不多。
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
这种情况应该属于参考电压偏差大, 如果对ADC一致性要求较高, 可以考虑使用外部专门的参考源。
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
这个是参考电源的偏差,建议使用外部精准参考电压源
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
Dear zongru zhan,
其实VDD5就是外部参考电压啊,
鉴于你的建议,我也做了如下测试,
在ADC1接的电压=0.506V,在ADC7接的电压=0.653V
用内部参考电压,测得ADC1的ADC值为3392,ADC7的ADC值为3380。(这里我非常不明白,不准就不准,为什么电压大的值反而要小?)
然后用ADC7做参考电压,测得ADC1的值为5252。(这个也不准啊,正常值应该是0.506/0.653*)
测试的时候,没跑协议,代码很简单,
#include&ioCC2541.h&
unsigned int count,val[10];
&int AdValue=0;
&void main()
&{& //设置系统时钟32MHz &&&
&&&& CLKCONCMD &= ~0x40; &&&
&&&& while(CLKCONSTA & 0x40);&&& &&&
&&&& CLKCONCMD &= ~0x47; &&&
&//ADC初始化&&&
&&&&&& APCFG=0
&&&& ADCCON1 = 0x33;
&&&& ADCCON3 = 0x31;
&//ADC采样5次&&&&
&& for(count=0;count&5;count++) &&&
& &{&& &&&&&
&&&&& && ADCCON3 = 0x31;&&&&&&&&& //内部基准& 12位ENOB& 通道1
&&&&&&& while(!(ADCCON1&0X80));
& &&&&& AdValue = ADCL&&2 ; &&&&&&&
&&&&&& &AdValue |= ADCH &&6; &&&&&&
&&&&& & if(AdValue&0) AdValue=0; &&&&&&&
&&&&&&&&val[count]=AdV &&&
&&&& } &&&
&&&& while(1);
TI的工程师帮看下,这是不是芯片本来的缺陷?
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
我说的外部参考源 是专门的参考电压输出片子 比如
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
文档上有说明,最好使用内部参考电压1.25V来做标准。外部电路可以采用分压法测量。
You have posted to a forum that requires a moderator to approve posts before they are publicly available.21ic官方微信
热门关键词
面向蓝牙BLE 4.1低功耗应用――TI CC2650 LaunchPad评测
[导读]CC2650 LaunchPad 套件采用 SimpleLink 超低功耗 CC26xx 系列器件,轻松实现 Bluetooth Smart 与 LaunchPad 生态系统的连接。此 LaunchPad 套件可为 CC2650 无线 MCU 以及其余 CC26xx 产品系列(适用于 ZigBee/6LoWPAN 的 CC2530以及适用于蓝牙智能的 CC2540)提供多协议支持。
随着科技水平的不断提高,蓝牙设备在我们的日常生活当中越来越普及。蓝牙BLE通信距离通常为10米至20米,载波频率2.4G-2.48G,通信速率可以达到1Mb/s,属于近距离通信,低功耗,加密性好,可以传输数据和语音。蓝牙用来替代连接不同终端设备之间的通信电缆线(比如rs232,usb等)。通信协议目前采用4.0版本,应用领域广泛,智能手机,平板电脑,可穿戴设备,蓝牙电视影音遥控器,蓝牙键鼠,蓝牙RFID卡,蓝牙耳机、音箱,遥控玩具,运动休闲,医疗保健,传感器数据采集等。IPHONE4S, IPHONE5S, IPHONE6S都支持BLE4.0,安卓4.3系统以上的智能手机和平板电脑也开始支持BLE4.0。
同时随着物联网络快速发展,智能家居,汽车蓝牙电子,智能手表,智能运动手环,智能白色家电(电视、冰箱、空调)、医疗蓝牙电子等应用快速普及,国际蓝牙联盟组织推出了功能更强的BLE 4.1协议,蓝牙通信功耗更低了!对芯片和传感器应用要求也更高,顺应市场需求半导体创新推出了cc2650/cc2640芯片,支持BLE 4.1协议,此外cc2650还支持zigbee等协议,功能确实很强大啊!此前我们曾经给大家介绍过TI CC2650STK,而此次由我来给大家介绍一下最新的基于CC2650的又一款开发板&&。&
二.板子照片
1. 板子外部包装盒照片
2.内部照片
3. 板子正面
4.板子背面
三.CC2650和CC2540对比
首先请看芯片内部的硬件功能模块:
接着请看CC2540芯片内部的硬件功能模块:
通过对比大家会发现:
1. 硬件架构为cortex m3内核, 32bit mcu,最高时钟达到48M Hz;
CC2540硬件架构为增强型8051内核,8bit mcu, 最高时钟为32M Hz;
由此可以看出比CC2540数据运算处理功能增强不少。
2. 硬件资源有128K flash,20K sram, uart ,spi, i2c,i2s,adc等;CC2540硬件资源有256K flash,8K sram, USB,uart ,spi, adc等;
0资源对比CC2540还是很丰富的,不足之处除了没有USB通信功能外,内部flash有点小,不方便实现OAD代码升级;
CC2540由于有USB通信功能,可以制作目前蓝牙领域最简洁的dongle 工具!
3. CC2540支持BLE4.0蓝牙协议,发射功率最大为+4dbm,通信接收电流19.6ma, 0dbm发送电流27CC2650支持BLE4.1蓝牙协议,发射功率最大为+5dbm,通信接收电流5.9ma,0dbm发送电流6.1ma, 从数据可以看出cc2650通信功耗降低很多。
4. CC2540当作主机时可以扫描到3个蓝牙设备;由于内部集成了M0芯片负责蓝牙通信,当作主机时可以扫描到8个蓝牙设备,此外cc2650还支持zigbee协议等。
四.板子硬件介绍
板子主要包括两个部分,模块部分和仿真调试以及烧录器部分。
如图所示:
1. cc2650火箭板芯片采用7mm & 7mm RGZ QFN48 封装,有31个GPIO,GPIO可以配置连接任意的数字外设引脚,非常灵活!同时所有GPIO引脚都外接出来,方便使用。板子上有两个按键以及两个指示灯,射频通信部分采用分立电容,电感器件,天线采样PCB天线。另外板子上外扩8Mbit flash,可以存储数据或者实现OAD。
引脚分布图:
2. 调试工具
开发工具采用简洁版的xds110, 和电脑通过usb接口通信,支持固件升级。带jtag通信接口,可以在线调试仿真,同时可以烧录代码,并且支持串口bootloader代码,是很不错的开发工具,使用效果很不错!
3. 开发工具驱动安装
从官方网站下载最新的驱动,默认安装在C盘目录,连接上火箭板后电脑提示如下:
我 要 评 论3680人阅读
& & & & Write programs that do one thing and do it well ~~~~~
& & & & 发现很多人关于使用CC2640/CC2650的过程中比较难以应对的问题就是实现ADC,为了方便大家,所以有了本篇博客,都是一些自己的理解,不对的地方请大家指正。
& & & & TI的这款新品上市不久,还有需要需要更新的地方,尤其是以往以其文档多为优势,而如今到了CC26xx这却几乎没什么可参考的文档了,大家就等等吧,肯定会越来越完善的。
& & & & 本篇主要介绍如何使用TI官方给的driverlib实现ADC的使用,SCS也能控制ADC的实现,但是这个过于复杂,生产的代码也比较难以理解,所以还是使用driverlib吧。
二、版权声明
博主:summer
声明:喝水不忘挖井人,转载请注明出处。
原文地址:http://blog.csdn.net/qq_
联系方式:
技术交流QQ:
三、试验平台
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的功耗还是比较低的。
五、如何在工程中实现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 adcV
& & & & 在上述实现代码中所涉及的一些问题,讲述一下自己的理解,如果仅仅是为了实现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;
// GPT trigger: Configure event routing via MCU_EV to the AUX domain
HWREG(EVENT_BASE + EVENT_O_AUXSEL0) =
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
#define AUXADC_SAMPLE_TIME_5P3_US
#define AUXADC_SAMPLE_TIME_10P6_US
#define AUXADC_SAMPLE_TIME_21P3_US
#define AUXADC_SAMPLE_TIME_42P6_US
#define AUXADC_SAMPLE_TIME_85P3_US
#define AUXADC_SAMPLE_TIME_170_US
#define AUXADC_SAMPLE_TIME_341_US
#define AUXADC_SAMPLE_TIME_682_US
#define AUXADC_SAMPLE_TIME_1P37_MS
#define AUXADC_SAMPLE_TIME_2P73_MS
#define AUXADC_SAMPLE_TIME_5P46_MS
#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
[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
#define ADI_4_AUX_ADC1_SCALE_DIS_BITN
#define ADI_4_AUX_ADC1_SCALE_DIS_M
#define ADI_4_AUX_ADC1_SCALE_DIS_S
//*****************************************************************************
AUXADCDisableInputScaling(void)
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC1, ADI_4_AUX_ADC1_SCALE_DIS_M);
}六、关于精度和测试结果
& & & & TI的&R&D给出了一份他们在实验的测试结果,大家可以按照这个作为比较,实测和这份数据差不多。
七、附加题(你肯定懂得它的含义)
& & & & 什么?不知道“附加题”的意义何在?那你肯定没经历过高考的洗&#31036;~~~~
& & & & 原本想再单独写一篇博文介绍关于供电电压采集的,但是感觉比较简单就和ADC放在一起讲吧,它俩比较接近。首先,很多工程师在做类&#20284;于手环、心率计、HCG等等时可能都需要使用到芯片的ADC功能,又想实时的获取供电电压,但是内部ADC的数量又是有限的,如何实现多路使用ADC呢,大家首先想到的应该就是切换使用内部ADC,但是在一路正在使用的时候直接切换掉是不是对正在ADC采集的数据导致错误呢,或者说这个切换的时间如何把握呢。所以CC26xx有了这个Battery
Monitor的功能,让工程师测量供电电压时不再占用外部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.v,小数部分的分辨率只有50mV(TYP)
batval = AONBatMonBatteryVoltageGet();& & & &&AONBatMonBatteryVoltageGet()的函数原型是:
__STATIC_INLINE uint32_t
AONBatMonBatteryVoltageGet(void)
uint32_t ui32CurrentB
ui32CurrentBattery = HWREG(AON_BATMON_BASE + AON_BATMON_O_BAT);
// Return the current battery voltage measurement.
return (ui32CurrentBattery && AON_BATMON_BAT_FRAC_S);
& & & & 返回&#20540;是根据不同的位代表芯片供电电压的整数部分和小数部分的,详细介绍如下。
//*****************************************************************************
// Register: AON_BATMON_O_BAT
//*****************************************************************************
[10:8] INT
// Integer part:
// 0x0: 0V + fractional part
// 0x3: 3V + fractional part
// 0x4: 4V + fractional part
#define AON_BATMON_BAT_INT_M
#define AON_BATMON_BAT_INT_S
[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的电压变化&#20540;,可以精确获取到。
& & & & 实在不知道写什么了,还是打个广告吧。
& & & & 学挖掘机技术哪家强?
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:90651次
积分:1161
积分:1161
排名:千里之外
原创:24篇
评论:73条
(1)(2)(2)(2)(2)(10)(5)(2)}

我要回帖

更多关于 ti cc2650 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信