zydlyq的笔记 https://bbs.21ic.com/?580785 [收藏] [复制] [RSS]

日志

(转载)Zigbee之旅(六):几个重要的CC2430基础实验——ADC单次采样

已有 1486 次阅读2011-9-18 14:22 |个人分类:单片机|系统分类:单片机


         
        

一、承上启下


  在无线传感器网络中,很重要的一项就是将传感器的模拟值转换成数字量,以便于传输和处理。而ADC(Analog-to-Digital Converter)正是用来完成这种转换的。


  上一节,我们介绍了CC2430与PC之间的串口通信。CC2430内部已嵌入一个温度传感器,本节将在上一节的基础上,实现一个简单的关于片
内温度监测的小实验:利用ADC将片内温度传感器的电压值转换成数字量,利用公式计算出温度值,然后通过串口将温度值传送到PC上并显示出来。


二、ADC单次采样(1)实验简介


  利用ADC转换CC2430片内温度传感器的温度值,通过串口将温度值发送到PC并显示出来。


(2)程序流程图




(3)实验源码及剖析/*


实验说明:片内温度采集实验,通过串口0将数据发送到PC机


*/


#include


#define led1 P1_0


#define led2 P1_1


#define led3 P1_2


#define led4 P1_3


/*32M晶振初始化


-------------------------------------------------------*/


voidxtal_init(void)


{


SLEEP&=~0x04; //都上电


while(!(SLEEP&0x40)); //晶体振荡器开启且稳定


CLKCON&=~0x47; //选择32MHz 晶体振荡器


SLEEP|=0x04;


}


/*LED灯初始化


-------------------------------------------------------*/


voidled_init(void)


{


P1SEL =0x00; //P1为普通 I/O 口


P1DIR|=0x0F; //P1.0 P1.1 P1.2 P1.3 输出



led1=1;


led2=1;


led3=1;


led4=1;


}


/*UART0初始化


-------------------------------------------------------*/


void Uart0Init(unsignedcharStopBits,unsignedcharParity)


{


P0SEL|= 0x0C; //初始化UART0端口


PERCFG&=~0x01; //选择UART0为可选位置一


U0CSR=0xC0; //设置为UART模式,而且使能接受器


U0GCR=11;


U0BAUD=216; //设置UART0波特率为115200bps


U0UCR|=StopBits|Parity; //设置停止位与奇偶校验


}


/*UART0发送字符


-------------------------------------------------------*/


void Uart0Send(unsignedchardata)


{


while(U0CSR&0x01); //等待UART空闲时发送数据


U0DBUF=data;


}


/*UART0发送字符串


-------------------------------------------------------*/


voidUart0SendString(unsignedchar*s)


{


while(*s!=0)


Uart0Send(*s++);


}


/*UART0接收数据


-------------------------------------------------------*/


unsignedcharUart0Receive(void)


{


unsignedchardata;


while(!(U0CSR&0x04));//查询是否收到数据,否则继续等待


data=U0DBUF;


returndata;


}


/*延时函数


-------------------------------------------------------*/


voidDelay(unsignedint n)


