事无巨细,ADC上阵
今天来讲讲AVR单片机的片内ADC的使用方法。比较简单,希望很快完成。
先看看什么是ADC:
ADC,英文全称为Analog Digital Converter,即模拟数字转换器,可以将连续的模拟量通过取样转换成离散的数字量。
那什么是模拟量呢:在时间上或数值上都是连续的物理量称为模拟量,比如温度,电压,电流,气压,它们都是连续变化的,在波形上都是一条平滑的曲线。
所以对ADC通俗的理解则是:用数字来表达模拟量的大小。
ADC现在已经被大量应用于日常生活中了,常见的数字式电子产品诸如MP3,数码相机,高清电视,还有你看这篇文章时正在使用的个人电脑,都不可能摆脱的了ADC的身影。各位对ADC的理解,ADC之于行业的意义,相信会在生产生活中逐渐得到全面的体会的。
AVR单片机,相比于8位单片机市场的老大——51单片机来说,内部集成了10位精度的ADC,不得不说这是一个巨大的优势。首先ADC是模拟器件,容易受到干扰,集成在片内,干扰问题得到了很好的解决。其次,节省了外围电路,也大大降低了成本,电路设计也因此变得简易,要知道一片低级的ADC就差不多顶一片51或者AT MEGA16了。况且10位的精度,足够应付大部分要求不高的工作场合了。
现在我说说ADC转换器的一些关键参数:
参考电压,关于参考电压,要记住以下几点点:
1、提供ADC转换的分辨率,具体见转换精度的说明。
2、参考电压直接影响ADC的转换精度,所以要十分准确。
3、输入电压大于参考电压的规定值,转换量程仍为参考电压最大值,但是应该尽量避免这种情况,否则会产生未知的危险,甚至烧毁单片机。
4、参考电压(有的ADC芯片是参考电压的数倍)代表ADC输入电压的最大值。
转换精度:也称最小分辨率,精度是指ADC将模拟量转换之后的最小变化量。比如10位精度ADC,参考电压为5V,转换结果位10位二进制数。它的转换精度则为5/(2的10次方)=4.88mv。表示转换后数字量每±1,则表示模拟量有±4.88mv的变化。
转换时间:衡量ADC性能的一个重要指标,即ADC完成一次转换所需要的时间,ADC的工作时钟频率越高,转换越快。(当然高速的AD价格可以是很贵的)
AVR片内的AD,可通过设置分别使用不同的参考电压,转换方式,时钟频率以及单路或差分输入通道,可以将差分信号放大。应该说功能还是比较全面的。
注:差分信号,即两个有一定差值的信号,将差分信号放大即是将此差值进行放大。
现在可以看看AVR单片机的各个寄存器的关键位,我们就是通过操作这些寄存器来设置AVR片内AD的工作方式的:
ADMUX寄存器:
REFS1、REFS0:ADC参考电压选择位;
ADLAR:ADC转换结果对齐选择位;
MUX4~MUX0:输入通道选择位,包括差分信号的输入。
ADCSRA寄存器:
ADEN:ADC转换使能位,该位置“1”时,ADC可以启用。
ADSC:ADC转换开始位,该位置“1”时,转换启动。
ADATE:ADC自带转换触发允许,即该位置“1”时,ADC在设定工作方式下连续转换,而不是单次转换。
ADIE:ADC中断允许为,ADC一次转换完成后,将该位置“1”,在全局中断允许的前提下,可触发ADC中断。
ADCL和ADCH寄存器:存放ADC转换结果。
SFIOR寄存器:
ADTS2、ADTS1、ADTS0:设置ADC连续转换的方式。
以上各寄存器详细功能请查看AVR官方数据手册,有详细说明。
我的设置方案为:使用内部2.56V参考电压,转换结果左对齐,输入通道PA0,连续自由转换(即转换完一次接着马上进行下一次转换),使能ADC中断。(其实很简单,就5个要设置的地方)设置完以后启动ADC(写ADSC位为“1”),ADC就开始工作了。
来看论坛的片内ADC的外围电路设计:
异常简单的一个电路,只有一个10K电位器提供输入电压,接在输入通道PA0上,滑动PA0可得到不同的输入电压从而得到不同的显示效果,验证我们的程序正确与否。
下面是源程序,功能为将采样到的模拟电压转换为数字量并在数码管显示,其中数码管显示的各个函数功能在《事无巨细,数码管》一文有详解,在此节省篇幅,不做重复说明:
- #include
- #include
- #include
- #define uchar unsigned char
- #define uint unsigned int
- /*数码管显示数据与位置数组*/
- unsigned char const LedData[]=
- {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xF8,
- 0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x7f};
- unsigned char const LedPos[]=
- {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
- /*全局变量定义*/
- uchar bai,shi,ge;
- /*函数声明*/
- void HC595shift(void);
- void HC595store(void);
- void display(uchar pos,uchar dat);
- void HC595send(uchar x);
- void init(void);
- void readbyte(void);
- int main(void)
- {
- init();
- while(1); //等待中断产生,即转换结束
- }
- void init(void)
- {
- DDRA=0x00;
- PORTA=0x00; //PA0设置为输入口,内部上拉失效,高阻态
- DDRB=0xff;
- PORTB=0x00; //PB口设置输出方向,输出低电平
- ADMUX=0xe0; //内部参考电源2.56V,输出数据左对齐,PA0输入通道
- SFIOR=0; //自由连续转换
- /*使能ADC,开始转换,允许自动转换,允许ADC中断,128分频*/
- ADCSRA=0xef;
- sei(); //允许全局中断
- }
- ISR(ADC_vect ) //ADC转换函数
- {
- readbyte(); //读取转换结果
- display(0,16); /*显示转换结果,小数点*/
- display(0,bai); /*显示转换结果,最高位*/
- display(1,shi); /*显示转换结果,次高位*/
- display(2,ge); /*显示转换结果,最低位*/
- }
- void readbyte(void) //读取转换字节函数
- {
- uchar byte;
- byte=ADCH;
- bai=byte/100;
- shi=byte%100/10;
- ge=byte%10;
- }
- /*以下为一系列数码管显示函数*/
- void HC595send(uchar x)
- {
- uchar n,temp;
- for(n=0;n<8;n++)
- {
- temp=x&0x80;
- if(temp!=0)
- {
- PORTB|=(1< HC595shift();
- }
- else
- {
- PORTB&=~(1< HC595shift();
- }
- x<<=1;
- }
- }
- void HC595store(void)
- {
- PORTB|=(1< PORTB&=~(1<}
- void HC595shift(void)
- {
- PORTB|=(1< PORTB&=~(1<}
- void display(uchar pos,uchar dat)
- {
- HC595send(LedPos[pos]);
- HC595send( LedData[dat]);
- HC595store();
- }
- /*以上为一系列数码管显示函数*/
挑几点特别的来说:
1、要注意设置ADC的输入通道PA0为输入方向,内部上拉电阻无效,IO呈高阻态,(具体见程序)。这样的抗干扰性比较好,从PA0管脚可以比较准确的反映ADC真实转换值。
2、转换结果保存在ADCH和ADCL中,因为是10位的二进制转换结果(10位精度),所以一个8位的寄存器无法装完。所以有其中一个寄存器只装了两位转换结果。要注意结合对齐标志位ADLAR的状态来读取数据。
3、注意读出数据的分离,读出的数据为10位二进制数,而人习惯于查看十进制数,所以要将10位二进制数转换为十进制数。在此笔者做了保留两位小数的处理。即只保留最高的三位。
4、如何分离一个已知多位数?主要是用求余("/")和求模("%")的办法,请尚不熟悉的读者结合求余和求模运算符的概念细细体会读取字节函数函数void readbyte(void)中的分离方法。(用笔描一描就很容易明白了)
5、最好将所有的ADC寄存器设置完毕之后,再启动ADC转换,再开启全局中断,避免产生未知干扰。(其实任何操作都应该遵循先设置,后启动的原则,因为启用了某样设备,往往意味着一个干扰源也启动了)
6、程序执行的流程十分简单,初始化init()完毕之后,ADC开始转换,while(1)死循环无限等待ADC转换结束触发中断,中断触发后进入中断服务函数ISR(ADC_vect )后将转换结果读出并分离显示。
小贴士:平日总说AVR,AVR你知道AVR这个称呼怎么来的吗?
我来告诉你:1997年,由ATMEL公司挪威设计中心的A先生与V先生利用ATMEL公司的Flash新技术, 共同研发出RISC精简指令集的高速8位单片机,简称AVR。
希望能给有需要的人一点帮助。
[
本帖最后由 losingamong 于 2010-3-16 15:32 编辑 ]