zengwei 发表于 2011-11-30 22:01:19

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

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

zengwei 发表于 2011-12-1 08:40:28

求解

walshao 发表于 2011-12-1 09:17:07

ADIF是中断标志位

walshao 发表于 2011-12-1 09:17:24

最好还是看下你程序,帮顶了

zengwei 发表于 2011-12-1 10:02:28

回复【2楼】walshao万少
-----------------------------------------------------------------------
我查询ADIF是否置1判断转换是否完成。

walshao 发表于 2011-12-1 10:11:49

那你就用中断处理啊,硬件会自动清零的……

zengwei 发表于 2011-12-1 12:31:19

回复【5楼】walshao 万少
-----------------------------------------------------------------------

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

walshao 发表于 2011-12-1 17:14:52

回复【6楼】zengwei
-----------------------------------------------------------------------

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

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

zengwei 发表于 2011-12-2 09:17:31

回复【7楼】walshao万少
-----------------------------------------------------------------------

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

walshao 发表于 2011-12-2 11:25:43

回复【8楼】zengwei
-----------------------------------------------------------------------

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

zengwei 发表于 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={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]|0x80;
_delay_ms(2);

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

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

   PORTB=~(1<<PB7);
PORTD=CodeTab];
_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();
}


那麻烦你看一下了。

walshao 发表于 2011-12-2 17:13:52

ad_dat=ADC;?这个是神马,你用的什么编译器啊

zengwei 发表于 2011-12-2 23:08:13

回复【11楼】walshao 万少
-----------------------------------------------------------------------

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

baikenuer 发表于 2011-12-2 23:11:52

我以前也发生过一个师兄帮我调好的,有个控制转换通道的寄存器你改了之后应该再改回来的,你看看吧!估计是这样! 我没看你程序啊!

zengwei 发表于 2011-12-3 00:14:47

回复【13楼】baikenuer
-----------------------------------------------------------------------
控制转换通道的寄存器跟这有什么关系?

machao 发表于 2011-12-3 21:05:37

我编写的教程中有相同的例程。例:10.3,可以参考对照。

millwood0 发表于 2011-12-4 03:17:50

"什么回事??"

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

boy_want 发表于 2012-1-17 09:35:35

piaogup

xuanfong1 发表于 2014-4-27 21:12:09

路过路过赞下吧

panhai0101 发表于 2014-12-26 22:52:44

