搜索
bottom↓
回复: 46

初学AVR做的ADC数值显示在1602上

[复制链接]

出0入0汤圆

发表于 2005-10-26 23:05:59 | 显示全部楼层 |阅读模式
累了几天了.刚刚学高兴高兴.



用了 kissme 的在LCD上显示数值的方法

出0入0汤圆

发表于 2005-10-27 16:51:07 | 显示全部楼层
能给你的程序给我看看吗?谢谢

出0入0汤圆

 楼主| 发表于 2005-10-28 10:46:03 | 显示全部楼层
我得整理一下.太乱了

出0入0汤圆

 楼主| 发表于 2005-10-28 11:33:57 | 显示全部楼层
点击此处下载armok0182466.rar

出0入0汤圆

发表于 2005-10-28 11:50:09 | 显示全部楼层
adcl=ADCL;

  adch=ADCH;

  PORTC=~adch;

  adc=ADC;



请问,为啥要这样做

出0入0汤圆

 楼主| 发表于 2005-10-28 13:36:41 | 显示全部楼层
因为单独用adc=ADC;这一句的话,机子好像不认为已经读了ADCH。所以只好用

adcl=ADCL;

adch=ADCH;

来读。这样保险点。

adc=ADC;是后面液晶上显示adc16的数字,

另PORTC=~adch;是我接了一个LED显示高位来玩的。没什么意义。

另我的程序里有几个问题写在里面了。请问你能给我说说吗。

#include <iom16v.h>

#include <macros.h>

#include <string.h>

#include "port.h" // 位变量定义及串口初死化

#include "1602.h"  //用的傻孩子的1602显示文件,其中显示数字的我改了一下.

unsigned int adczs; //ADC三次平均数

unsigned int re;    //串口接收到的数据,

void main(void)

{   

DDRC = 0b11111111;

PORTC = 0b00000000;

DDRB = 0b11111111;

PORTB = 0b00000000;

PORTDefine();

LCDInit();

PORTA=0;

DDRA=0;

   Locate(1,1)

   Print("[ADCL")

   Locate(11,1)

   Print("ADC16")

   Locate(1,0)

   Print("[ADCH")

   Locate(16,1)

   Print("]")

   Locate(16,0)

   Print("]")



ADMUX=0b01000000;  //ADC0,

ADCSR=0B10001110;  //

ADCSR|=0B01000000; //启动一次转换

delay_nms(1);

while(ADCSR&0b00010000)   //这个可能没有起做用,我还不熟

{

unsigned int n;     

unsigned int adcl;

unsigned int adch;

unsigned int adc;

unsigned int adcpjt;  



ADCSR|=0B00000000; //清转换完成标志位,也不知道是不是M16已经硬件清除了.

  adcl=0;

  adch=0;

  adc=0;

  n++;

  adcl=ADCL;

  adch=ADCH;

  PORTC=~adch;

  adc=ADC;

  adczs+=adc; //ADC转换三次的总数,

       

        adcl=((adc<<8)>>8); //好像也是多余的

        adch=((adc>>8)<<8); //前面已经读过了

        ADCSR|=0B01000000;

        Locate(7,1)       

        LCDDisplayNum(adcl);

        Locate(7,0)

        LCDDisplayNum(re);

        Locate(11,0)

        LCDDisplayNum(adcpj);

        if (n>2)

        {

        adcpj=(adczs/3); ADC转换三次的平均数

        adcpzs=0;

        n=0;

        }

       

        UDR=(adcl);

        while(UCSRA&=TXC) \\这句我本来的意思是,等待TXC标志位为1,不知道这样写对不对。请DX给我讲讲

        {

        ;

        }

       

        UCSRA|=0B01000000;

       

        UDR=(adc>>8);

        while(UCSRA&=TXC)

        {

        ;

        }

        while((UCSRA&=RXC))

        {

        ;

        }

        re=UDR;

        delay_nms(200);

}

}

   



-----此内容被gongcsf于2005-10-28,13:37:43编辑过


-----此内容被gongcsf于2005-10-28,13:40:59编辑过

出0入0汤圆

发表于 2005-10-28 14:17:34 | 显示全部楼层
while(ADCSR&0b00010000)   //这个可能没有起做用,我还不熟

第4位是转换完成中断标志



ADCSR|=0B00000000; //清转换完成标志位,也不知道是不是M16已经硬件清除了

