搜索
bottom↓
回复: 20

AVR ADC 只有第一次转换结果能存入寄存器,此后的转换结果皆无效.什么回事??

[复制链接]

出0入0汤圆

发表于 2011-11-30 22:01:19 | 显示全部楼层 |阅读模式
学习avr内部的ad转换实验的时候发现
1.当我选择自动触发 并选择定时器计数器0比较匹配做为触发源  在中断里面读取转换的ADC值 并在数码管上面显示 发现只有第一次转换结果能存入寄存器,此后的转换结果皆无效,只能复位才能读到当前的数据
2.当我选择自动触发 并选择连续转换模式的时候 在中断里面读取转换的ADC值  现在数码管上面能显示当前的值了 但是数码管上面的数字很明显的一个接一个显示 人眼一下就识别了。
3.如果我选择连续转换模式 并用查询的方式 是不是每次AD转换完成后都要清零ADIF?

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

 楼主| 发表于 2011-12-1 08:40:28 | 显示全部楼层
求解

出0入0汤圆

发表于 2011-12-1 09:17:07 | 显示全部楼层
ADIF是中断标志位

出0入0汤圆

发表于 2011-12-1 09:17:24 | 显示全部楼层
最好还是看下你程序,帮顶了

出0入0汤圆

 楼主| 发表于 2011-12-1 10:02:28 | 显示全部楼层
回复【2楼】walshao  万少
-----------------------------------------------------------------------
我查询ADIF是否置1判断转换是否完成。

出0入0汤圆

发表于 2011-12-1 10:11:49 | 显示全部楼层
那你就用中断处理啊,硬件会自动清零的……

出0入0汤圆

 楼主| 发表于 2011-12-1 12:31:19 | 显示全部楼层
回复【5楼】walshao 万少
-----------------------------------------------------------------------

如果设置为连续转换模式的话 会一直进入中断 主函数里面的程序就不能正常执行了。

出0入0汤圆

发表于 2011-12-1 17:14:52 | 显示全部楼层
回复【6楼】zengwei
-----------------------------------------------------------------------

我看了你另外一个帖子,你是用的T/C0比较匹配作为触发源的吧?

想想,你的T/C0会不会一直都发生在比较匹配吧?那么会不会一直进入中断呢?

出0入0汤圆

 楼主| 发表于 2011-12-2 09:17:31 | 显示全部楼层
回复【7楼】walshao  万少
-----------------------------------------------------------------------

我用比较匹配作为触我在比较匹配里面清发源时候发现,只进行了一次ad转换(比较匹端中标志位定时清除)

出0入0汤圆

发表于 2011-12-2 11:25:43 | 显示全部楼层
回复【8楼】zengwei
-----------------------------------------------------------------------

看下你T/C0程序有问题没

出0入0汤圆

 楼主| 发表于 2011-12-2 15:20:18 | 显示全部楼层
回复【9楼】walshao 万少
-----------------------------------------------------------------------

#include<avr/io.h>
#include<avr/interrupt.h>
#include<util/delay.h>

#define uchar unsigned char
#define uint unsigned int

uchar CodeTab[] =
{
    0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d,     // 0, 1, 2, 3, 4, 5
    0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c,     // 6, 7, 8, 9, A, b
    0x39, 0x5e, 0x79, 0x71                  // C, d, E, F
};
uchar buffer[4]={0,0,0,0};

void port_init()
{
DDRD=0xff;
PORTD=0xff;     //PA口设置为输出
DDRB=0xff;
PORTB=0xff;      //PB口设置为输出
}

