历史上的今天
今天是:2024年11月20日(星期三)
2019年11月20日 | ATmage16-ADC
2019-11-20 来源:51hei
AVR的模数转换器ADC具有下列特点:
10位精度;
0.5LSB积分非线形误差
±2LSB的绝对精度;
13μs~260μs的转换时间;
在最大精度下可达到每秒15kSPS的采样速率;
8路可选的单端输入通道;
7路差分输入通道;
2路差分输入通道带有可选的10×和200×增益;
ADC转换结果的读取可设置为左端对齐(LEFT ADJUSTMENT);
ADC的电压输入范围0~Vcc;
可选择的内部2.56V的ADC参考电压源;
自由连续转换模式和单次转换模式;
ADC自动转换触发模式选择;
ADC转换完成中断;
休眠模式下的噪声抑制器(NOISE CANCELER)。
在本实例中,我们将编写程序实现将模数转换后获得的电压值通过单片机的串口发送到计算机,然后通过计算机上的串口助手显示测量的电压值。
本实例共有3个功能模块,分别描述如下:
● 单片机系统:使用单片机的串口实现将模数转换后获得的电压值通过串口发送到计算机。
● 外围电路:RS232电平转换电路,DB9串行接口插座,模拟电压输入采集电路。
● 软件程序:进一步熟悉单片机的串行通信,并掌握单片机的模数转换的方法。
6.2.2、器件和原理
关于串行接口的原理已接单片机与计算机的串口的连接在上一实例中进行了描述,在本实例中不再重复。
本实例只介绍ATmega16单片机如何通过内置的模数转换模块采集外界输入的模拟电压。
1、ATmega16单片机的模数转换器ADC介绍
由于单片机只能处理数字信号,所以外部的模拟信号量需要转变成数字量才能进一步的由单片机进行处理。ATmega16内部集成有一个10位逐次比较(successive approximation)ADC电路。因此使用AVR可以非常方便的处理输入的模拟信号量。
ATmega16的ADC与一个8通道的模拟多路选择器连接,能够对以PORTA作为ADC输入引脚的8路单端模拟输入电压进行采样,单端电压输入以0V(GND)为参考。另外还支持16种差分电压输入组合,其中2种差分输入方式(ADC1,ADC0和ACD3,ADC2)带有可编程增益放大器,能在A/D转换前对差分输入电压进行0dB(1×),20dB(10×)或46dB(200×)的放大。还有七种差分输入方式的模拟输入通道共用一个负极(ADC1),此时其它任意一个ADC引脚都可作为相应的正极。若增益为1×或10×,则可获得8位的精度。如果增益为200×,那么转换精度为7位。
AVR的ADC功能单元由独立的专用模拟电源引脚AVcc供电。AVcc和Vcc的电压差别不能大于±0.3V。ADC转换的参考电源可采用芯片内部的2.56V参考电源,或采用AVcc,也可使用外部参考电源。使用外部参考电源时,外部参考电源由引脚ARFE接入。使用内部电压参考源时,可以通过在AREF引脚外部并接一个电容来提高ADC的抗噪性能。
ADC功能单元包括采样保持电路,以确保输入电压在ADC转换过程中保持恒定。ADC通过逐次比较(successive approximation)方式,将输入端的模拟电压转换成10位的数字量。最小值代表地,最大值为AREF引脚上的电压值减1个LSB。可以通过ADMUX寄存器中REFSn位的设置,选择将芯片内部参考电源(2.56V)或AVcc连接到AREF,作为A/D转换的参考电压。这时,内部电压参考源可以通过外接于AREF引脚的电容来稳定,以改进抗噪特性。
模拟输入通道和差分增益的选择是通过ADMUX寄存器中的MUX位设定的。任何一个ADC的输入引脚,包括地(GND)以及内部的恒定能隙(fixed bandgap)电压参考源,都可以被选择用来作为ADC的单端输入信号。而ADC的某些输入引脚则可选择作为差分增益放大器的正、负极输入端。当选定了差分输入通道后,差分增益放大器将两输入通道上的电压差按选定增益系数放大,然后输入到ADC中。若选定使用单端输入通道,则增益放大器无效。
通过设置ADCSRA寄存器中的ADC使能位ADEN来使能ADC。在ADEN没有置“1”前,参考电压源和输入通道的选定将不起作用。当ADEN位清“0”后,ADC将不消耗能量,因此建议在进入节电休眠模式前将ADC关掉。
ADC将10位的转换结果放在ADC数据寄存器中(ADCH和ADCL)。默认情况下,转换结果为右端对齐(RIGHT ADJUSTED)的。但可以通过设置ADMUX寄存器中ADLAR位,调整为左端对齐(LEFT ADJUSTED)。如果转换结果是左端对齐,并且只需要8位的精度,那么只需读取ADCH寄存器的数据作为转换结果就达到要求了。否则,必须先读取ADCL寄存器,然后再读取ADCH寄存器,以保证数据寄存器中的内容是同一次转换的结果。因为一旦ADCL寄存器被读取,就阻断了ADC对ADC数据寄存器的操作。这就意味着,一旦指令读取了ADCL,那么必须紧接着读取一次ADCH;如果在读取ADCL和读取ADCH的过程中正好有一次ADC转换完成,ADC的2个数据寄存器的内容是不会被更新的,该次转换的结果将丢失。只有当ADCH寄存器被读取后,ADC才可以继续对ADCL和ADCH寄存器操作更新。
ADC有自己的中断,当转换完成时中断将被触发。尽管在顺序读取ADCL和ADCH寄存器过程中,ADC对ADC数据寄存器的更新被禁止,转换的结果丢失,但仍会触发ADC中断。
2、ATmwga16单片机的模数转换器ADC相关的I/O寄存器
1.ADC多路复用器选择寄存器—ADMUX
位7,6—REFS[1:0]:ADC参考电源选择
REFS1、REFS2用于选择ADC的参考电压源,见表6.2.1。如果这些位在ADC转换过程中被改变,新的选择将在该次ADC转换完成后(ADCSRA中的ADIF被置位)才生效。一旦选择内部参考源(AVcc、2.56V)为ADC的参考电压后,AREF引脚上不得施加外部的参考电源,只能与GND之间并接抗干扰电容。
位5—ADLAR:ADC结果左对齐选择
ADLAR位决定转换结果在ADC数据寄存器中的存放形式。写“1”到ADLAR位,将使转换结果左对齐(LEFT ADJUST);否则,转换结果为右对齐(RIGHT ADJUST)。无论ADC是否正在进行转换,改变ADLAR位都将会立即影响ADC数据寄存器。
位4..0—MUX4:0:模拟通道和增益选择
这5个位用于对连接到ADC的输入通道和差分通道的增益进行选择设置,详见表6.2.2。注意,只有转换结束后(ADCSRA的ADIF是“1”),改变这些位才会有效。
本实例中我们需要设置ADC的参考电压源为AVcc,即REFS0设置为1,ADC默认转换结果为右对齐,我们不需要改变,模拟通道选择ADC0通道单端输入,即MUX4:0。
2.ADC控制和状态寄存器A—ADCSRA
位7—ADEN:ADC使能
该位写入“1”时使能ADC,写入“0”关闭ADC。如在ADC转换过程中将ADC关闭,该次转换随即停止。
位6—ADSC:ADC转换开始
在单次转换模式下,置该位为“1”,将启动一次转换。在自由连续转换模式下,该位写入“1”将启动第一次转换。先置位ADEN位使能ADC,再置位ADSC;或置位ADSC的同时使能ADC,都会使能ADC开始进行第一次转换。第一次ADC转换将需要25个ADC时钟周期,而不是常规转换的13个ADC时钟周期,这是因为第一次转换需要完成对ADC的初始化。
在ADC转换的过程中,ADSC将始终读出为“1”。当转换完成时,它将转变为“0”。强制写入“0”是无效的。
位5—ADATE:ADC自动转换触发允许
当该位被置为“1”时,允许ADC工作在自动转换触发工作模式下。在该模式下,在触发信号的上升沿时ADC将自动开始一次ADC转换过程。ADC的自动转换触发信号源由SFIOR寄存器中的ADTS位选择确定。
位4—ADIF:ADC中断标志位
当ADC转换完成并且ADC数据寄存器被更新后该位被置位。如果ADIE位(ADC转换结束中断允许)和SREG寄存器中的I位被置“1”,ADC中断服务程序将被执行。ADIF在执行相应的中断处理向量时被硬件自动清零。此外,ADIF位可以通过写入逻辑“1”来清零。
位3—ADIE:ADC中断允许
当该位和SREG寄存器中的I位同时被置位时,允许ADC转换完成中断。
位2,0—ADPS[2:0]:ADC预分频选择
这些位决定了XTAL时钟与输入到ADC的ADC时钟之间分频数,见表6.2.3。
本实例中我们需要使能ADC,即ADEN设置为1,我们不用自动转换,也不需要中断,所以,ADTE、ADIE位不需要设置。在通常情况下,ADC的逐次比较转换电路要达到最大精度时,需要50kHz~200kHz之间的采样时钟。本例中使用的时钟是12M的,所以要将时钟64分频,分频后ADC频率为188KHz,即时钟分频选择ADPS[2:0]=6。
3.ADC数据寄存器—ADCL和ADCH
ADLAR = 0,ADC转换结果右对齐时,ADC结果的保存方式