这句等于没用,正确的应该是ADCSR|=0b00010000;



while(UCSRA&=TXC) \\这句我本来的意思是,等待TXC标志位为1,不知道这样写对不对。请DX给我讲讲

这也是错误的,应该是while(!(UCSRA&TXC));具体TXC还是1<<TXC 看你头文件。



因为单独用adc=ADC;这一句的话,机子好像不认为已经读了ADCH。所以只好用

adcl=ADCL;  

adch=ADCH;  

来读。这样保险点。

adc=ADC;是后面液晶上显示adc16的数字,

既然为了保险,你为何后面还用adc=ADC来读ADC?

出0入0汤圆

 楼主| 发表于 2005-10-28 14:54:45 | 显示全部楼层
//

while(ADCSR&0b00010000) 这句我的本意是等待ADC完成标志位ADIF为1,

这里是ADCSR的第5位也就是ADIF为1的话那么(ADCSR&0b00010000)就是真值。那么应该就实现了胖断ADC转换完成的功能了吧。

问题是如果ADIF不为真的话那我的程序应该跑到while(){}的}号之后了。那}号之后已经没有东西了main()

已经完了。那我的程序怎么还能一直走下去呢。难道机子在跑完MAIN()程序之后再回头跑MAIN()吗。

//  搞错了.ADIF应该是第四位.我在书上看10101010的二进制数看多了,看眼花了



//

ADCSR|=0B00000000; //清转换完成标志位,也不知道是不是M16已经硬件清除了

这句等于没用,正确的应该是ADCSR|=0b00010000;

RE;

ADCSR|=0b00010000好像也不能使ADIF清零啊。

如果ADIF为1那么    0bxxx1xxxx

                |  0Bxxx1xxxx

           =       0Bxxx1xxxx

还是没有清到零吧。

ADCSR&=0B11101111;好像可以让ADIF为0

                   0bxxx1xxxx

              &    0b11101111

           =       0bXXX0XXXX

这样好像就可以让ADIF清零了吧。

//







//

while(UCSRA&=TXC) \\这句我本来的意思是,等待TXC标志位为1,不知道这样写对不对。请DX给我讲讲

这也是错误的,应该是while(!(UCSRA&TXC));具体TXC还是1<<TXC 看你头文件。

串口是第一次用这东西还不了解

//







//

因为单独用adc=ADC;这一句的话,机子好像不认为已经读了ADCH。所以只好用  

adcl=ADCL;   

adch=ADCH;   

来读。这样保险点。  

adc=ADC;是后面液晶上显示adc16的数字,  

既然为了保险,你为何后面还用adc=ADC来读ADC?



adc只是用来显示的没起什么做用。因为我不会把adcl和adch加在一起所以直接用了这个adc=ADC;这样好像方便点吧。

//





另我的程序里我觉得有很多地方是不对的。但是为什么我的程序可以正常的跑呢。我转动电位器液晶上面也是正常显示值来。

另电脑上串口收到的东西也正确。

还可以在串口上发数值到机子上,在液晶上显示也是正确的。



那这是为什么?????????

//





第一次做东西问题多多。见笑~—~








-----此内容被gongcsf于2005-10-28,22:38:38编辑过

出0入0汤圆

发表于 2005-10-28 14:55:24 | 显示全部楼层
ADC建议你用噪声抑制模式(转换更准确):



看一下下面的这篇文章:

http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=531555&bbs_page_no=1&bbs_id=1000
-----此内容被IFine于2005-10-28,14:56:39编辑过

出0入0汤圆

 楼主| 发表于 2005-10-28 15:10:59 | 显示全部楼层
我也知道。不过用噪声抑制模式的话要用到中断吧,

要等以后再加上去。先一点点的搞好。慢慢来。

出0入0汤圆

发表于 2005-10-28 15:21:07 | 显示全部楼层
建议你多看看例子,不单单是ADC方面的。你能读对是因为avr够快。如果换到51,你就会发现问题了

出0入104汤圆

发表于 2005-10-29 22:46:54 | 显示全部楼层
提供我的ACD_LDC_DISP应用例子。



//ICC-AVR application builder

// Target : M16

// Crystal: 8.0000Mhz



#include <iom16v.h>

#include <macros.h>

#include "1602BLCD.h"



typedef        unsigned char        uchar;

typedef        unsigned int        uint;

typedef        unsigned long        ulong;