void ad_init()
{
ADMUX|=(1<<REFS0);     //参考电压选择AVCC,模拟通道选择ADC0,单端输入
SFIOR|=(1<<ADTS1)|(1<<ADTS0);    //定时器计数器0比较匹配作为触发源
ADCSRA|=(1<<ADEN)|(1<<ADSC)|(1<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
//ADC使能,ADC使能中断,128预分频
}

void timer0_init()
{
TCNT0=0;
OCR0=90;
TCCR0|=(1<<WGM01)|(1<<CS02);     //CTC模式,256预分频  
TIFR|=(1<<OCF0);      //清除比较匹配中断标志
TIMSK|=(1<<OCIE0);    //输出比较匹配中断使能
}

void dat_buffer(uint dat)
{
uchar i;
for(i=0;i<4;i++)
{
  buffer=dat%10;
  dat/=10;
}
}

void display()
{
  PORTB=~(1<<PB4);
  PORTD=CodeTab[buffer[3]]|0x80;
  _delay_ms(2);

   PORTB=~(1<<PB5);
  PORTD=CodeTab[buffer[2]];
  _delay_ms(2);

   PORTB=~(1<<PB6);
  PORTD=CodeTab[buffer[1]];
  _delay_ms(2);

   PORTB=~(1<<PB7);
  PORTD=CodeTab[buffer[0]];
  _delay_ms(2);
}

int main()
{
  uint i;
  ad_init();       //ad转换初始化设置
timer0_init();   //定时器计数器0比较匹配初始化
port_init();     //IO口初始化设置
_delay_us(100);
sei();           //打开总中断
while(1);
}

ISR(ADC_vect)
{
ADCSRA|=(1<<ADSC);
uint ad_result,ad_dat;

ad_dat=ADC;
ad_result=(unsigned long)ad_dat*5000/1024;      //换算成电压值
dat_buffer(ad_result);
display();
}

ISR(TIMER0_COMP_vect)
{
display();
}


那麻烦你看一下了。

出0入0汤圆

发表于 2011-12-2 17:13:52 | 显示全部楼层
ad_dat=ADC;?这个是神马,你用的什么编译器啊

出0入0汤圆

 楼主| 发表于 2011-12-2 23:08:13 | 显示全部楼层
回复【11楼】walshao 万少
-----------------------------------------------------------------------

我用的studio GCC编译器  ad_dat=ADC是读取AD转换结果。

出0入0汤圆

发表于 2011-12-2 23:11:52 | 显示全部楼层
我以前也发生过  一个师兄帮我调好的,有个控制转换通道的寄存器你改了之后应该再改回来的,你看看吧!估计是这样! 我没看你程序啊!

出0入0汤圆

 楼主| 发表于 2011-12-3 00:14:47 | 显示全部楼层
回复【13楼】baikenuer  
-----------------------------------------------------------------------
控制转换通道的寄存器跟这有什么关系?

出0入0汤圆

发表于 2011-12-3 21:05:37 | 显示全部楼层
我编写的教程中有相同的例程。例:10.3,可以参考对照。

出0入0汤圆

发表于 2011-12-4 03:17:50 | 显示全部楼层
"什么回事??"

all of your questions and more can be easily answered if you just read the @#%%#^#!@ datasheet.

出0入0汤圆

发表于 2012-1-17 09:35:35 | 显示全部楼层
piaogup

出0入0汤圆

发表于 2014-4-27 21:12:09 | 显示全部楼层
路过路过赞下吧

出0入0汤圆

发表于 2014-12-26 22:52:44 | 显示全部楼层
machao 发表于 2011-12-3 21:05
我编写的教程中有相同的例程。例:10.3,可以参考对照。

用1602显示获得的AD采样值,发现开中断LCD就显示不了。
  1. /*********************************************
  2. File name           : demo_6_8.c
  3. Chip type           : ATmega16
  4. Program type        : Application
  5. Clock frequency     : 4.000000 MHz
  6. Memory model        : Small
  7. External SRAM size  : 0
  8. Data Stack size     : 256
  9. *********************************************/
  10. #include <mega16.h>
  11. #include <delay.h>
  12. #include "lcd1602.h"
  13. //
  14. #asm
  15. .equ __lcd_port=0x15         ; PORTC数据寄存器地址
  16. #endasm
  17. /*  [LCD]     
  18.     1 GND- 9  GND
  19.     2 +5V- 10 VCC  
  20.     3 VLC- LCD HEADER Vo
  21.     4 RS - 1  PC0 (M16)
  22.     5 RD - 2  PC1 (M16)
  23.     6 EN - 3  PC2 (M16)
  24.    11 D4 - 5  PC4 (M16)
  25.    12 D5 - 6  PC5 (M16)
  26.    13 D6 - 7  PC6 (M16)
  27.    14 D7 - 8  PC7 (M16) */
  28. unsigned int adc_data,adc_v;
  29. interrupt [ADC_INT] void adc_isr(void)
  30. {   

  31.     adc_data=ADCW;                  //读取ADC置换结果                  
  32.     adc_v=(unsigned long)adc_data*2560/1024;    //换算成电压值
  33.   
  34. }
  35. void main(void)
  36. {

  37.         lcd_init(16);                                // initialize the LCD for 2 lines & 16 columns     
  38.     DDRA=0x00;
  39.     PORTA=0x00;               
  40.     TCCR0=0x0B;     // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  41.     TCNT0=0x00;     
  42.     OCR0=0x7C;      // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  43.     TIMSK=0x02;     // 允许T/C0比较中断

  44.     // ADC 初始化
  45.     ADMUX=0xC7;     // 参考电源内部2.56V、ADC7单端输入!!!!!!!!!!!!!!!!!!!!!!!!!!!
  46.     SFIOR&=0x1F;   
  47.     SFIOR|=0x60;    // 选择T/C0比较匹配中断为ADC触发源
  48.     ADCSRA=0xAD;    // ADC允许、自动触发转换、ADC转换中断允许、ADCclk=125Kz

  49. //  #asm("sei")     // 开放全局中断
  50.         while(1)
  51.         {
  52.                 lcd_gotoxy(0,0);                                // clere the LCD   
  53.         lcd_4_char(adc_v);
  54.                 //lcd_putsf("It's demo_6_8.c");        // display the message
  55.             lcd_gotoxy(0,1);                                // go on the second LCD line
  56.         lcd_3_char(222);   
  57.         lcd_float(52.9) ;  
  58.             //delay_ms(500);
  59.     }       
  60. }
复制代码

.c文件
  1. #include "lcd1602.h"
  2. void lcd_1_char(unsigned char data_1_char)         //在1602LCD上显示一个1位的整数
  3. {                unsigned char lcd_table[2];
  4.                
  5.                 lcd_table[1]=data_1_char%10;       //获得个位的数字   
  6.                 lcd_putchar(lcd_table[1]+0x30); //显示个位
  7. }
  8. //-------------------------------------------------------------------------
  9. void lcd_2_char(unsigned char data_2_char)      //在1602LCD上显示一个2位的整数
  10. {                unsigned char lcd_table[3];

  11.                 lcd_table[1]=data_2_char/10;    //获得十位的数字
  12.                 lcd_table[2]=data_2_char%10;    //获得个位的数字
  13.    
  14.                 lcd_putchar(lcd_table[1]+0x30); //显示十位     
  15.                 lcd_putchar(lcd_table[2]+0x30); //显示个位
  16. }
  17. //------------------------------------------------------------------------
  18. void lcd_3_char(unsigned int data_3_char)        //在1602LCD上显示一个3位的整数
  19. {                unsigned int lcd_table[4];

  20.                 lcd_table[1]=data_3_char/100;       //获得百位的数字
  21.                 lcd_table[2]=data_3_char%100/10;    //获得十位的数字
  22.                 lcd_table[3]=data_3_char%10;        //获得个位的数字
  23.             
  24.                 lcd_putchar(lcd_table[1]+0x30); //显示百位     
  25.                 lcd_putchar(lcd_table[2]+0x30); //显示十位     
  26.                 lcd_putchar(lcd_table[3]+0x30); //显示个位
  27. }
  28. //------------------------------------------------------------------------
  29. void lcd_4_char(unsigned int data_4_char)        //在1602LCD上显示一个4位的整数
  30. {                unsigned int lcd_table[5];

  31.                 lcd_table[1]=data_4_char/1000;        //获得千位的数字
  32.                 lcd_table[2]=data_4_char%1000/100;    //获得百位的数字
  33.                 lcd_table[3]=data_4_char%100/10;      //获得十位的数字
  34.                 lcd_table[4]=data_4_char%10;          //获得个位的数字

  35.                  lcd_putchar(lcd_table[1]+0x30); //显示千位
  36.                  lcd_putchar(lcd_table[2]+0x30); //显示百位     
  37.                  lcd_putchar(lcd_table[3]+0x30); //显示十位     
  38.                  lcd_putchar(lcd_table[4]+0x30); //显示个位
  39. }
  40. //----------------------------------------------------------------------------------
  41. void lcd_5_char(unsigned int data_5_char)        //在1602LCD上显示一个5位的整数  void lcd_5_char(unsigned int data_5_char);
  42. {                unsigned int lcd_table[9];
  43.                               
  44.                 lcd_table[1]=data_5_char%100000/10000;        //获得万位的数字
  45.                 lcd_table[2]=data_5_char%10000/1000;          //获得千位的数字
  46.                 lcd_table[3]=data_5_char%1000/100;            //获得百位的数字
  47.                 lcd_table[4]=data_5_char%100/10;              //获得十位的数字
  48.                 lcd_table[5]=data_5_char%10;                  //获得个位的数字

  49.             
  50.                   lcd_putchar(lcd_table[1]+0x30); //显示万位
  51.                   lcd_putchar(lcd_table[2]+0x30); //显示千位
  52.                   lcd_putchar(lcd_table[3]+0x30); //显示百位     
  53.                   lcd_putchar(lcd_table[4]+0x30); //显示十位     
  54.                  lcd_putchar(lcd_table[5]+0x30); //显示个位
  55. }
  56. void lcd_float(float f_data)        //在1602LCD上显示一个小于100、保留3位小数的浮点数
  57. {                unsigned char lcd_table[5];
  58.                 unsigned long aa;
  59.                 aa=f_data*1000;                   //保留3位小数

  60.                 lcd_table[0]= aa/10000 ;                //分别获取各位上的数
  61.                 lcd_table[1]= aa%10000/1000 ;
  62.                 lcd_table[2]= aa%1000/100 ;
  63.                 lcd_table[3]= aa%100/10 ;
  64.                 lcd_table[4]= aa%10 ;               
  65.                 if (lcd_table[0]==0)        lcd_putchar(' '); //如果整数部分的十位数是0则不显示(显示空格)
  66.                         else  lcd_putchar(lcd_table[0]+0x30); //显示整数部分的十位数,加上0x30以便直接得到相应的ASCII码去显示
  67.                  lcd_putchar(lcd_table[1]+0x30); //显示整数部分的个位数
  68.                  lcd_putchar('.');                            //显示小数点"."         
  69.                  lcd_putchar(lcd_table[2]+0x30); //显示小数部分的十分位     
  70.                  lcd_putchar(lcd_table[3]+0x30); //显示小数部分的百分位     
  71.                  lcd_putchar(lcd_table[4]+0x30); //显示小数部分的千分位
  72. }
复制代码


。h文件
  1. #ifndef __LCD1602_H__
  2. #define __LCD1602_H__

  3. #include <mega16.h>
  4. #include <delay.h>
  5. #include <lcd.h>
  6. /*
  7.   lcd_gotoxy();
  8.   lcd_putsf();
  9. lcd_putsf("It's demo_6_8.c");                          ;PORTC数据寄存器地址
  10.     lcd_clear();          
  11.    
  12.      lcd_float() ;  
  13. */   



  14. void lcd_1_char(unsigned char data_1_char) ;   
  15. void lcd_2_char(unsigned char data_2_char);//显示二位整数:
  16. void lcd_3_char(unsigned int data_3_char);        //显示三位整数:
  17. void lcd_4_char(unsigned int data_4_char);        //显示四位整数:
  18. void lcd_5_char(unsigned int data_5_char);        //显示五位整数:
  19. void lcd_float(float f_data) ;         
  20. #endif /* LCD1602_H_ */
复制代码


如果,把关于ADC的一切操作都注销,仅仅开中断,是可以在1602上显示字符的。
如果,仅仅注销总中断那句,也可以在1602上显示字符的。
但是,想在1602上显示ADC采样电压,就不行了。

出0入0汤圆

发表于 2014-12-26 23:09:20 | 显示全部楼层
machao 发表于 2011-12-3 21:05
我编写的教程中有相同的例程。例:10.3,可以参考对照。

明白了。跟T0的匹配中断函数有关,那个中断函数没写,导致一直在中断中。已经解决了,花了一天的时间,有点心疼时间过得快。得回去宿舍了,明天再研究,因为宿舍有个哥们明天考研,不能打扰他休息。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-3-29 06:26

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

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