CC2530ADC转换
一、ADC简介
ADC支持 14 位的模拟数字转换,具有多达12 位的 ENOB(有效数字位)。它包括一个模拟多路转换器,具有多达8 个各自可配置的通道,以及一个参考电压发生器。转换结果通过DMA写入存储器。还具有若干运行模式。
二、A/D转换的基本工作原理
将时间上连续变化的模拟量转化为脉冲有无的数字量,这一过程就叫做数字化,实现数字化的关键设备是ADC。
ADC:数模转换器,将时间和幅值连续的模拟量转化为时间和幅值离散的数字量,A/D转换一般要经过采样、保持、量化和编码4个过程。
三、CC2530的A/D转换模块
ADC的主要特性如下:
● 可选的抽取率,这也设置了分辨率(7 到 12 位)
● 8 个独立的输入通道,可接受单端或差分信号
● 参考电压可选为内部单端、外部单端、外部差分或 AVDD5
● 产生中断请求
● 转换结束时的 DMA 触发
● 温度传感器输入
● 电池测量功能
四、一些关于ADC的概念
<1> 序列ADC转换:可以按序列进行多通道的ADC转换,并把结果通过DMA传送到存储器,而不需要CPU任何参与。
<2> 单通道ADC转换:在程序设计中,通过写ADCCON3寄存器触发单通道ADC转换,一旦寄存器被写入,转换立即开始。
<3> 参考电压:内部生成的电压、AVDD5引脚、适用于AIN7输入引脚的外部电压,或者 适用于AIN6~AIN7输入引脚的差分电压。
<4> 转换结果:数字转换结果以2的补码形式表示。对于单端,结果总是正的。对于差分配置,两个引脚之间的差分被转换,可以是负数。 当ADCCON1.EOC设置为1时,数字转换结果可以获得,且结果总是驻留在ADCH和ADCL寄存器组合的MSB段中。
<5> 中断请求:通过写ADCCON3触发一个单通道转换完成时,将产生一个中断,而完成 一个序列转换时,是不产生中断的。当每完成一个序列转换,ADC将产生 一个DMA触发。
<6> 寄存器:ADC有两个数据寄存器:ADCL和ADCH;三个控制寄存器:ADCCON1、ADCCON2、ADCCON3;分别用来配置ADC并返回转换结果。
五、ADC模块的信号输入
端口0引脚可以配置为ADC输入端,依次为AIN0~AIN7:
<1> 可以把输入配置为单端输入或差分输入。
<2> 在选择差分输入的情况下,差分输入对:AIN0~AIN1、AIN2~AIN3、AIN4~AIN5、AIN6~AIN7。
<3>除了输入引脚 AIN0-AIN7,片上温度传感器的输出也可以选择作为 ADC的输入,用于温度测量。
<4> 可以将一个对应AVDD5/3的电压作为ADC输入,实现电池电压监测。
<5> 负电压和大于VDD的电压都不能用于这些引脚。
<6> 单端电压输入AIN0~AIN7,以通道号码0~7表示;四个差分输入对则以 通道号码8~11表示;温度传感器的通道号码为14;AVDD5/3电压输入的通道号码为15。
题目:定时采集电压数据发送到上位机
将光照度传感器接到的Zigbee小模块上,每隔1秒以单通道的传送到上位机。上位机与CC2530的 串口0相连,系统时钟为传送到上位机。上位机与CC2530的 串口0相连,系统时钟为16MHz,波特率为9600BPS,发送数据采用查询的方式。数据帧有4个字节,格式如下: 0xFA (帧头) ADCH ADCL 0xAF (帧尾)
思路:
1.初始化定时器1,实现0.1秒定时。
1 void Init_Timer1() 2 { 3 T1CC0L = 0xd4; //设置最大计数值的低8位 4 T1CC0H = 0x30; //设置最大计数值的高8位 5 T1CCTL0 |= 0x04; //开启通道0的输出比较模式 6 T1IE = 1; //使能定时器1中断 7 T1OVFIM = 1; //使能定时器1溢出中断 8 EA = 1; //使能总中断 9 T1CTL = 0x0e; //分频系数是128,模模式 10 }
2.在定时中断函数中实现1秒定时。
1 unsigned char count = 0; 2 unsigned char F_time = 0; 3 /*================定时器1服务函数====================*/ 4 #pragma vector = T1_VECTOR 5 __interrupt void Timer1_Sevice() 6 { 7 T1STAT &= ~0x01; //清除定时器1通道0中断标志 8 count++; 9 if(count == 10) //定时1秒到 10 { 11 F_time = 1; 12 count = 0; 13 } 14 }
3.按照参数要求初始化串口0。
1 void Init_Uart0() 2 { 3 PERCFG = 0x00; //串口0的引脚映射到位置1,即P0_2和P0_3 4 P0SEL = 0x0C; //将P0_2和P0_3端口设置成外设功能 5 U0BAUD = 59; //16MHz的系统时钟产生9600BPS的波特率 6 U0GCR = 9; 7 U0UCR |= 0x80; //禁止流控,8位数据,清除缓冲器 8 U0CSR |= 0xC0; //选择UART模式,使能接收器 9 UTX0IF = 0; //清除TX发送中断标志 10 URX0IF = 0; //清除RX接收中断标志 11 URX0IE = 1; //使能URAT0的接收中断 12 EA = 1; //使能总中断 13 }
4.设计字节数组发送函数。
unsigned char dat[4]; /*===================UR0发送字符串函数==================*/ void UR0SendString(unsigned char *str, unsigned char count) { while(count--) { U0DBUF = *str++; //将要发送的1字节数据写入U0DBUF while(!UTX0IF); //等待TX中断标志,即数据发送完成 UTX0IF = 0; } }
5.初始化ADC (单通道采集)。
配置APCFG寄存器
当使用ADC时,端口0的引脚必须配置为ADC模拟输入。要配置一个端口0引脚为一个ADC输入,APCFG寄存器中相应的位必须设置为1。这个寄存器的默认值是0,选择端口0为非模拟输入,即作为数字I/O端口。
注意:APCFG寄存器的设置将覆盖P0SEL的设置。
主要对端口的功能进行选择,设置其传输方向,并将端口设置为模拟输入。
1 void Init_ADC0() 2 { 3 P0SEL |= 0x01; //P0_0端口设置为外设功能 4 P0DIR &= ~0x01; //P0_0端口设置为输入端口 5 APCFG |= 0x01; //P0_0作为模拟I/O使用 6 }
6.实现数据采集并发送到上位机。
配置ADCCON3寄存器
单通道的ADC转换,只需将控制字写入ADCCON3寄存器即可。
例子:ADCCON3 = (0x80 | 0x10 | 0x00); //参考电压选择AVDD5引脚,256 抽取率,AINO通道0
首先将ADCIF标志位清0,接着对ADCCON3寄存器设置,该寄存器一旦被写入,转换立即开启;然后等待ADCIF置1,这时候转换完成,读取数据即可。
1 /*===================读取ADC的数据====================*/ 2 void Get_ADC0_Value() 3 { 4 ADCIF = 0; 5 //参考电压选择AVDD5引脚,256抽取率,AIN0通道0 6 ADCCON3 = (0x80 | 0x10 | 0x00); 7 while(!ADCIF); //等待A/D转换完成, 8 dat[0] = 0xaf; 9 dat[1] = ADCH; //读取ADC数据低位寄存器 10 dat[2] = ADCL; //读取ADC数据高位寄存器 11 dat[3] = 0xfa; 12 }
完整代码:
1 #include "ioCC2530.h" 2 /*===============定时器1初始化函数==================*/ 3 void Init_Timer1() 4 { 5 T1CC0L = 0xd4; //设置最大计数值的低8位 6 T1CC0H = 0x30; //设置最大计数值的高8位 7 T1CCTL0 |= 0x04; //开启通道0的输出比较模式 8 T1IE = 1; //使能定时器1中断 9 T1OVFIM = 1; //使能定时器1溢出中断 10 EA = 1; //使能总中断 11 T1CTL = 0x0e; //分频系数是128,模模式 12 } 13 unsigned char count = 0; 14 unsigned char F_time = 0; 15 /*================定时器1服务函数====================*/ 16 #pragma vector = T1_VECTOR 17 __interrupt void Timer1_Sevice() 18 { 19 T1STAT &= ~0x01; //清除定时器1通道0中断标志 20 count++; 21 if(count == 10) //定时1秒到 22 { 23 F_time = 1; 24 count = 0; 25 } 26 } 27 /*===================UR0初始化函数====================*/ 28 void Init_Uart0() 29 { 30 PERCFG = 0x00; //串口0的引脚映射到位置1,即P0_2和P0_3 31 P0SEL = 0x0C; //将P0_2和P0_3端口设置成外设功能 32 U0BAUD = 59; //16MHz的系统时钟产生9600BPS的波特率 33 U0GCR = 9; 34 U0UCR |= 0x80; //禁止流控,8位数据,清除缓冲器 35 U0CSR |= 0xC0; //选择UART模式,使能接收器 36 UTX0IF = 0; //清除TX发送中断标志 37 URX0IF = 0; //清除RX接收中断标志 38 URX0IE = 1; //使能URAT0的接收中断 39 EA = 1; //使能总中断 40 } 41 unsigned char dat[4]; 42 /*===================UR0发送字符串函数==================*/ 43 void UR0SendString(unsigned char *str, unsigned char count) 44 { 45 while(count--) 46 { 47 U0DBUF = *str++; //将要发送的1字节数据写入U0DBUF 48 while(!UTX0IF); //等待TX中断标志,即数据发送完成 49 UTX0IF = 0; 50 } 51 } 52 /*===================ADC初始化函数====================*/ 53 void Init_ADC0() 54 { 55 P0SEL |= 0x01; //P0_0端口设置为外设功能 56 P0DIR &= ~0x01; //P0_0端口设置为输入端口 57 APCFG |= 0x01; //P0_0作为模拟I/O使用 58 } 59 /*===================读取ADC的数据====================*/ 60 void Get_ADC0_Value() 61 { 62 ADCIF = 0; 63 //参考电压选择AVDD5引脚,256抽取率,AIN0通道0 64 ADCCON3 = (0x80 | 0x10 | 0x00); 65 while(!ADCIF); //等待A/D转换完成, 66 dat[0] = 0xaf; 67 dat[1] = ADCH; //读取ADC数据低位寄存器 68 dat[2] = ADCL; //读取ADC数据高位寄存器 69 dat[3] = 0xfa; 70 } 71 /*=======================主函数======================*/ 72 void main() 73 { 74 Init_Uart0(); 75 Init_Timer1(); 76 Init_ADC0(); 77 while(1) 78 { 79 if(F_time == 1) //定时1秒时间到 80 { 81 Get_ADC0_Value(); //进行A/D转换并读取数据 82 UR0SendString(dat,4); //向上位机发送数据 83 F_time = 0; //定时1秒标志清0 84 } 85 } 86 }