uchar Lcd_data_buff_1[16];  //LCD 第一行在MEGA16 RAM 显示缓冲区

uchar Lcd_data_buff_2[16];  //LCD 第二行在MEGA16 RAM 显示缓冲区

/*-----------------------------------------------------------------------

  英文字符串存放在MEGA16 RAM 显示缓冲区Lcd_data_buff_(1~2)[16]函数          

-----------------------------------------------------------------------*/

void LCD_buff_write_string(uchar Line,uchar location,uchar *s)

{

    if (Line == 1)

        {

             while (*s)

      {

       Lcd_data_buff_1[location]=(*s);

           location++;   

           s++;

      }

        }

        else if (Line == 2)

        {

      while (*s)

      {

       Lcd_data_buff_2[location]=(*s);

           location ++;   

           s ++;

      }

        }

}

/*-----------------------------------------------------------------------

第一行在MEGA16 RAM 显示缓冲区存送到LCD第一行显示寄存器地址:0X80-0X8F          

-----------------------------------------------------------------------*/

void Lcd_data_buff_send_LCD_1(void)

{

    uchar Counter,x;

        x=0;

        LCD_set_xy(0,0);

        for(Counter=0;Counter<16;Counter++)

        {

        LCD_write_char(1,Lcd_data_buff_1[x]);

        x++;

        }

}

/*-----------------------------------------------------------------------

第二行在MEGA16 RAM 显示缓冲区存送到LCD第二行显示寄存器地址:0XC0-0XCF          

-----------------------------------------------------------------------*/

void Lcd_data_buff_send_LCD_2(void)

  {       

    uchar Counter,x;       

        x=0;

        LCD_set_xy(0,1);

        for(Counter=0;Counter<16;Counter++)

        {       

        LCD_write_char(1,Lcd_data_buff_2[x]);

        x ++;

        }

  }

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

               查询方式读取ADC 0~31通道

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

uint read_adc(uchar vol_reference,uchar ADC_chunnel)  

{  

  ADMUX=(vol_reference<<6)|(0<<ADLAR)|(ADC_chunnel&0x1F); //ADLAR_bit5=0 右对齐

/*

  ADMUX (ADC Multiplexer Select Register)

             bit7  bit6

             REFS1 REFS0  参考电压选择

              0     0     AREF,内部Vref关闭

              0     1     AVCC,AREF引脚外加滤波电容

              1     0     保留

              1     1     2.56V的片内基准电压源,AREF引脚外加滤波电容

             bit5         ADC结果左对齐选择 1=左对齐  0=右对齐

             bit4~0       选择32通道  



*/

  ADCSRA=(1<<ADEN)|(0<<ADSC)|(0<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);

/*  

               ADCSRA (ADC Control and Status Register A)

                bit7   ADEN ADC使能=1

                bit6   ADSC 启动ADC开始转换=1

                bit5   ADATE 自己触发使能

                bit4   ADIF ADC中断标志

                bit3   ADIE ADC中断使能

                bit2:0 ADC 预分频选择位 111=128时钟分频

*/  

  delay_nus(200);   

  ADCSRA|=(1<<ADSC);            //启动ADC开始转换

  while ((ADCSRA&0x10)!=0x10);  //等待ADC转换结束

  ADCSRA|=(1<<ADIF);                        //写1清除标志位

  ADCSRA=0x00;                  //关闭ADC

  return (ADC&0x03FF);                    //ADC=ADCH:ADCL

}

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

将BCD码转换为ASCII码函数

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

uchar bcd_to_ascii(uchar bcd)

{

      bcd &= 0x0F;

          if(bcd > 9)

          bcd +=('0'+7);          // 将A~F转换为ASCII

          else

          bcd += '0';                   // 将0~9转换为ASCII 0~9

          return(bcd);

}

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



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

void LCD_DISP_ADC(void)