ADLAR = 1,ADC转换结果左对齐时,ADC结果的保存方式

当ADC转换完成后,可以读取ADC寄存器的ADC0-ADC9得到ADC的转换的结果。如果是差分输入,转换值为二进制的补码形式。一旦开始读取ADCL后,ADC数据寄存器就不能被ADC更新,直到ADCH寄存器被读取为止。因此,如果结果是左对齐(ADLAR=1),且不需要大于8位的精度的话,仅仅读取ADCH寄存器就足够了。否则,必须先读取ADCL寄存器,再读取ADCH寄存器。ADMUX寄存器中的ADLAR位决定了从ADC数据寄存器中读取结果的格式。如果ADLAR位为“1”,结果将是左对齐;如果ADLAR位为“0”(默认情况),结果将是右对齐。
4.特殊功能I/O寄存器—SFIOR
位7..5—ADTS[2:0]:ADC自动转换触发源选择
当ADCSRA寄存器中的ADATE为“1”,允许ADC工作在自动转换触发工作模式时,这3位的设置用于选择ADC的自动转换触发源。如果禁止了ADC的自动转换触发(ADATE为“0”),这3个位的设置值将不起任何作用。
本例中我们不使用自动转换功能,所以该寄存器可以不必设置。
6.2.3、电路
本实例的电路包括232电平转换电路和电阻分压电路,这两种电路在前面的实例中均做过介绍,这里不再重复。
1、电路原理
在本实例中利用MAX3232芯片使单片机输出的TTL电平转换为标准的RS232电平,从而使计算机能够识别。同时将计算机输出的RS232电平转换为单片机可以识别的TTL电平。
利用电位器产生电阻分压电路,从而产生变化的模拟电压加到单片机的模拟信号采集端口,供单片机采集。
2、电路连接
电路中MAX3232芯片的9、10引脚分别连接单片机的PD0、PD1端口,MAX3232的13、14引脚分别连接计算机串口线的3、2脚。
电位器RP2的动片引脚连接单片机的模拟信号采集通道PA0(ADC0)。
3、特别说明
本学习板采用的是串口插座是公头的,所以与计算机相连的串口连接线应该是交叉串口线,而不是串口延长线。
6.2.4、程序设计
1、程序功能
程序的功能是通过单片机的串行接口,将单片机采集到的模拟电压值发送到计算机中,通过计算机上的串口助手显示采集的电压值。
● 单片机串行接收中断的编程
在本例中,我们用到了单片机的串行接收中断,需要编写串行接收中断服务程序,通过查询WINAVR(GCC)的中断库函数手册,可以查找到ATmega16单片机串行接收中断的中断向量为USART_RXC_vect。据此我们可以编写串行接收中断服务程序,如下:
//接收中断函数
ISR(USART_RXC_vect )
{
unsigned char Rev;
Rev = UDR; //从USART I/O数据寄存器-UDR中读出数据
Usart_PutChar(Rev); //将接收到的数据发送
}
在中断服务程序中,我们首先把单片机串口接收到的数据放入变量Rev中,然后调用上一实例中编写的串行接口字节发送函数将变量Rev中的数据发送到计算机。
2、 单片机与计算机串行通信结果的观察
在观察本例运行结果时,我们同样要用到串口助手,本例中,单片机发送串口数据采用的波特率是9600bps,数据格式是8位数据位,1位停止位,无奇偶校验。在串口助手里面,我们也要将波特率和数据格式设置成一样的。
3、函数说明
本实例用到了6个函数,分别是:
void Port_Init(void); //端口初始化配置
void Usart_Init(void); //USART寄存器设置
void AD_Init(void); //AD初始化
void Usart_PutChar(unsigned char cTXData); //字节发送函数
void Usart_PutString(unsigned char *pcString); // 字符串发送数据
unsigned int AD_GetData(void); //AD转换函数
4、使用WINAVR开发环境,在本例中我们使用的是外部12M的晶振,所以需要将MAKEFILE文件中的时钟频率修改为12M。另外在程序烧录到单片机的时候,熔丝位也要选择为外部12M晶振(注意是晶振,不是外部振荡器,一定不要选择错了,否则会导致单片机不能再烧写程序)。
5、程序代码
#include
#include
#include
//常量声明
#define BAUD 9600 //波特率设置值
//全局变量声明
unsigned int ADData; //AD转换获得的数据
//函数声明
void Port_Init(void); //端口初始化配置
void Usart_Init(void); //USART寄存器设置
void AD_Init(void); //AD初始化
void Usart_PutChar(unsigned char cTXData); //字节发送函数
void Usart_PutString(unsigned char *pcString); // 字符串发送数据
unsigned int AD_GetData(void); //AD转换函数
int main(void)
{
unsigned char Delay3s;
Port_Init();
Usart_Init();
AD_Init();
Usart_PutString("AD转换测试程序");
Usart_PutString("测得ADC0通道的电压值为:");
sei(); //使能全局中断
while(1)
{
ADData = (int)((long)AD_GetData() * 5010 / 1024); //将获得的AD值转换为电压值
//单位为mv。
Usart_PutChar(ADData / 1000 + 0x30); //得到电压值的千位并发送
Usart_PutChar('.'); //发送小数点
Usart_PutChar(ADData % 1000 / 100 + 0x30); //得到电压值的百位并发送
Usart_PutChar(ADData % 100 / 10 + 0x30); //得到电压值的十位并发送
Usart_PutChar(ADData % 10 + 0x30); //得到电压值的个位并发送
Usart_PutChar('V'); //发送电压符号“V”
Usart_PutChar(0x0d); //
Usart_PutChar(0x0a); // AD值发送结束,回车换行
for(Delay3s = 0;Delay3s < 30;Delay3s++) //延时3S
{
_delay_ms(90);
}
}
}
//端口状态初始化设置函数
void Port_Init()
{
PORTA = 0X00;
DDRA = 0x00; //ADC通道设置为输入口,高阻态
}
//USART寄存器配置函数
void Usart_Init()
{
UCSRA = 0X00;
UCSRC |= (1<
UBRRL = (F_CPU / BAUD / 16 - 1) % 256; //波特率设置
UBRRH = (F_CPU / BAUD / 16 - 1) / 256;
UCSRB |= (1 << RXCIE) | (1 << RXEN) | (1 << TXEN); //发送使能
}
//字节发送函数
void Usart_PutChar(unsigned char cTXData)
{
while( !(UCSRA & (1 << UDRE)) ); //只有数据寄存器为空时才能发送数据
UDR = cTXData; //发送数据送USART I/O数据寄存器-UDR
}
//接收中断函数
ISR(USART_RXC_vect )
{
unsigned char Rev;
Rev = UDR; //从USART I/O数据寄存器-UDR中读出数据
Usart_PutChar(Rev); //将接收到的数据发送
}
void Usart_PutString(unsigned char *pcString)
{
while (*pcString)
{
Usart_PutChar(*pcString++);
}
Usart_PutChar(0x0D);
Usart_PutChar(0x0A); //结尾发送回车换行
}
//AD转换初始化函数
void AD_Init()
{
ADMUX |= (1 << REFS0); //ADC参考电压为AVcc,ADC结果右对齐,选择通道ADC0
ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); //使能AD转换,ADC时钟64分频
}
//AD转换函数
unsigned int AD_GetData()
{
ADCSRA |= (1 << ADSC); //开始AD转换
while(!(ADCSRA & (1 << ADIF))); //等待转换完成
ADCSRA |= (1 << ADIF); //清零ADC中断标志位
return ADC; //返回ADC值
}
附录:ADC应用设计要点 1.预分频与转换时间
在通常情况下,ADC的逐次比较转换电路要达到最大精度时,需要50kHz~200kHz之间的采样时钟。在要求转换精度低于10位的情况下,ADC的采样时钟可以高于200kHz,以获得更高的采样率。
下一篇:AVR_点亮LED程序
史海拾趣
|
1 步进电机 步进电动机是纯粹的数字控制电动机,它将电脉冲信号转变成角位移,即给一个脉冲,步进电机就转一个角度,因此非常适合单片机控制。在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响, ...… 查看全部问答> |
|
1 引言 现今,随着整机尺寸的减小和元器件的高度集成,促进了元器件的小型化、薄型化。由于SAW(Surface Acoustic Wave)器件小型化并且有着出众的滤波功能,它们存许多领域的应用中扮演着非常重要的角包。小型化和多功能化是SAW器件发展的主要动力 ...… 查看全部问答> |
|
概述:步进电机主要是依相数来做分类,而其中又以二相、五相步进电机为目前市场上所广泛采用。二相步进电机每转最细可分割为400等分,五相则可分割为 1000等分, 所以表现出来的特性以五相步进电机较佳、 加减速时间较短、 动态惯性较低。 二相/ ...… 查看全部问答> |
|
本帖最后由 jameswangsynnex 于 2015-3-3 20:02 编辑 针对消费娱乐的家庭网络连接 利用多媒体家庭联网技术,各种多媒体设备 ( 例如电视机、便携式媒体播放器、照相机和蜂窝电话等) 以及数据设备 (例如PC和PDA) 可以在安全的家庭网络环境中共享音 ...… 查看全部问答> |
|
目前我手上有一台导航仪,用的是wince5.0的系统,现在我想在这台导航仪上开发一个程序。 目前的问题是,我无法直接在该导航仪上调试我的程序,只能将程序编译好后再复制到导航仪上运行,这样调试起来非常不方便。 因为我的导航仪目前是只要通过US ...… 查看全部问答> |
|
推荐一本用PowerPC开发通信设备的书,我还是第一次见同类型的书 嵌入式设计及通信设备开发详解——基于MPC82XX处理器 卓越的链接 http://www.amazon.cn/mn/detailApp?qid=1238487283&ref=SR&sr=13-1&uid=168-0888845-7367438&prodid=bkbk941360 当当的链接 http://product.dangdang.com/product.aspx?pro ...… 查看全部问答> |
|
一个非常奇怪的keil c51串口中断问题! 比如我的程序如下: uchar b[10]; #define a4 0x03 void fun1(void) interrupt 4 { fun2(2); } fun2(uchar a2) { while(a2--) { .... } fun3(a4); } void fun3(uchar a3)//这个函数无论有没 ...… 查看全部问答> |




