发 帖  

[经验] 牛人Zigbee学习经验(六)之ADC单次采集

2016-3-2 09:43:26  3980 温度传感器 无线
分享
5
牛人Zigbee学习经验(六)之ADC单次采集

上一篇,我们学习了CC2430PC之间的串口通信。CC2430内部已嵌入一个温度传感器,而将传感的模拟值转换成数字量用于传输和处理数据是无线网路里面很重要的一项。这一节我们将本节将做一个片内温度监测的小实验:利用ADC将片内温度传感器的电压值转换成数字量,利用公式计算出温度值,然后通过串口将温度值传送到PC上并显示出来。
二、ADC单次采样
1)实验简介
  利用ADC转换CC2430片内温度传感器的温度值,通过串口将温度值发送到PC并显示出来。
2)程序流程图
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(*s != 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一般涉及到6SFR
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.43OK,下面解惑之:
  此温度传感器是位于CC2430片内的,所以必然可以在其手册中找到其介绍。果不其然,我在 电气规范 这一节中找到了相关内容,现截图如下:
  此表是描述温度传感器的温度()与输出电压(V)的关系。
  首先看第二个红框处:温度系数。系数?是不是有点感觉?然后再看其单位:mV/℃,你就会恍然大悟,原来温度与电压的关系是线性的啊~ 即有:
  其中V为输出电压值,T为温度值,2.45为斜率。下面就要确定截距b了。
  乍一看,我们会在第一个红框处发现0℃时的电压为743mV,那么b就等于743?不然,继续往下看,你会发现其绝对误差达到了8℃之多!然后往右看,我们会发现它已经提供了最适合的截距,即:b=763,因此有如下公式:
  OK,现在我们已经有了温度传感器的 输入温度T 输出电压V 的关系,接下来必须找到ADC 输入电压V 输出值N(即14位的转换结果)的关系,才可最终找到NT的转换公式。
  转换结果N14位的,当N=11 1111 1111 1111(二进制)时,输出电压应为最大值(即参考电压1.25V)。因此我们有下面的比例关系:
  (注:由于14位的输出结果是2进制的补码,因此第14位为符号位。所以从绝对值的角度来说,有效值只有13位,因此是213次方)  
  结合两式,可导出TN的关系:
  OVER~
  最后,稍微提一下为什么每次采样需要进行64循环。因为传感器在测定温度时,难免会受到干扰或者随机性的error,其得到的数据有时候会很夸张(比如说忽然出现10℃的变动,然后又瞬间回复正常。但我们知道温度的变化是一个积分的过程,很少会出现那种在瞬间产生大幅度跳跃的情况)。因此我们采用了取平均值的方法来减少此类误差。
4)实验结果
  首先打开串口调试工具,然后下载程序并启动,就会出现如下画面:
  
片内温度大概在14.5℃左右。笔者用身体感受寝室的室温,大概在10℃多一点。芯片内部多少要发点热,所以14℃基本正常啦~
  到此,实验结束。    
三、结语
  本篇介绍了ADC单次采样的实现。下一节,我们来介绍一种数据传输模式 DMAdirect memory access),即直接内存存取ADC/UART/RF收发器等外设单元和存储器件之间,可以直接在“DMA控制器的控制下交换数据而几乎不需要CPU的干预,因此可大大提高了系统的整体效率。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
执着~~~ 2016-3-3 19:57:10
牛牛牛牛牛牛牛牛牛牛牛
回复

举报

彦辰110 2018-5-8 16:39:19
双击666,666可以
回复

举报

jjwangxu2008 2018-7-13 07:36:18
牛牛牛牛牛牛牛牛牛牛牛
回复

举报

只有小组成员才能发言,加入小组>>

171个成员聚集在这个小组

加入小组

创建小组步骤

关闭

站长推荐 上一条 /8 下一条

快速回复 返回顶部 返回列表