{

      uint  Temp;

          uchar d1000,d100,d10,d1;

          uchar hex_100,hex_10,hex_1;



          uchar vol_reference=3;     //2.56V的片内基准电压源,AREF引脚外加滤波电容

          uchar ADC_chunnel=30;             //选择0~31 ADC通道

                     

          Temp=read_adc(vol_reference,ADC_chunnel);  // 读取ADC 0~31通道

          

          hex_100=(Temp>>8)&0x03;        //转换十六进制数百位

          hex_10=(Temp>>4)&0x0F;                 //转换十六进制数十位

          hex_1=Temp & 0x0F;                         //转换十六进制数个位

          hex_100=bcd_to_ascii(hex_100);

          hex_10=bcd_to_ascii(hex_10);          

          hex_1=bcd_to_ascii(hex_1);

            

          //Temp=Temp-2;

          Temp=Temp*25; //2.56V基准 25*1024=25600只要前四位数2560就可作为十进制数

          d1000=Temp/10000; Temp=Temp%10000; //转换十进制数万位

          d100=Temp/1000;  Temp=Temp%1000;         //转换十进制数千位      

      d10=Temp/100;   Temp=Temp%100;         //转换十进制数百位

            d1=Temp/10;                                                   //转换十进制数十位



          if(ADC_chunnel>9)

          {

            Lcd_data_buff_2[3]=(ADC_chunnel/10)+'0'; //转换十进制数十位

            Lcd_data_buff_2[4]=(ADC_chunnel%10)+'0'; //转换十进制数个位

          }

          else

          {

            Lcd_data_buff_2[4]=(ADC_chunnel&0x0F)+'0'; //转换十进制数个位

          }

          Lcd_data_buff_2[6]=(d1000+'0');

          Lcd_data_buff_2[8]=d100+'0';

          Lcd_data_buff_2[9]=d10+'0';          

          Lcd_data_buff_2[10]=d1+'0';

          Lcd_data_buff_2[13]=hex_100;

          Lcd_data_buff_2[14]=hex_10;

          Lcd_data_buff_2[15]=hex_1;

      Lcd_data_buff_send_LCD_2();                      

}          



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



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

void main (void)

{

  uint Temp;



  //OSCCAL=0xB7;                      // 8M系统内部时钟校准



  DDRC |= LCD_DATA | LCD_RS | LCD_EN;

  LCD_EN_PORT &= ~LCD_EN;                   //EN=0

  LCD_init();



  LCD_buff_write_string(1,0," Voltage Meter  "); //1=第一行,0=位置0~15,

  LCD_buff_write_string(2,0," CH__= .   V    "); //2=第二行,0=位置0~15,

  Lcd_data_buff_send_LCD_1();

//  Lcd_data_buff_send_LCD_2();

  for(;;)

  {

  LCD_DISP_ADC();

  delay_nms(250);

  }

  

}

出0入0汤圆

 楼主| 发表于 2005-10-29 23:19:54 | 显示全部楼层
谢谢.明天星期天好好消化一下.哈哈.我自己的程序里的那些个0B00000000的二进数我看过HJJ的指导后已经改成(1<<ADIF)这类的了.现在那个程序里面我又加上了一个用定时器0做的八位PWM,用串口发送的值或ADC转换的值来驱动一个小电机.



另串口的发送接收有些地方不是很明白.等一下看一下书.再有不明白的下次问你行吗.

出0入0汤圆

 楼主| 发表于 2005-10-30 00:32:40 | 显示全部楼层
ADCSRA|=(1<<ADIF);         //写1清除标志位? 是写0清标志位吗.我刚看书了.

另你这个程序里读的是ADC0差分输入,1X放大吧.

另外不是说要把第一次转换的结果丢弃吗.你程序里好像没有体现出来呢.

学习中.这样显示是简洁多了.

出0入0汤圆

发表于 2005-10-31 08:51:33 | 显示全部楼层
ADCSRA|=(1<<ADIF);         //写1清除标志位? 是写0清标志位吗.我刚看书了.



你看书了?你的书写的是写0清标志位?那你赶紧把你的书扔了吧,再写封信给作者,大骂一通

出0入0汤圆

发表于 2006-2-21 08:50:13 | 显示全部楼层
好东西,但是就是没有接口图,如果能弄个protus仿真那就更好!

出0入0汤圆

发表于 2006-2-21 22:26:43 | 显示全部楼层
强,好好学习,天天向上!

出0入0汤圆

发表于 2006-8-11 20:55:49 | 显示全部楼层
楼主的签名档还是挺有哲理的哈

出0入0汤圆

发表于 2006-10-18 18:18:22 | 显示全部楼层
给个接口图

出0入0汤圆

 楼主| 发表于 2006-10-18 22:13:01 | 显示全部楼层
2005-10-26,23:05:59 这贴也找得出来啊.那你再找找四线接法的1602的接线吧.ADC就随便找一个吧.我也是刚学的.程序里面没有注释.也有好些错的地方

