CC2530基础实验五 ADC转换实验

发布于 / 诗与故事

####一、任务分析

编写程序实现实验板测定芯片外部光敏传感器的电压,通过串口发送电压值。实验板安装上光线传感器,光线的强弱转换成电压的高低,经ADC转换以后通过串口将电压值发送给PC,可以通过串口调试软件读取电压值。每发送一次电压值的字符串消息,LED1闪亮一次。具体工作方式如下:

①通电后LED1熄灭。
②UART0初始化。
③设置ADC。
④LED1点亮。
⑤开启单通道ADC。
⑥ADC对通道0进行模数转换测量电压。
⑦发送字符串“光照传感器电压值”与测量电压值。
⑧LED1熄灭。
⑨延时一段时间,延时时间可以设置为3秒。
⑩返回步骤④循环执行。

1.电信号的形式与转换
信息是指客观事物属性和相互联系特性的表征,它反映了客观事物的存在形式和运动状态。表示信息的形式可以是数值、文字、图形、声音、图像以及动画等。信号是信息的载体,是运载信息的工具,信号可以是光信号、声音信号、电信号。电话网络中的电流就是一种电信号,人们可以将电信号经过发送、接收以及各种变换,传递着双方要表达的信息。数据是把事件的属性规范化以后的表现形式,它能被识别,可以被描述,是各种事物的定量或定性的记录。信号数据可以表示任何信息,如文字、符号、语音、图像、视频等等。
从电信号的表现形式上,可以分为模拟信号和数字信号。

(1)模拟信号
模拟信号是指用连续变化的物理量所表达的信息,如温度、湿度、压力、长度、电流、电压等等,我们通常又把模拟信号称为连续信号,它在一定的时间范围内可以有无限多个不同的取值。
(2)数字信号
数字信号指自变量是离散的、因变量也是离散的信号,这种信号的自变量用整数表示,因变量用有限数字中的一个数字来表示,在计算机中,数字信号的大小常用有限位的二进制数表示。由于数字信号是用两种物理状态来表示0和1的,故其抵抗材料本身干扰和
和环境干扰的能力都比模拟信号强很多;在现代技术的信号处理中,数字信号发挥的作用越来越大,几乎复杂的信号处理都离不开数字信号,只要能把解决问题的方法用数学公式表示,就能用计算机来处理代表物理量的数字信号。
(3)模拟/数字转换
模拟/数字转换通常简写为ADC,是将输入的模拟信号转换为数字信号。各种被测控的物理量(如:速度、压力、温度、光照强度、磁场等)是一些连续变化的物理量,传感器将这些物理量转换成与之相对应的电压和电流就是模拟信号。单片机系统只能接收数字信号,要处理这些信号就必须把他们转换成数字信号。模拟/数字转换是数字测控系统中必须的信号转换。

2.CC2530的ADC模块
CC2530的ADC模块支持最高14位二进制的模拟数字转换,具有12位的有效数据位。它包括一个模拟多路转换器,具有8个各自可配置的通道;以及一个参考电压发生器。转换结果通过DMA写入存储器,还具有多种运行模式。ADC模块结构如图6-1所示。
CC2530的ADC模块有如下主要特征:

可选的抽取率,设置分辨率(7到12位)
8个独立的输入通道,可接收单端或差分信号
参考电压可选为内部单端、外部单端、外部差分或AVDD5
转换结束产生中断请求
转换结束时可发出DMA触发
 可以将片内温度传感器作为输入
 电池电压测量功能

3.ADC的工作模式

