编写程序实现实验板测定芯片外部光敏传感器的电压,通过串口发送电压值。实验板安装上光线传感器,光线的强弱转换成电压的高低,经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;
/* 包含头文件 */
#include "ioCC2530.h"
#include
#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; //指示灯熄灭
}
}
}