CC2430 ADC使用——查询法
1 目标
熟悉使用CC2430的ADC功能。根据我自己开发板的情况,我使用P07作为AD转换的输入口,使用一个旋转电位器来调整输入端口的电压,通过串口发送AD转换结果。在这里还是说说ADC的结构。
CC2430的ADC是基于sigma-delta原理,而不是常用的逐次比较式,通过不同的抽取率来实现不同的转换精度。
2 代码总览
还是老规矩,先列出所有的代码。在这里除了使用到ADC模块,还使用了定时器和串口模块,串口模块用来输出转换结果,定时器模块用来间隔调用ADC转换函数。具体的代码如下所示:
//包含头文件
#include "hal.h"
#include "stdio.h"
//函数申明
UINT8 UART0_Init();
UINT8 ADC_Init();
UINT8 Timer1_Init();
UINT16 ADC_Convert();
void main(){
//使用外部晶振
SET_MAIN_CLOCK_SOURCE(CRYSTAL);
//设定IO口
IO_DIR_PORT_PIN(0, 7, IO_IN);
//初始化定时器
Timer1_Init();
//初始化串口
UART0_Init();
//初始化ADC
ADC_Init();
//输出提示
printf("CC2430 ADC Test\n");
//无线循环
while(1){
}
}
UINT8 ADC_Init(){
//选择AD转换通道
ADC_ENABLE_CHANNEL(ADC_AIN7);
//选择参考电压,分辨率,通道
ADC_SINGLE_CONVERSION(ADC_REF_AVDD | ADC_10_BIT | ADC_AIN7);
return 0;
}
UINT16 ADC_Convert(){
//转换结果高位和低位
UINT8 adc_h;
UINT8 adc_l;
UINT16 adc_value;
//开始转换
ADC_SAMPLE_SINGLE();
//等待转化结束
while(!ADC_SAMPLE_READY());
//获得转换结果
adc_h = ADCH;
adc_l = ADCL;
//获得AD转换结果,10位结果
adc_value = (( adc_h << 8) | adc_l) >> 6;
//输出转换结果
printf("ADC 10bit = %d\n",adc_value);
return adc_value ;
}
UINT8 UART0_Init(){
//UART0 IO口定位
IO_PER_LOC_UART0_AT_PORT0_PIN2345();
//UART0参数9600 8 N 1
UART_SETUP(0,9600,HIGH_STOP);
UTX0IF = 1;
return 0;
}
int putchar(int c){
if(c== '\n'){
while(!UTX0IF);
UTX0IF = 0;
U0DBUF = '\r';
}
while(!UTX0IF);
UTX0IF = 0;
U0DBUF = c;
return c;
}
UINT8 Timer1_Init(){
//定时器1复位
TIMER1_INIT();
//设定定时器相关参数
//溢出值低8位
T1CC0L=0x24;
//溢出值高8位
T1CC0H=0xF4;
//128分频0000 1100
T1CTL = 0x0c;
//定时器T1溢出中断使能
TIMER1_ENABLE_OVERFLOW_INT(TRUE);
//定时器T1中断使能
INT_ENABLE(INUM_T1,INT_ON);
//启动定时器1
TIMER1_RUN(TRUE);
//全局中断使能,注意
INT_GLOBAL_ENABLE(INT_ON);
return 0;
}
//定时器1 中断函数
#pragma vector=T1_VECTOR
__interrupt void T1_ISR(void)
{
//检查中断标志位
if(T1CTL & 0x10){
//ADC 通道参数初始化
ADC_Init();
//启动转换,通过串口输出结果
ADC_Convert();
//清中断标志
T1CTL &= ~0x10;
}
}
3 初始化其他内容
//使用外部晶振
SET_MAIN_CLOCK_SOURCE(CRYSTAL);
//设定IO口
IO_DIR_PORT_PIN(0, 7, IO_IN);
//初始化定时器
Timer1_Init();
//初始化串口
UART0_Init();
其他的不多说了,在使用AD转换功能之前,需要定义该IO口为输入状态。使用这个宏就可以了。IO_DIR_PORT_PIN(0, 7, IO_IN);
4 初始化ADC
//初始化ADC
ADC_Init();
ADC_Init的函数如下所示:
UINT8 ADC_Init(){
//选择AD转换通道
ADC_ENABLE_CHANNEL(ADC_AIN7);
//选择参考电压,分辨率,通道
ADC_SINGLE_CONVERSION(ADC_REF_AVDD | ADC_10_BIT | ADC_AIN7);
return 0;
}
初始化ADC可以分为2步,
第一步,使能ADC转换通道(IO特性),在这里我们选择通道7,使用了一个动作宏
#define ADC_ENABLE_CHANNEL(ch) ADCCFG |= (0x01<<ch);
该宏操作了ADCCFG寄存器,这个寄存器的说明位于IO部分,而不是ADC部分。
第二步,选择ADC的参考电压,转换分辨率和ADC通道。在这里使用了另一个宏定义:
#define ADC_SINGLE_CONVERSION(settings) \
do{ ADCCON3 = settings; }while(0)
// Reference voltage:
#define ADC_REF_1_25_V 0x00 // Internal 1.25V reference
#define ADC_REF_P0_7 0x40 // External reference on AIN7 pin
#define ADC_REF_AVDD 0x80 // AVDD_SOC pin
#define ADC_REF_P0_6_P0_7 0xC0 // External reference on AIN6-AIN7 differential input
// Resolution (decimation rate):
#define ADC_7_BIT 0x00 // 64 decimation rate
#define ADC_9_BIT 0x10 // 128 decimation rate
#define ADC_10_BIT 0x20 // 256 decimation rate
#define ADC_12_BIT 0x30 // 512 decimation rate
// Input channel:
#define ADC_AIN0 0x00 // single ended P0_0
#define ADC_AIN1 0x01 // single ended P0_1
#define ADC_AIN2 0x02 // single ended P0_2
#define ADC_AIN3 0x03 // single ended P0_3
#define ADC_AIN4 0x04 // single ended P0_4
#define ADC_AIN5 0x05 // single ended P0_5
#define ADC_AIN6 0x06 // single ended P0_6
#define ADC_AIN7 0x07 // single ended P0_7
#define ADC_GND 0x0C // Ground
#define ADC_TEMP_SENS 0x0E // on-chip temperature sensor
#define ADC_VDD_3 0x0F // (vdd/3)
所有的参数都可以在数据手册中,ADCCON3部分找到,这里不多做说明。需要说明的一点是,原书代码中(ZigBee技术实践教程)转换分辨率的定义为8,10,12,14,通过我个人的多次试验和资料查证,分辨率实际为7,9,10,12,数据左对齐,以补码的形式保存。所以这里定义为10位分辨率时,最大的结果为511,最小的结果为-512。但是这里是不会有负结果出现的。(这个和实验的结果也是吻合的)
5 进行AD转换
UINT16 ADC_Convert(){
//转换结果高位和低位
UINT8 adc_h;
UINT8 adc_l;
UINT16 adc_value;
//开始转换
ADC_SAMPLE_SINGLE();
//等待转化结束
while(!ADC_SAMPLE_READY());
//获得转换结果
adc_h = ADCH;
adc_l = ADCL;
//获得AD转换结果,10位结果
adc_value = (( adc_h << 8) | adc_l) >> 6;
//输出转换结果
printf("ADC 10bit = %d\n",adc_value);
return adc_value ;
}
这里使用了最简单的等待方法,ADC还可以使用其他方法,比如说中断或者DMA传送等。先从简单的来,完成一次ADC转换可以分为3步:
第一步:启动AD转换
#define ADC_SAMPLE_SINGLE() \
do { ADC_STOP(); ADCCON1 |= 0x40; } while (0)
#define ADC_STOP() \
do { ADCCON1 |= 0x30; } while (0)
第二步:等待AD转换结束
只需要查询标志位就可以了。
#define ADC_SAMPLE_READY() (ADCCON1 & 0x80)
ADCCON1的7位置位时代表AD转换完成,否则不断等待。
第三步:结果处理
AD转换的结果保存在ADCH和ADCL寄存器中,先把两个寄存器组成一个16位长度的整形数据,然后使用移位算法获得相应的结果,本例中使用了10位数据,所以右移6位即可。
转换完成后使用printf输出结果,这里就体现了串口的好处了。最大的作用方便调试。
6 定时输出结果
由于完成单次的转换没有意义,所以需要定时完成转换。在这里使用了定时器1,定时器1的使用前面的文章给你已经说过,这里不再重复。中断服务函数如下所示:
#pragma vector=T1_VECTOR
__interrupt void T1_ISR(void)
{
//检查中断标志位
if(T1CTL & 0x10){
//ADC 通道参数初始化
ADC_Init();
//启动转换,通过串口输出结果
ADC_Convert();
//清中断标志
T1CTL &= ~0x10;
}
}
还请大家注意,每次转换完成后必须重新选择通道。数据手册中关于ADCCON3有明确提到。我一开始也以为只要设定好了,这个通道号是不会变化的,但是后面发现这样做转换的结果总是不变,打印了数据手册一页一页看才明白过来。
7 输出结果
没有实验结果的示例是站不住脚的。我把旋转定位器的先拧到最大,使7通道的输入电压最大,也就是达到VDD(3.3V),然后再慢慢减小。测试的结果如下图所示:
通过转动电位器使电压不断减小,转换的结果也随之不断减小。还可以看出,转换的最大结果为511,符合预计结果。幸好没有出现512,否则我又要郁闷好久。为了这个AD转换我还做了很多实验,在不同的抽取率情况下取出ADC结果,然后画图分析,这个以后再写文章说明。
CC2430串口使用说明
CC2430定时器使用说明
CC2430 hal.h
分享到:
相关推荐
CC2430CC2431实例程序---片内温度传感器使用 CC2430CC2431实例程序---片内温度传感器使用
CC2430单片机AD转换使用方法总结
cc2430单片机AD转换使用方法,提供初学者共同学习
该资源已经成功的采集一路CC2430的ad,CC2530,CC2431同样适用
是AD13数据库——Zetex部分
是AD13数据库——Zilog部分
TI公司/德州电子所生产的元器件的AD元件库, l289n/l298p/mc34063等TI公司所产的元器件库里都有 含有三维封装pcblib和原理图库schlib 非常齐全,非常精美
基于STM32的CC2430点对多通信包含AD采集
是AD数据库——Xilinx部分
是AD数据库——Winbond Electronics部分
是AD数据库——Zarlink Semiconductor部分
zigbee cc2430模块控制lcd,初学者可知如何控制其io口
CC2530的AD转换部分的详解,对AD转换精度部分做了详细的解析
ESP8266封装——AD
STM32并口驱动AD9854——HAL库
(个人不推荐下载,下载请谨慎) 合泰单片机原理图库 AD 格式为SCHLIB 不含封装库 只有原理图库 型号有限,不齐全的,下载别说坑 但是主流的型号是有的 画的还算可以的。
(个人不推荐下载,下载请谨慎) STM32原理图库 AD 格式为SCHLIB 不含封装库 只有原理图库 型号有限,不齐全的,下载别说坑 但是主流的型号是有的 画的还算可以的。
内含esp8266的各型号AD库,文件格式分别为schlib和pcblib,即有原理图库和封装库,精装三维库,非常好看的。 内含型号:ESP-01 &01S Esp-01F ESP-01 M ESP-07 ESP-07S ESP-12E&F ESP-12S 其他的没有
这是一份关于CC2430方面的资料,里面包括电路原理图、pcb和程序代码
Altium designer绘制直流降压电路。经检验,可正常工作