(1)ADC模块的输入
对于CC2530的ADC模块,端口P0引脚可以配置为ADC输入端,依次为AIN0~AIN7。可以把输入配置为单端或差分输入。在选择差分输入的情况下,差分输入包括输入对AIN0-AIN1、AIN2-AIN3、AIN4-AIN5和AIN6-AIN7。除了输入引脚AIN0-AIN7,片上温度传感器的输出也可以选择作为ADC的输入用于温度测量;还可以输入一个对应AVDD5/3的电压作为一个ADC输入,在应用中这个输入可以实现一个电池电压监测器的功能。特别提醒,负电压和大于VDD(未调节电压)
的电压都不能用于这些引脚。它们之间的转换结果是在差分模式下每对输入端之间的电压差值。
8位模拟量输入来自I/O引脚,不必通过编程将这些引脚变为模拟输入,但是,当相应的模拟输入端在APCFG寄存器中被禁用时,此通道将被跳过。当使用差分输入时,相应的两个引脚都必须在APCFG寄存器中设置为模拟输入引脚。APCFG寄存器如表6-1所示。
(2)序列ADC转换与单通道ADC转换
CC2530的ADC模块可以按序列进行多通道的ADC转换,并把结果通过DMA传送到存储器,而不需要CPU任何参与。
转换序列可以由APCFG寄存器设置,八位模拟输入来自I/O引脚,不必经过编程变为模拟输入。如果一个通道是模拟I/O输入,它就是序列的一个通道,如果相应的模拟输入在APCFG中禁用,那么此I/O通道将被跳过。当使用差分输入,处于差分对的两个引脚都必须在APCFG寄存器中设置为模拟输入引脚。
寄存器位ADCCON2.SCH用于定义一个ADC转换序列。如果ADCCON2.SCH设置为一个小于8的值,ADC转换序列包括从0通道开始,直到并包括ADCCON2.SCH所设置的通道号码。当ADCCON2.SCH设置为一个在8和12之间的值,转换序列包括从通道8开始差分输入,到ADCCON2.SCH所设置的通道号码结束。
除可以设置为按序列进行ADC转换之外,CC2530的ADC模块可以编程实现任何单个通道执行一个转换,包括温度传感器(14)和AVDD5/3(15)两个通道。单通道ADC转换通过写ADCCON3寄存器触发,转换立即开始。除非一个转换序列已经正在进行,在这种情况下序列一完成,单个通道的ADC转换就会被执行。

####二、初始化
1、定义结果变量;
unsigned long value; //无符号long类型
2、ADC初始化
APCFG |= 1; //模拟 I/O 使能
P0SEL |= 0X01; //片上外设
P0DIR &= ~0X01; //设置输入模式
ADCIF = 0; //ADC中断标志位
3、参考电压、分辨率、序列通道选择(ADCCON2/ADCCON3)
ADCCON3 = 0X90; //AVDD5引脚;9位分辨率;
3、采用基准电压 acdd5: 3.3v,通道0, 启动 AD 转换
ADCCON3 = (0x80 | 0x10 | 0x00);
4、等待ADC转换结束
while(!ADCIF);
5、得到的数据放到变量value 中
value = ADCH;
value = value << 8;
value |= ADCL;
value = value*330; //电压值 = (value * 3.3) / 32768
value = value >>15; // value * 330 是为了后面处理数据所以多乘 100
6、返回value值 unsigned short 类型
return value;

这里写图片描述

ADC数据处理(光电传感器)

buf[0] = val / 100 + ‘0’;
buf[1] = ‘.’;
buf[2] = val / 10 % 10 + ‘0’;
buf[3] = val % 10 + ‘0’;
buf[4] = ‘V’;
buf[5] = ‘\n’;

寄存器

ADCCON1
    选择ADC的启动模式和开启AD转换
    例如:设置ADC的启动模式为手动,并开启AD转换
      ADCCON1 |= 0X30;   //选择ADC的启动模式为手动
      ADCCON1 |= 0X40;   //开启AD转换

这里写图片描述
ADCCON2
选择内部参考电压;分辨率;多通道选择
与ADCCON3的区别是单/多通道的选择,其他配置相同。
这里写图片描述

ADCCON3
选择内部参考电压;分辨率;单通道选择
与ADCCON3的区别是单/多通道的选择,其他配置相同。
例如:选择内部参考电压;12位分辨率;对片内温度传感器采样
  ADCCON3 = 0X3E;

这里写图片描述

ADCL、ADCH
注意:低8位的0、1位一直为0;

这里写图片描述
APCFG
这里写图片描述
这里写图片描述
ADCIF
ADC中断标志

这里写图片描述

###代码实现
/* 包含头文件 */
#include “ioCC2530.h”
#include <string.h>

#define LED1 P1_0     // P1_0定义为P1_0  led灯端口
#define uint16 unsigned short
#define uint32 unsigned long
#define uint unsigned int

unsigned int flag,counter=0; //统计溢出次数
unsigned char s[8];//定义一个数组大小为8

void InitLED()
{
    P1SEL&=~0X01;          //P1_0设置为普通的IO口 1111 1110
    P1DIR |= 0x01;              //配置P1_0的方向为输出
    LED1=0;
}

