然后再对SAR寄存器的次高位置“1”,依上述方法进行D/A转换和比较。
如此重复上述过程,直至确定SAR寄存器的最低位为止。
过程结束后,状态线改变状态,表明已完成一次转换。
最后,逐次逼近寄存器SAR中的内容就是与输入模拟量V相对应的二进制数字量。
显然A/D转换器的位数N决定于SAR的位数和D/A的位数。
图2.4.1(b)表示四位A/D转换器的逐次逼近过程。
转换结果能否准确逼近模拟信号,主要取决于SAR和D/A的位数。
位数越多,越能准确逼近模拟量,但转换所需的时间也越长。
z逐次逼近式的A/D转换器的主要特点是:
转换速度较快,在1—100/μs以内,分辨率可以达18位,特别适用于工业控制系统。
转换时间固定,不随输入信号的变化而变化。
抗干扰能力相对积分型的差。
例如,对模拟输入信号采样过程中,若在采样时刻有一个干扰脉冲迭加在模拟信号上,则采样时,包括干扰信号在内,都被采样和转换为数字量,这就会造成较大的误差,所以有必要采取适当的滤波措施。
图2.4.1逐次逼近式A/D转换器
2、A/D转换的重要指标
¾分辨率(Resolution)
分辨率反映A/D转换器对输入微小变化响应的能力,通常用数字输出最低位(LSB)所对应的
模拟输入的电平值表示。
n位A/D能反应1/2n满量程的模拟输入电平。
由于分辨率直接与
转换器的位数有关,所以一般也可简单地用数字量的位数来表示分辨率,即n位二进制数,最低位所具有的权值,就是它的分辨率。
值得注意的是,分辨率与精度是两个不同的概念,不要把两者相混淆。
即使分辨率很高,也可能由于温度漂移、线性度等原因,而使其精度不够高。
¾精度(Accuracy)
精度有绝对精度(AbsoluteAccuracy)和相对精度(RelativeAccuracy)两种表示方法。
z绝对误差:
在一个转换器中,对应于一个数字量的实际模拟输入电压和理想的模拟输入电压之差并非
是一个常数。
我们把它们之间的差的最大值,定义为“绝对误差”。
通常以数字量的最小有效位(LSB)的分数值来表示绝对误差,例如:
±1LSB等。
绝对误差包括量化误差和其它所有误差。
z相对误差是指整个转换范围内,任一数字量所对应的模拟输入量的实际值与理论值之差,用模拟电
压满量程的百分比表示。
例如,满量程为10V,10位A/D芯片,若其绝对精度为±1/2LSB,则其最小有效位的量化单位:
9.77mV,其绝对精度为=4.88mV,其相对精度为0.048%。
z转换时间(ConversionTime)
转换时间是指完成一次A/D转换所需的时间,即由发出启动转换命令信号到转换结束信号开始有效的时间间隔。
转换时间的倒数称为转换速率。
例如AD570的转换时间为25us,其转换速率为40KHz。
z电源灵敏度(powersupplysensitivity)
电源灵敏度是指A/D转换芯片的供电电源的电压发生变化时,产生的转换误差。
一般用电源电压变化1%时相当的模拟量变化的百分数来表示。
z量程
量程是指所能转换的模拟输入电压范围,分单极性、双极性两种类型。
例如,单极性量程为0~+5V,0~+10V,0~+20V;
双极性量程为-5~+5V,-10~+10V。
z输出逻辑电平
多数A/D转换器的输出逻辑电平与TTL电平兼容。
在考虑数字量输出与微处理的数据总线接口时,应注意是否要三态逻辑输出,是否要对数据进行锁存等。
z工作温度范围
由于温度会对比较器、运算放大器、电阻网络等产生影响,故只在一定的温度范围内才能
保证额定精度指标。
一般A/D转换器的工作温度范围为(0~700C),军用品的工作温度范围为(-55~+1250C)
¾ARM自带的十位A/D转换器
ARMS3C2410芯片自带一个8路10位A/D转换器,并且支持触摸屏功能。
ARM2410开发板只用作3路A/D转换器,其最大转换率为500K,非线性度为正负1.5位,其转换时间可以通过下式计算:
如果系统时钟为50MHz,比例值为49,则为
A/D转换器频率=50MHz/(49+1)=1MHz
转换时间=1/(1MHz/5cycles)=1/200kHz(相当于5us)=5us
表2.4.1采样控制寄存器的设置
寄存器
地址
读/写
描述
复位值
ADCCON
0x58000000
R/W
ADC控制寄存器
0x3FC4
表2.4.2采样控制寄存器的位描述
ADCCON
位
描述
初始设置
ECFLG
[15]
Endofconversionflag(readonly).
0=A/Dconversioninprocess
1=EndofA/Dconversion
0
PRSCEN
[14]
A/Dconverterprescalerenable.
0=Disable
1=Enable
0
PRSCVL
[13:
6]
A/Dconverterprescalervalue.Datavalue:
1~255
Notethatdivisionfactoris(N+1)whentheprescalervalueis
N.
0xFF
SEL_MUX
[5:
3]
Analoginputchannelselect.000=AIN0
001=AIN1
010=AIN2
011=AIN3
100=AIN4
101=AIN5
110=AIN6
111=AIN7(XP)
0
STDBM
[2]
Standbymodeselect.
0=Normaloperationmode
1=Standbymode
1
READ_START
[1]
A/Dconversionstartbyread.
0=Disablestartbyreadoperation
1=Enablestartbyreadoperation
0
ENABLE_START
[0]
A/Dconversionstartsbysettingthisbit.
IfREAD_STARTisenabled,thisvalueisnotvalid.
0=Nooperation1=A/Dconversionstartsandthisbitisclearedafterthestart-up.
0
该寄存器的0位是转换使能位,写1表示转换开始。
1位是读操作使能转换,写1表示转
换在读操作时开始。
3、4、5位是通道号。
[13:
6]位为AD转换比例因子。
14位为比例因子有效位,15位为转换标志位(只读)。
表2.4.3A/D转换结果数据寄存器的设置
寄存器
地址
读/写
描述
复位值
ADCDAT0
0x5800000C
R
ADC转换数据寄存器
-
ADCDAT0:
转换结果数据寄存器。
该寄存器的十位表示转换后的结果,全为1时为满量程
3.3伏。
¾A/D转换器在扩展板的连接
A/D转换器在扩展板的接法如图2.4.2所示,前三路通过电位器接到3.3v电源上。
图2.4.2A/D转换器在扩展板上的接法
六、程序分析(关键代码分析)
ad驱动对用户来说只是下面的一个文件结构。
在用户程序里只需要用到open、read、
write、release等内核函数即可。
本实验采用的是模块方式加载,可以在实验箱的
/mnt/yaffs/ad/中找到AD的驱动程序。
staticstructfile_operationss3c2410_fops={
owner:
THIS_MODULE,open:
s3c2410_adc_open,read:
s3c2410_adc_read,write:
s3c2410_adc_write,
release:
s3c2410_adc_release,
};
下面我们对驱动部分重要函数进行说明。
ad驱动在内核里的代码我们放到了本次实验的src文件下,s3c2410.h_chip.h里为arm2410头文件s3c2410.h初始化ADC的部分。
所有代码也可以到内核里面去阅读。
关于驱动知识的基本介绍请见第4章第一小节,本节只作为应用实验的简单例子。
staticints3c2410_adc_open(structinode*inode,structfile*file)
{
init_MUTEX(&adcdev.lock);init_waitqueue_head(&(adcdev.wait));adcdev.channel=0;adcdev.prescale=0xff;MOD_INC_USE_COUNT;DPRINTK("adcopened\n");
return0;
}//AD通道和比例因子初始化
staticssize_ts3c2410_adc_write(structfile*file,constchar*buffer,size_tcount,loff_t*ppos)
{
intdata;
if(count!
=sizeof(data)){
//errorinputdatasize
DPRINTK("thesizeofinputdatamustbe%d\n",sizeof(data));
return0;
}
copy_from_user(&data,buffer,count);adcdev.channel=ADC_WRITE_GETCH(data);adcdev.prescale=ADC_WRITE_GETPRE(data);
DPRINTK("setadcchannel=%d,prescale=0x%x\n",adcdev.channel,adcdev.prescale);
returncount;
}//告诉内核驱动读哪一个通道的数据和设置比例因子
#defineSTART_ADC_AIN(ch,prescale)\
do{\
ADCCON=PRESCALE_EN|PRSCVL(prescale)|ADC_INPUT((ch));\ADCCON|=ADC_START;\
}while(0)
//PRESCALE_EN左移14使位比例因子有效;PRSCVL左移6位设置比例因子;
//ADC_INPUT左移3位选择通道;
//ADCCON|=ADC_START;ADCCON0为置1,准备采集数据
staticssize_ts3c2410_adc_read(structfile*filp,char*buffer,size_tcount,loff_t*ppos)
{
intret=0;
if(down_interruptible(&adcdev.lock))
return-ERESTARTSYS;START_ADC_AIN(adcdev.channel,adcdev.prescale);interruptible_sleep_on(&adcdev.wait);
ret=ADCDAT0;
ret&=0x3ff;//把数据寄存器内容放入变量ret
DPRINTK("AIN[%d]=0x%04x,%d\n",adcdev.channel,ret,ADCCON&0x80?
1:
0);
copy_to_user(buffer,(char*)&ret,sizeof(ret));
up(&adcdev.lock);
returnsizeof(ret);
//把ret变量的内容传给用户缓冲区
}//由内核采集通道数据后把数据放回用户区
main.c的代码如下:
/************************************************\
*
bythreewater
*
*
2004.06.18
*
\***********************************************/
#include
#include
#include
#include
#include
#include
#include
#include"s3c2410-adc.h"
#defineADC_DEV"/dev/adc/0raw"staticintadc_fd=-1;
staticintinit_ADdevice(void)
{
if((adc_fd=open(ADC_DEV,O_RDWR))<0){
printf("Erroropening%sadcdevice\n",ADC_DEV);
return-1;
}
}
staticintGetADresult(intchannel)
{
intPRESCALE=0XFF;
intdata=ADC_WRITE(channel,PRESCALE);
write(adc_fd,&data,sizeof(data));read(adc_fd,&data,sizeof(data));returndata;
}
staticintstop=0;
staticvoid*comMonitor(void*data)
{
getchar();
stop=1;
returnNULL;
}
intmain(void)
{
inti;
floatd;
pthread_tth_com;
void*retval;
//sets3c44b0ADregisterandstartAD
if(init_ADdevice()<0)
return-1;
/*Createthethreads*/
pthread_create(&th_com,NULL,comMonitor,0);
printf("\nPressEnterkeyexit!
\n");
while(stop==0){
for(i=0;i<=2;i++){//采样0~2路A/D值
d=((float)GetADresult(i)*3.3)/1024.0;
printf("a%d=%8.4f\t",i,d);
}usleep
(1);printf("\r");
}
/*Waituntilproducerandconsumerfinish.*/
pthread_join(th_com,&retval);
printf("\n");
return0;
}
七、实验步骤
1、阅读理解源码
进入/arm2410cl/exp/basic/04_ad目录,使用vi编辑器或其他编辑器阅读理解源代码。
2、编译应用程序
运行make产生ad可执行文件
[root@zxt/]#cd/arm2410cl/exp/basic/04_ad/[root@zxt04_ad]#make
armv4l-unknown-linux-gcc-c-omain.omain.c
armv4l-unknown-linux-gcc-o../bin/admain.o-lpthreadarmv4l-unknown-linux-gcc-oadmain.o-lpthread[root@zxt04_ad]#ls
adhardware.hmain.oMakefile.baks3c2410-adc.h
binmain.cMakefilereadme.txtsrc
3、下载调试
换到minicom终端窗口,使用NFSmount开发主机的/arm2410cl到/host目录。
[root@zxtroot]#minicom
[/mnt/yaffs]mount-tnfs-onolock192.168.0.56:
/arm2410cl/host
[/mnt/yaffs]insmodad/s3c2410-adc.o[/mnt/yaffs]cd/host/exp/basic/04_ad/[/host/exp/basic/04_ad]./ad
PressEnterkeyexit!
a0=0.0032a1=3.2968a2=3.2968
我们可以通过调节开发板上的三个黄色的电位器,来查看a0、a1、a2的变化。
八、思考题
1.逐次逼近型的A/D转换器原理是什么?
2.A/D转换的重要指标包括哪些?
3.ARM的A/D功能的相关寄存器有哪几个,对应的地址是什么?
4.如何启动ARM开始转换A/D,有几种方式?
转换开始时ARM是如何知道转换哪路通道的?
如何判断转换结束?