您的当前位置:首页ATMAGE16内部ADC的使用程序

ATMAGE16内部ADC的使用程序

2020-03-28 来源:爱问旅游网
ATMAGE16内部ADC的使用程序

程序说明:

本例程是控制ATMAGE16内部的AD进行转换,然后将转换结果转换成电压,显示到数码管上。

本人刚开始用AVR这是写的第一个程序,可能思路上会有很多问题,忘个位网友看后指出,我的邮箱是462511238@qq.com欢迎和我交流。 写这个程序的目的是为了用AD采集一个模拟量,在网上看了些历程,很多都是用查询发写的。就是启动ADC转换以后,等待ADC转换完成,然后就将数据读出,显示出来。这种程序也就只能自己玩玩,毫无实用价值。因为在实际产品中,会有很多干扰信号,采集一次就显示,得到的数据往往是干扰信号。要消除这些干扰,需要在ADC的输入通道上加上滤波电容,当然更重要的是在程序中进行处理。这也就是所谓的数字滤波了,由于单片机运算能力有限,很多PC上的一些算法对于单片机来说就过于复杂了。我在这个程序中,只是采用多次采集数据,然后求平均值的算法进行最简单的滤波的,但这在要求不高的场合已经能够满足要求了。

采用查询法,一直查询ADC是否转换结束是非常浪费CPU时间的。因此我们需要开启ADC的中断,但是每隔多久进行一次转换呢,一直都不停的转换,其实对我们得到准确的数据意义不大,(我采集的是桥式应变片经过差分放大的信号)。并且数据刷新太快,用于显示,会给人不稳定的感觉,还没看清楚显示的是什么,就又刷新了。由于AVR的ADC可以用定时的溢出来触发转换。于是我想到,用定

时器来定时,每隔0.1S采集一次,1S刷新一次显示,也就是每次显示的数据是采集十次数据的平均值,这样做出来还是比较稳定的。 程序实现思路:

将ATMAGE16的定时器1设置为普通计数模式,并且将时钟256分频作为定时器1的工作脉冲(我采用的是4MHZ晶振)。然后将ADC设置为定时器1溢出触发,当定时器溢出后,将触发ADC转换,ADC转换完成后,进入ADC中断,读取数据,并对定时器进行重装初值。这样,就可以保证,每次进行ADC转换的间隔时间基本是一样的。连续转换十次以后,将达到的数据求平均值,就是我们要的数据。 下面是本程序的全部源代码,加注释,显示函数可以完成送入任何一个数据,自动显示。包括判断小数点的位置。由于显示函数比较简单,所以没有注释,忘谅解。

/************************************** 程序说明:

公司:宁水科技

项目:小流量侦测传感器 开发人:徐飞飞

功能描述,采用定时器1作为ADC的触发源,每隔0.1秒

触发一次AD转换,转换15次以后将其求平均值,输出到

数码管显示。使用到了AVR单片机的ADC转换完成中断和

定时器1的普通计数模式。 ***************************************/

#include

#include\"show.h\" #include #pragma interrupt_handler ADC_Conventer:15 uchar num=0; float Buffer=0.0; float result=0.0; uint addata=0;

void ADC_Conventer()//AD转换中断程序,当定时1发生溢出时,将触发AD转换,连续十次转换,将得到的结果取平均数,然后保存到RESULT中 {

addata=ADCL;

addata=addata+ADCH*256;//进入中断程序以后,先从ADC的结果寄存器重读出ADC转换的值

TCNT1H=0XF9;

TCNT1L=0XE4;//对定时器进行重装初值,确保每次触发转换的时间基本一致

Buffer+=addata*5/1024.0;//算出当前ADC转换对应的电压值 if(num>=15) { result=Buffer/15; result=result-0.073; if(result<=0) { result=0.0; } num=0; Buffer=0.0; }

num++;

}

void Init_ADC()//对ADC进行初始化的函数

{ DDRA&=~BIT(0); PORTA&=~BIT(0);//将端口进行初始化,设置为输入模式,并且关闭上拉 ADMUX=0xc0;//设置ADC转换的参考电压为内部参考电压 SFIOR|=BIT(7)|BIT(6);//设置ADC转换的触发方式为定时器一溢出触发 TIMSK|=BIT(2);//开启总中断 ADCSR|=BIT(ADEN)|BIT(ADATE)|BIT(ADIE);//使能ADC转化器,允许ADC被自动触发,开启ADC中断 }

void Init_Timer1() { TCCR1B=0X04;//设置定时器1的时钟源

TCNT1H=0xF9; TCNT1L=0xE4;//为定时器装初值 SREG|=BIT(7);//开启定时器1的中断(用定时器1的溢出作为ADC的触发源,必须要开启定时器1的中断否则不能触发) }

int main() { Init_ADC(); Init_Timer1(); while(1) { show(result); }

return 0; }

/**************************************

程序说明:

公司:宁水科技

项目:小流量侦测传感器 开发人:徐飞飞

功能描述:将送入的任何一个数据可以直接显示到数码管上,程序自动完成小数点位置的判断

***************************************/

uchar wei[]={0xf7,0xfb,0xfd,0xfe}; uchar

duan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,

0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

uchar error[]={0xc0,0x88,0x88,0x86}; void show(float num) {

uchar i; uint temp;

DDRD=0XFF; DDRC=0X0F; PORTD|=0xff; PORTC|=0x0f;

if(num>9999) {

for(i=0;i<4;i++) { PORTC|=0x0f; PORTD=error[i];

PORTC=wei[i];

PORTD|=0xff;

}

}

if((num<=9999)&&(num>=1000)) { temp=num; for(i=0;i<4;i++) { PORTC|=0x0f; PORTD=~duan[temp%10];

PORTC=wei[i];

temp=temp/10; PORTD|=0xff; } }

if((num<=999.9)&&(num>=100.0)) { temp=num*10; for(i=0;i<4;i++) { PORTC|=0x0f;

PORTD=~duan[temp%10]; PORTC=wei[i]; temp=temp/10; PORTD|=0xff; PORTC|=0x0f; PORTD=0x7f; PORTC=0xf7;

}

}

if((num<=99.99)&&(num>=10.00)) { temp=num*100; for(i=0;i<4;i++) { PORTC|=0x0f;

PORTD=~duan[temp%10];

PORTC=wei[i]; temp=temp/10; PORTD|=0xff; PORTC|=0x0f; PORTD=0x7f; PORTC=0xfd; } }

if((num<=9.999)&&(num>=0.000))

{

temp=num*1000; for(i=0;i<4;i++) { PORTC|=0x0f; PORTD=~duan[temp%10]; PORTC=wei[i]; temp=temp/10; PORTD|=0xff;

PORTC|=0x0f;

PORTD=0x7f; PORTC=0xfe; } } }

欢迎大家和我交流,有问题或提出意见,请发电子邮件给我,我会尽快回复的。

因篇幅问题不能全部显示,请点此查看更多更全内容