好久没玩单片机了.买的板子都锈了.

出0入0汤圆

发表于 2006-10-19 15:10:47 | 显示全部楼层
andy 红日

我是刚学AVR,但我的ICCAVR里没有1602BLCD.h这个头文件,能否发一份给我,

先谢了!

 tycote@163.com

出0入0汤圆

发表于 2007-3-30 18:01:21 | 显示全部楼层
那个LCDSHOWNUM的函数太长了,有没有什么简单一点的方法?

出0入0汤圆

发表于 2007-3-31 20:14:40 | 显示全部楼层
ADC是一个int型的指针,你把adc定义为int型就可以了

出0入0汤圆

发表于 2007-4-4 10:17:22 | 显示全部楼层
//*********************************读A/D转换子程序***************************//

int read_adc(unsigned int ADC_chunnel)   

{

     ADMUX=(0<<REFS1)|(0<<REFS0)|(0<<ADLAR)|(ADC_chunnel&0x1F);  

     ADCSRA=(1<<ADEN)|(1<<ADSC)|(0<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);

     delay_nus(400);         

     ADCSRA=0x00;                                            

     return (ADC&0x03FF);

出0入0汤圆

发表于 2007-4-19 21:47:04 | 显示全部楼层
我毕业设计做数据采集,用AVR单片机控制

一点感觉都没有

出0入0汤圆

发表于 2007-4-20 11:52:19 | 显示全部楼层
我没有用过ICC或GCC开发环境,我用的是CODE VISIONAVR

ADCSRA=(1<<ADEN)|(1<<ADSC)|(0<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); 一定要这样写吗??可以写成ADCSRA|=0XC7吗??

出0入0汤圆

发表于 2007-4-20 13:43:00 | 显示全部楼层
前一段用M8的ADC做了一个产品,

1-5V分成17个档位输出,

发现采用外部基准电压,

转换误差比较大,

大概误差80mV左右。

采用内部AVCC作为基准,

误差仅为10mV左右。

是M8本身的问题,

还是我的外部基准有问题呢?

出0入0汤圆

发表于 2007-10-12 21:56:57 | 显示全部楼层
我靠,楼主的程序看的我头晕死了,受不了!!!!

程序可读性不高!!!

出0入0汤圆

发表于 2007-11-3 16:07:25 | 显示全部楼层

出0入0汤圆

发表于 2007-12-5 16:54:52 | 显示全部楼层
呵呵,是不是刚学还是刚从51转过来的,呵呵,感觉1楼的作者是个悟性也高的人。路过踩一下,留下咱们进步的脚印……呵呵

出0入0汤圆

发表于 2007-12-7 00:08:43 | 显示全部楼层
shoucang

出0入0汤圆

发表于 2008-1-28 22:56:26 | 显示全部楼层
学习楼主的例程,顶顶!!!

出0入0汤圆

发表于 2008-1-29 13:44:38 | 显示全部楼层
刚开始涉及AVR。感觉还不是很好,没找到中断函数的定义方法及各个矢量的地址,看来还得在看看资料。呵呵

出0入0汤圆

发表于 2009-2-26 15:10:15 | 显示全部楼层
学习楼主的例程,顶顶!!!

出0入0汤圆

发表于 2009-2-26 18:01:09 | 显示全部楼层
学习

出0入0汤圆

发表于 2009-6-15 14:56:12 | 显示全部楼层
ddddddddddddddddd

出0入0汤圆

发表于 2009-6-18 11:59:06 | 显示全部楼层
标记一下,谢谢诶分享!

出0入0汤圆

发表于 2009-7-14 21:26:07 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-7-14 22:03:32 | 显示全部楼层
想问一下,现在的1602多少钱。

出0入0汤圆

发表于 2009-8-10 19:30:54 | 显示全部楼层
好好消化一下才行!!

出0入4汤圆

发表于 2010-5-7 22:22:51 | 显示全部楼层
不知现在学,晚不晚

出0入0汤圆

发表于 2010-7-21 10:29:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-7-22 17:48:21 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-14 11:08:36 | 显示全部楼层
mark,过两天也做一个玩玩
头像被屏蔽

出0入0汤圆

发表于 2011-4-10 12:22:53 | 显示全部楼层
记号
头像被屏蔽

出0入0汤圆

发表于 2011-4-18 19:05:39 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-7-8 11:33:24 | 显示全部楼层
mark
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-6 07:35

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表