所有课程见此链接:
4.7 AD采集内部温度实验
1.学习CC2530内部温度传感器控制;
2.学习AD数据采集;
3.实现CC2530温度采集并通过串口发送到上位机。
温度检测在工业现场以及物联网领域都有着较为广泛的应用,对于智能控制需要以采集到的环境温度作为控制依据,CC2530单片机在芯片的内部就集成了温度传感器,不需要再外接温度传感器电路,提高了系统的集成度,降低了电路设计的复杂度,但是传感器与MCU的集成由于芯片本身的发热会导致检测温度的偏差,通常需要软件的矫正。
要实现CC2530的温度检测并通过串口发送给上位机,在串口通信部分已经将通信解决,在需要的就是AD与温度检测寄存器的相关配置,所涉及到的寄存器有:
CC2530 的内部温度检测需要配置的寄存器比较多,包括温度和 AD 的
CLKCONCMD、PERCFG、U0CSR、U0GSR、U0BAUD、CLKCONSTA、IEN0、U0DUB、ADCCON1、ADCCON3、ADCH、ADCL。各寄存器功能如下表4-6所示:
表4-6 AD温度检测相关寄存器功能描述
ADC控制寄存器1ADCCON1(0XB4) |
ADC 转换完成标志位Bit7:EOC |
0:AD 转换进行中 |
1:AD 转换完成 |
||
手动启动 AD 转换 Bit6:RE |
0:关 |
|
1:启动 AD 转换(需要 Bit5:Bit4=11) |
||
AD 转换启动方式选择 Bit[5:4] |
00:外部触发 |
|
01:全速转换,不需要触发 |
||
10:T1 通道 0 比较触发 |
||
11:手动触发 |
||
16 位随机数发生器控制位 Bit[3:2]FE |
00:普通模式 (13x 打开) |
|
01:开启 LFSR 时钟一次 (13x 打开) |
||
10:保留位 |
||
11:关 |
||
序列 AD 转换控制寄存器 2ADCCON2(0XB5) |
选择 AD 转换参考电压SREF Bit[7:6] |
00:内部参考电压(1.25V) |
01:外部参考电压 AIN7 输入 |
||
10:模拟电源电压 |
||
11:外部参考电压 AIN6-AIN7 差分输入 |
||
设置 AD 转换分辨率Bit[5:4] |
00: 64dec,7位有效 |
|
01: 128dec,9位有效 |
||
10: 256dec,10位有效 |
||
11: 512dec,12位有效 |
||
设置序列 AD 转换最末通道,如果置位 时 ADC 正在运行,则在完成序列 AD 转换后立刻开始, 否则置位后立即开始 AD 转换,转换完成后自动清 0. Bit[3:0]ORDER |
0000: AIN0 |
|
0001: AIN1 |
||
0010: AIN2 |
||
0011: AIN3 |
||
0100: AIN4 |
||
0101: AIN5 |
||
0110: AIN6 |
||
0111: AIN7 |
||
1000: AIN0-AIN1 差分 |
||
1001: AIN2-AIN3 差分 |
||
1010: AIN4-AIN5 差分 |
||
1011: AIN6-AIN7 差分 |
||
1100:GND |
||
1101:保留 |
||
1110:温度传感器 |
||
1111:1/3模拟电源电压 |
||
Bit[4:0]:BAUD_E |
波特率指数值 BAUD_E 连同 BAUD_M 一起决定了 UART 的波特率 |
|
单通道 AD 转换控制寄存器 2 ADCCON3(0XB5) |
选择单通道AD 转换参考电压SREF Bit[7:6]: |
00:内部参考电压(1.25V) |
01:外部参考电压 AIN7 输入 |
||
10:模拟电源电压 |
||
11 :外部参考电压 AIN6-AIN7 差分输入 |
||
设置单通道 AD 转换分辨率 Bit[5:4] |
00: 64dec,7 位有效 |
|
01: 128dec,9 位有效 |
||
10: 256dec,10 位有效 |
||
11: 512dec,12 位有效 |
||
单通道 AD 转换选择,如果置位时 ADC 正在运行,则在完成 AD 转换后立刻开始,否则置位后 立即开始 AD 转换,转换完成后自动清 0. Bit[3:0] |
0000:AIN0 |
|
0001: AIN1 |
||
0010:AIN2 |
||
0011: AIN3 |
||
0100:AIN4 |
||
0101: AIN5 |
||
0110:AIN6 |
||
0111: AIN7 |
||
1000:AIN0-AIN1 差分 |
||
1001: AIN2-AIN3 差分 |
||
1010:AIN4-AIN5 差分 |
||
1011: AIN6-AIN7 差分 |
||
1100:GND |
||
1101:保留 |
||
1110:温度传感器 |
||
1111:1/3 模拟电源电压 |
||
TR0 (0x624B) |
Bit0 |
置 1 表示将温度传感器与 ADC 连接起来 |
ATEST(0x61BD) |
Bit0 |
置 1 表示将温度传感器启用 |
根据表中相关寄存器的功能说明,具体进行如下配置:
TR0 = 0X01; //置”1”连接温度传感器与AD采集
ATEST= 0X01; // 使能温度传感器功能
AD 数据采集配置:
ADCCON3 = (0x3E); //选择 1.25V 为参考电压;14 位分辨率;片内采样
ADCCON1 |= 0x30; //选择 ADC 的启动模式为手动
ADCCON1 |= 0x40; //启动 AD 转换
具体程序如下:
#include <ioCC2530.h>
#define uint unsigned int
#define uchar unsigned char
#define uint16 unsigned short
#define DISABLE_ALL_INTERRUPTS() (IEN0 = IEN1 = IEN2 = 0x00)
/**************************
系统时钟 不分频
计数时钟 32分频
**************************/
void InitClock(void)
{
CLKCONCMD &= ~0x40; //设置系统时钟源为 32MHZ晶振
while(CLKCONSTA & 0x40); //等待晶振稳定
CLKCONCMD &= ~0x47; //设置系统主时钟频率为 32MHZ
}
/********************************************************
温度传感器初始化函数
********************************************************/
void initTempSensor(void)
{
DISABLE_ALL_INTERRUPTS(); //关闭所有中断
InitClock(); //设置系统主时钟为 32M
TR0=0X01; //set '1' to connectthe temperature sensorto the SOC_ADC.
ATEST=0X01; // Enablesthe temperature sensor
}
/****************************************************************
读取温度传感器 AD 值函数
****************************************************************/
float getTemperature(void)
{
uint value;
ADCCON3 = (0x3E); //选择1.25V为参考电压;14位分辨率;对片内温度传感器采样
ADCCON1 |= 0x30; //选择ADC的启动模式为手动
ADCCON1 |= 0x40; //启动AD转化
while(!(ADCCON1 & 0x80)); //等待 AD 转换完成
value = ADCL >> 4; //ADCL 寄存器低 2 位无效
value |= (((uint16)ADCH) << 4);
return (value-1367.5)/4.5-5; //根据 AD 值,计算出实际的温度,芯片手册有错,温度系数应该是4.5 /℃
//进行温度校正,这里减去5℃(不同芯片根据具体情况校正)
}
/*****************************************
串口初始化函数:初始化串口 UART0
*****************************************/
void InitUART0(void)
{
PERCFG = 0x00; //位置1 P0口
P0SEL = 0x3c; //P0用作串口
P2DIR &= ~0XC0; //P0优先作为UART0
U0CSR |= 0x80; //串口设置为UART方式
U0GCR |= 8;
U0BAUD |= 59; //波特率设为9600
UTX0IF = 1; //UART0 TX中断标志初始置位1
U0CSR |= 0X40; //允许接收
IEN0 |= 0x84; //开总中断,接收中断
}
/****************************************************************
串口发送字符串函数
****************************************************************/
void UartTX_Send_String(char *Data,int len)
{
int j;
for(j=0;j<len;j++)
{
U0DBUF = *Data++;
while(UTX0IF == 0);
UTX0IF = 0;
}
U0DBUF = 0x0A; //换行
while(UTX0IF == 0);
UTX0IF = 0;
}
/****************************
//延时函数
*****************************/
void Delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=587;j>0;j--);
}
/****************************************************************
主函数
****************************************************************/
void main(void)
{
char i;
char TempValue[7];
float AvgTemp;
InitUART0(); //初始化串口
initTempSensor(); //初始化 ADC
while(1)
{
AvgTemp = 0;
for(i = 0 ; i < 64 ; i++)
{
AvgTemp += getTemperature();
AvgTemp=AvgTemp/2; //每次累加后除 2
}
/****温度转换成ascii码发送****/
TempValue[0] = (unsigned char)(AvgTemp)/10 + 48; //十位
TempValue[1] = (unsigned char)(AvgTemp)%10 + 48; //个位
TempValue[2] = '.'; //小数点
TempValue[3] = (unsigned char)(AvgTemp*10)%10+48; //十分位
TempValue[4] = (unsigned char)(AvgTemp*100)%10+48; //百分位
TempValue[5] = '\r'; //字符串结束符
TempValue[6] = '\n';
UartTX_Send_String( TempValue,7);
Delayms(2000); //使用32M晶振,故这里2000约等于1S
}
}
图4-9 实验效果图
扩展知识——AD模数转换
以8位的寄存器为例, A/D转换器片内有D/A转换和电压比较器,首先向片内D/A转换器输入1000 0000,若电压比较器:VIN > VN (VN为片内D/A转换的输出,VIN为A/D转换器的输入电压),N位寄存器的首位置1 (若VIN < VN,则寄存器首位写0);再向D/A转换输入1100 0000(首位写0时,输入0111 1111),若VIN > VN则寄存器第二位置1(若VIN < VN,则写0);再向D/A转换输入1110 0000(或0011 1111),若VIN > VN则寄存器第三位置1(若小于,则写0);依次下去直到寄存器第8位赋值结束,控制逻辑监测到比较放大器进行8次后,EOC输入信号,让A/D转换器将结果通过锁存缓存器输出至D0~D9。