AVR ADC 只有第一次转换结果能存入寄存器,此后的转换结果皆无效.什么回事??
学习avr内部的ad转换实验的时候发现1.当我选择自动触发 并选择定时器计数器0比较匹配做为触发源在中断里面读取转换的ADC值 并在数码管上面显示 发现只有第一次转换结果能存入寄存器,此后的转换结果皆无效,只能复位才能读到当前的数据
2.当我选择自动触发 并选择连续转换模式的时候 在中断里面读取转换的ADC值现在数码管上面能显示当前的值了 但是数码管上面的数字很明显的一个接一个显示 人眼一下就识别了。
3.如果我选择连续转换模式 并用查询的方式 是不是每次AD转换完成后都要清零ADIF? 求解 ADIF是中断标志位 最好还是看下你程序,帮顶了 回复【2楼】walshao万少
-----------------------------------------------------------------------
我查询ADIF是否置1判断转换是否完成。 那你就用中断处理啊,硬件会自动清零的…… 回复【5楼】walshao 万少
-----------------------------------------------------------------------
如果设置为连续转换模式的话 会一直进入中断 主函数里面的程序就不能正常执行了。 回复【6楼】zengwei
-----------------------------------------------------------------------
我看了你另外一个帖子,你是用的T/C0比较匹配作为触发源的吧?
想想,你的T/C0会不会一直都发生在比较匹配吧?那么会不会一直进入中断呢? 回复【7楼】walshao万少
-----------------------------------------------------------------------
我用比较匹配作为触我在比较匹配里面清发源时候发现,只进行了一次ad转换(比较匹端中标志位定时清除) 回复【8楼】zengwei
-----------------------------------------------------------------------
看下你T/C0程序有问题没 回复【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();
}
那麻烦你看一下了。 ad_dat=ADC;?这个是神马,你用的什么编译器啊 回复【11楼】walshao 万少
-----------------------------------------------------------------------
我用的studio GCC编译器ad_dat=ADC是读取AD转换结果。 我以前也发生过一个师兄帮我调好的,有个控制转换通道的寄存器你改了之后应该再改回来的,你看看吧!估计是这样! 我没看你程序啊! 回复【13楼】baikenuer
-----------------------------------------------------------------------
控制转换通道的寄存器跟这有什么关系? 我编写的教程中有相同的例程。例:10.3,可以参考对照。 "什么回事??"
all of your questions and more can be easily answered if you just read the @#%%#^#!@ datasheet. piaogup 路过路过赞下吧 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采样电压,就不行了。 machao 发表于 2011-12-3 21:05
我编写的教程中有相同的例程。例:10.3,可以参考对照。
明白了。跟T0的匹配中断函数有关,那个中断函数没写,导致一直在中断中。已经解决了,花了一天的时间,有点心疼时间过得快。得回去宿舍了,明天再研究,因为宿舍有个哥们明天考研,不能打扰他休息。
页:
[1]