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

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

一、承上启下

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

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

二、ADC单次采样

(1)实验简介

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

(2)程序流程图

Zigbee之旅(六):几个重要的CC2430基础实验——ADC单次采样_第1张图片

(3)实验源码及剖析

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

#include <ioCC2430.h>

#define led1 P1_0
#define led2 P1_1
#define led3 P1_2
#define led4 P1_3

/*32M晶振初始化
-------------------------------------------------------*/
void  xtal_init( void)
{
   SLEEP  &=  ~ 0x04;              //都上电
   while( !( SLEEP  &  0x40));      //晶体振荡器开启且稳定
   CLKCON  &=  ~ 0x47;           //选择32MHz 晶体振荡器
   SLEEP  |=  0x04;
}

/*LED灯初始化
-------------------------------------------------------*/
void  led_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( unsigned  char  StopBits , unsigned  char  Parity)
{
    P0SEL  |=   0x0C;                   //初始化UART0端口
    PERCFG &=  ~ 0x01;                   //选择UART0为可选位置一
    U0CSR  =  0xC0;                     //设置为UART模式,而且使能接受器
    U0GCR  =  11;
    U0BAUD  =  216;                     //设置UART0波特率为115200bps
    U0UCR  |=  StopBits| Parity;         //设置停止位与奇偶校验
}

/*UART0发送字符
-------------------------------------------------------*/
void   Uart0Send( unsigned  char  data)
{
   while( U0CSR & 0x01);     //等待UART空闲时发送数据
   U0DBUF  =  data;
}

/*UART0发送字符串
-------------------------------------------------------*/
void  Uart0SendString( unsigned  char  *s)
{
   while( *!=  0)
     Uart0Send( *s ++);
}

/*UART0接收数据
-------------------------------------------------------*/
unsigned  char  Uart0Receive( void)
{
   unsigned  char  data;
   while( !( U0CSR & 0x04));  //查询是否收到数据,否则继续等待
   data = U0DBUF;
   return  data;
}

/*延时函数
-------------------------------------------------------*/
void  Delay( unsigned  int n)
{
   unsigned  int  i;
   for( i = 0; i <n; i ++);
   for( i = 0; i <n; i ++);
   for( i = 0; i <n; i ++);
   for( i = 0; i <n; i ++);
   for( i = 0; i <n; i ++);
}

/*得到实际温度值
-------------------------------------------------------*/
float  getTemperature( void
{
   unsigned  int   value;

   ADCCON3   = ( 0x3E);                   //选择1.25V为参考电压;14位分辨率;对片内温度传感器采样
    
   ADCCON1  |=  0x30;                     //选择ADC的启动模式为手动
   ADCCON1  |=  0x40;                     //启动AD转化             
    
   while( !( ADCCON1  &  0x80));            //等待ADC转化结束

   value  =   ADCL  >>  2;
   value  |= ( ADCH  <<  6);                //取得最终转化结果,存入value中
  
   return  value * 0.06229 - 311.43;         //根据公式计算出温度值
}

/*主函数
-------------------------------------------------------*/
void  main( void)
{
   char  i;
   float  avgTemp;
   unsigned  char  output [] = "";
        
   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 ]  = ( unsigned  char)( avgTemp) / 10  +  48;           //十位
     output [ 1 ]  = ( unsigned  char)( avgTemp) % 10  +  48;           //个位
     output [ 2 ]  =  '.';                                        //小数点 
     output [ 3 ]  = ( unsigned  char)( avgTemp * 10) % 10 + 48;          //十分位
     output [ 4 ]  = ( unsigned  char)( 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片内的,所以必然可以在其手册中找到其介绍。果不其然,我在 电气规范 这一节中找到了相关内容,现截图如下:

Zigbee之旅(六):几个重要的CC2430基础实验——ADC单次采样_第2张图片  此表是描述温度传感器的温度(℃)与输出电压(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)。因此我们有下面的比例关系:

Zigbee之旅(六):几个重要的CC2430基础实验——ADC单次采样_第3张图片  (注:由于14位的输出结果是2进制的补码,因此第14位为符号位。所以从绝对值的角度来说,有效值只有13位,因此是2的13次方)   

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

Zigbee之旅(六):几个重要的CC2430基础实验——ADC单次采样_第4张图片

  OVER~

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

(4)实验结果

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

Zigbee之旅(六):几个重要的CC2430基础实验——ADC单次采样_第5张图片  片内温度大概在14.5℃左右。笔者用身体感受寝室的室温,大概在10℃多一点。芯片内部多少要发点热,所以14℃基本正常啦~

  到此,实验结束。    

三、结语

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

你可能感兴趣的:(嵌入式,物联网,智能家居,zigbee)