void adc_Init(void)
{
    APCFG  |=1;
    P0SEL  |= 0x01; 
    P0DIR  &= ~0x01;    
}
/************************************************************
* 名称       get_adc
* 功能       读取ADC通道0电压值
* 入口参数   无
* 出口参数   16位电压值,分辨率为10mV
***************获取ADC通道0电压值************************/
uint16 get_adc(void)
{
    uint32 value;
    ADCIF = 0;   //清ADC 中断标志
    //采用基准电压avdd5:3.3V,通道0,启动AD转化
    ADCCON3 = (0x80 | 0x10 | 0x00);
    while ( !ADCIF )
    {
        ;  //等待AD转化结束
    }
    value = ADCH;
    value = value<< 8;
    value |= ADCL;
    // AD值转化成电压值
    // 0 表示 0V ,32768 表示 3.3V
    // 电压值 = (value*3.3)/32768 (V)
    value = (value * 330);
    value = value >> 15;   // 除以32768
    // 返回分辨率为0.01V的电压值
    return (uint16)value;
}
/**********串口通信初始化************************/
void initUART0(void)
{
    PERCFG = 0x00;  
    P0SEL = 0x3c;   
    U0CSR |= 0x80;
    U0BAUD = 216;
    U0GCR = 10;
    U0UCR |= 0x80;
    UTX0IF = 0;  // 清零UART0 TX中断标志
    EA = 1;   //使能全局中断
}

/*************************************************
* 函数名称:inittTimer1
* 功    能:初始化定时器T1控制状态寄存器
******************定时器初始化*****************************/
void inittTimer1()
{
    CLKCONCMD &= 0x80;   //时钟速度设置为32MHz
    T1CTL = 0x0E;    // 配置128分频,模比较计数工作模式,并开始运行
    T1CCTL0 |= 0x04;  //设定timer1通道0比较模式
    T1CC0L =50000 & 0xFF;    // 把50000的低8位写入T1CC0L
    T1CC0H = ((50000 & 0xFF00) >> 8); //把50000的高8位写入T1CC0H

    T1IF=0;           //清除timer1中断标志(同IRCON &= ~0x02)
    T1STAT &= ~0x01;  //清除通道0中断标志

    TIMIF &= ~0x40;  //不产生定时器1的溢出中断
    //定时器1的通道0的中断使能T1CCTL0.IM默认使能
    IEN1 |= 0x02;    //使能定时器1的中断
    EA = 1;        //使能全局中断
}
/***********************************************************
* 函数名称:UART0SendByte
* 功    能:UART0发送一个字节
* 入口参数:c
* 出口参数:无
* 返 回 值:无
************************************************************/
void UART0SendByte(unsigned char c)
{
    U0DBUF = c;     // 将要发送的1字节数据写入U0DBUF
    while (!UTX0IF) ;  // 等待TX中断标志,即U0DBUF就绪
    UTX0IF = 0;       // 清零TX中断标志
}

/**************************************************************
* 函数名称:UART0SendString
* 功    能:UART0发送一个字符串
* 入口参数:*str
* 出口参数:无
* 返 回 值:无
**********************************************************/
void UART0SendString(unsigned char *str)
{
    while(*str != '\0')
    {
        UART0SendByte(*str++);   // 发送一字节
    }
}

/**************获取电压值并处理数据******************/
void Get_val()
{
    uint16 sensor_val;
    sensor_val=get_adc();
    s[0]=sensor_val/100+'0';
    s[1]='.';
    s[2]=sensor_val/10%10+'0';
    s[3]=sensor_val%10+'0';
    s[4]='V';
    s[5]='\n';
    s[6]='\0';
}
/******************************************
* 功    能:定时器T1中断服务子程序
************************************/
#pragma vector = T1_VECTOR //中断服务子程序
__interrupt void T1_ISR(void)
{
    EA = 0;   //禁止全局中断
    counter++;
    T1STAT &= ~0x01;  //清除通道0中断标志
    EA = 1;   //使能全局中断
}
/******************************************
* 函数名称:main
* 功    能:main函数入口
* 入口参数:无
* 出口参数:无
* 返 回 值:无
**************************************************/
void main(void)
{
    InitLED();
    inittTimer1();  //初始化Timer1
    initUART0();  // UART0初始化
        adc_Init(); // ADC初始化
    while(1)
    {
        if(counter>=15)     //定时器每0.2S溢出中断计次
           {
            counter=0;       //清标志位
            LED1 = 1;    //指示灯点亮
            Get_val();
            UART0SendString("光照传感器电压值  ");
            UART0SendString(s); 
            LED1 = 0;    //指示灯熄灭
            }
    }
}
本文采用 CC BY-NC-SA 3.0 Unported 协议进行许可
本文链接: https://www.ahwgs.cn/cc2530jichushiyanwu-adczhuanhuanshiyan.html