{


unsignedinti;


for(i=0;i< p=""><>

for(i=0;i< p=""><>

for(i=0;i< p=""><>

for(i=0;i< p=""><>

for(i=0;i< p=""><>

}


/*得到实际温度值


-------------------------------------------------------*/


floatgetTemperature(void)


{


unsignedint value;


ADCCON3 = (0x3E); //选择1.25V为参考电压;14位分辨率;对片内温度传感器采样



ADCCON1|=0x30; //选择ADC的启动模式为手动


ADCCON1|=0x40; //启动AD转化



while(!(ADCCON1&0x80)); //等待ADC转化结束


value= ADCL>>2;


value|= (ADCH<<6); //取得最终转化结果,存入value中



returnvalue*0.06229-311.43; //根据公式计算出温度值


}


/*主函数


-------------------------------------------------------*/


voidmain(void)


{


chari;


floatavgTemp;


unsignedcharoutput[]="";



xtal_init();


led_init();



led1=0;


Uart0Init(0x00,0x00); //初始化串口:无奇偶校验,停止位为1位


Uart0SendString("Hello CC2430 - TempSensor!\r\n");


while(1)


{


led1=0;


avgTemp=0;


for(i=0 ;i<64 ;i++)


{


avgTemp+=getTemperature();


avgTemp=avgTemp/2; //每采样1次,取1次平均值


}



output[0]= (unsignedchar)(avgTemp)/10+48; //十位


output[1]= (unsignedchar)(avgTemp)%10+48; //个位


output[2]='.'; //小数点


output[3]= (unsignedchar)(avgTemp*10)%10+48; //十分位


output[4]= (unsignedchar)(avgTemp*100)%10+48; //百分位


output[5]='\0'; //字符串结束符



Uart0SendString(output);


Uart0SendString("℃\n");


led1=1; //LED熄灭,表示转换结束,



Delay(20000);


Delay(20000);


Delay(20000);


Delay(20000);


Delay(20000);


Delay(20000);


Delay(20000);


Delay(20000);


Delay(20000);


Delay(20000);


}


}


  关于串口通信的代码内容,请参考上一节,在此不解释~


  ADC一般涉及到6个SFR:


    ADCCON1:用于ADC通用控制,包括转换结束标志、ADC触发方式、随机数发生器


    ADCCON2:用于连续ADC转换的配置(本实验不涉及连续ADC转换,故不使用此SFR)


    ADCCON3:用于单次ADC转换的配置,包括选择参考电压、分辨率、转换源


    ADCH[7:0]:ADC转换结果的高位,即ADC[13:6]


    ADCL[7:2]:ADC转换结果的低位,即ADC[5:0]


    ADCCFG:选择 P0.0~P0.7 作为ADC输入的 AIN0~AIN7(由于本次试验选择片内温度传感器作为转换源,不涉及AIN0~AIN7,故不使用此SFR) 


  (注:以上SFR的具体内容请参考CC2430中文手册)


  接下来,我们来重点关注一下getTempurature 函数,它是获取温度值的关键:


    (1)首先配置ADC单次采样:令 ADCCON3=0x3E,选择1.25V为系统电压,选择14位分辨率,选择CC2430片内温度传感器作为ADC转换源


    (2)然后令 ADCCON1 |= 0x30,设置ADC触发方式为手动(即当ADCCON.6=1时,启动ADC转换)


    (3)接着令 ADCCON1 |= 0x40,启动ADC单次转换


    (4)使用语句 while(!(ADCCON1 & 0x80)) 等待ADC转换的结束


    (5)转换结果存放在ADCH[7:0](高8位),ADCH[7:2](低6位),通过:


  value= ADCL>>2;


  value|= (ADCH<<6);    


       将转换结果存进 value 中


    (6)最后利用公式temperature= value*0.06229-311.43,计算出温度值并返回即可


CC2430 小贴士


  你一定会对最后一个公式感到莫名其妙,为什么是一次函数?为什么其斜率为0.06229,其截距为211.43?OK,下面解惑之:


  此温度传感器是位于CC2430片内的,所以必然可以在其手册中找到其介绍。果不其然,我在电气规范这一节中找到了相关内容,现截图如下:



  此表是描述温度传感器的温度(℃)与输出电压(V)的关系。


  首先看第二个红框处:温度系数。系数?是不是有点感觉?然后再看其单位:mV/℃,你就会恍然大悟,原来温度与电压的关系是线性的啊~ 即有:




  其中V为输出电压值,T为温度值,2.45为斜率。下面就要确定截距b了。


  乍一看,我们会在第一个红框处发现0℃时的电压为743mV,那么b就等于743?不然,继续往下看,你会发现其绝对误差达到了8℃之多!然后往右看,我们会发现它已经提供了最适合的截距,即:b=763,因此有如下公式:




  OK,现在我们已经有了温度传感器的输入温度T 和输出电压V 的关系,接下来必须找到ADC的输入电压V 与输出值N(即14位的转换结果)的关系,才可最终找到N和T的转换公式。


  转换结果N是14位的,当N=11 1111 1111 1111(二进制)时,输出电压应为最大值(即参考电压1.25V)。因此我们有下面的比例关系:



  (注:由于14位的输出结果是2进制的补码,因此第14位为符号位。所以从绝对值的角度来说,有效值只有13位,因此是2的13次方)  


  结合两式,可导出T与N的关系:




  OVER~


  最后,稍微提一下为什么每次采样需要进行64循环。因为传感器在测定温度时,难免会受到干扰或者随机性的error,其得到的数据有时候会很夸
张(比如说忽然出现10℃的变动,然后又瞬间回复正常。但我们知道温度的变化是一个积分的过程,很少会出现那种在瞬间产生大幅度跳跃的情况)。因此我们采
用了取平均值的方法来减少此类误差。


(4)实验结果


  首先打开串口调试工具,然后下载程序并启动,就会出现如下画面:




  片内温度大概在14.5℃左右。笔者用身体感受寝室的室温,大概在10℃多一点。芯片内部多少要发点热,所以14℃基本正常啦~


  到此,实验结束。    


三、结语


  本篇介绍了ADC单次采样的实现。下一节,我们来介绍一种数据传输模式DMA(direct memory
access),即直接内存存取。ADC/UART/RF收发器等外设单元和存储器件之间,可以直接在DMA控制器的控制下交换数据而几乎不需要CPU的
干预,因此可大大提高了系统的整体效率。


  敬请期待!


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)