machao 发表于 2011-12-3 21:05
我编写的教程中有相同的例程。例:10.3,可以参考对照。

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

    adc_data=ADCW;                  //读取ADC置换结果                  
    adc_v=(unsigned long)adc_data*2560/1024;    //换算成电压值

}
void main(void)
{

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

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

//#asm("sei")   // 开放全局中断
        while(1)
        {
                lcd_gotoxy(0,0);                                // clere the LCD   
      lcd_4_char(adc_v);
                //lcd_putsf("It's demo_6_8.c");        // display the message
            lcd_gotoxy(0,1);                                // go on the second LCD line
      lcd_3_char(222);   
      lcd_float(52.9) ;
            //delay_ms(500);
    }       
}

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

                lcd_table=data_2_char/10;    //获得十位的数字
                lcd_table=data_2_char%10;    //获得个位的数字
   
                lcd_putchar(lcd_table+0x30); //显示十位   
                lcd_putchar(lcd_table+0x30); //显示个位
}
//------------------------------------------------------------------------
void lcd_3_char(unsigned int data_3_char)      //在1602LCD上显示一个3位的整数
{                unsigned int lcd_table;

                lcd_table=data_3_char/100;       //获得百位的数字
                lcd_table=data_3_char%100/10;    //获得十位的数字
                lcd_table=data_3_char%10;      //获得个位的数字
            
                lcd_putchar(lcd_table+0x30); //显示百位   
                lcd_putchar(lcd_table+0x30); //显示十位   
                lcd_putchar(lcd_table+0x30); //显示个位
}
//------------------------------------------------------------------------
void lcd_4_char(unsigned int data_4_char)      //在1602LCD上显示一个4位的整数
{                unsigned int lcd_table;

                lcd_table=data_4_char/1000;      //获得千位的数字
                lcd_table=data_4_char%1000/100;    //获得百位的数字
                lcd_table=data_4_char%100/10;      //获得十位的数字
                lcd_table=data_4_char%10;          //获得个位的数字

               lcd_putchar(lcd_table+0x30); //显示千位
               lcd_putchar(lcd_table+0x30); //显示百位   
               lcd_putchar(lcd_table+0x30); //显示十位   
               lcd_putchar(lcd_table+0x30); //显示个位
}
//----------------------------------------------------------------------------------
void lcd_5_char(unsigned int data_5_char)      //在1602LCD上显示一个5位的整数void lcd_5_char(unsigned int data_5_char);
{                unsigned int lcd_table;
                              
                lcd_table=data_5_char%100000/10000;      //获得万位的数字
                lcd_table=data_5_char%10000/1000;          //获得千位的数字
                lcd_table=data_5_char%1000/100;            //获得百位的数字
                lcd_table=data_5_char%100/10;            //获得十位的数字
                lcd_table=data_5_char%10;                  //获得个位的数字

            
                  lcd_putchar(lcd_table+0x30); //显示万位
                  lcd_putchar(lcd_table+0x30); //显示千位
                  lcd_putchar(lcd_table+0x30); //显示百位   
                  lcd_putchar(lcd_table+0x30); //显示十位   
               lcd_putchar(lcd_table+0x30); //显示个位
}
void lcd_float(float f_data)      //在1602LCD上显示一个小于100、保留3位小数的浮点数
{                unsigned char lcd_table;
                unsigned long aa;
                aa=f_data*1000;                   //保留3位小数

                lcd_table= aa/10000 ;                //分别获取各位上的数
                lcd_table= aa%10000/1000 ;
                lcd_table= aa%1000/100 ;
                lcd_table= aa%100/10 ;
                lcd_table= aa%10 ;               
                if (lcd_table==0)      lcd_putchar(' '); //如果整数部分的十位数是0则不显示(显示空格)
                        elselcd_putchar(lcd_table+0x30); //显示整数部分的十位数,加上0x30以便直接得到相应的ASCII码去显示
               lcd_putchar(lcd_table+0x30); //显示整数部分的个位数
               lcd_putchar('.');                            //显示小数点"."         
               lcd_putchar(lcd_table+0x30); //显示小数部分的十分位   
               lcd_putchar(lcd_table+0x30); //显示小数部分的百分位   
               lcd_putchar(lcd_table+0x30); //显示小数部分的千分位
}

。h文件
#ifndef __LCD1602_H__
#define __LCD1602_H__

#include <mega16.h>
#include <delay.h>
#include <lcd.h>
/*
lcd_gotoxy();
lcd_putsf();
lcd_putsf("It's demo_6_8.c");                          ;PORTC数据寄存器地址
    lcd_clear();          
   
   lcd_float() ;
*/   



void lcd_1_char(unsigned char data_1_char) ;   
void lcd_2_char(unsigned char data_2_char);//显示二位整数:
void lcd_3_char(unsigned int data_3_char);        //显示三位整数:
void lcd_4_char(unsigned int data_4_char);        //显示四位整数:
void lcd_5_char(unsigned int data_5_char);        //显示五位整数:
void lcd_float(float f_data) ;         
#endif /* LCD1602_H_ */

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

panhai0101 发表于 2014-12-26 23:09:20

machao 发表于 2011-12-3 21:05
我编写的教程中有相同的例程。例:10.3,可以参考对照。

明白了。跟T0的匹配中断函数有关,那个中断函数没写,导致一直在中断中。已经解决了,花了一天的时间,有点心疼时间过得快。得回去宿舍了,明天再研究,因为宿舍有个哥们明天考研,不能打扰他休息。
页: [1]
查看完整版本: AVR ADC 只有第一次转换结果能存入寄存器,此后的转换结果皆无效.什么回事??