打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

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

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

 一、承上启下

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

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

  二、ADC单次采样

  (1)实验简介

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

  (2)程序流程图

  (3)实验源码及剖析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
    实验说明:片内温度采集实验,通过串口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一般涉及到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
0
(请您对文章做出评价)
博主前一篇:Zigbee之旅(五):几个重要的CC2430基础实验——串口通信(转)
博主后一篇:Zigbee之旅(七):几个重要的CC2430基础实验——DMA传输(转)
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
CC2530 ADC实验1(读取片内温度并通过串口显示)
MQ-2烟雾传感器
Mini2440触摸屏程序分析
基于NTC热敏电阻和nRF24L01的无线温度计设计
LM3S1138作为下位机,用于电压采集、脉冲发生、电流采集、频率测量、脉冲测量等
ad_imh
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服