ADC Wandlung mit Interrupt geht nicht

Gast #2431769
Lesenswert?

Hi!

Ich probier gerade die ADC Wandlung mit Interrupt, so dass der Wert auf 
dem LCD Display aktualisiert wird.

Ohne Interrupt hab ichs zum laufen gebracht, aber sobald ich sei(); 
einfüge, scheint das Programm stecken zu bleiben und die LCD Ausgabe 
wird nicht mehr erreicht.

Kann mir bitte wer helfen?

Danke!

andi
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "lcd.h"
4

5
char buffer[7];
6
int adc_value;
7

8

9
void ISR_ADC(void)
10
{
11

12
  while (ADCSRA & (1<<ADSC))
13
  {
14
  }
15
  adc_value= ADCL;
16
  adc_value+= (ADCH<<8);
17
}    
18

19

20
int main(void)
21
{
22
  lcd_init(LCD_DISP_ON);
23
  lcd_clrscr();
24
  
25
  ADMUX= (1<<REFS1)|(1<<REFS0)|(1<<ADLAR)|(1<<MUX0);
26
  ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADIE)|(1<<ADATE);
27
  
28
  sei();
29
  
30
  while(1)
31
    {
32
  lcd_gotoxy(0,0);
33
        lcd_puts("ADC Value: ");
34
    lcd_gotoxy(13,0);
35
    itoa(adc_value, buffer, 10);
36
    lcd_puts(buffer);  
37
    }
38
}
#2431781
Lesenswert?

Ich bin kein großer Atmel Kenner, vermute aber, dass du die while 
Schleife im Interrupt nicht verlässt.

folgende Zeile startet ja bereits deine AD-Wandlung:
  ADCSRA = 
(1<<ADEN)|(1<<ADSC)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADIE)|(1<<ADATE);

sobald die Wandlung komplett ist wird das zugehörige Flag für den 
Wandler gesetzt und gleichzeitig ADSC gelöscht!

die Schleife
  while (ADCSRA & (1<<ADSC))
  {
  }
wird somit nie verlassen, da ADSC nun bereits 0 ist


Generell ist der AD Interrupt eigentlich dazu da, dass man eben nicht 
auf die Fertigstellung der Konversion warten muss, wozu also die 
Schleife? Sobald der Interrupt aufgerufen wird ist das AD Ergebnis 
bereits vorhanden.
#2431785
Lesenswert?

Soweit ich das noch weiß, brauchst du in deiner Interuptroutine nicht 
mehr warten, bis der uC fertig gewandelt hat, sondern die Routine wird 
ja aufgrufen, wenn ein Wert bereit ist.

Nebenbei würde ich in der Initialisierung vom adc_value lieber den 
Datentyp long nehmen, da der auf jedenfall 26 bit ist und nicht wie int 
systemabhängig
Gast #2431887
Lesenswert?

und ich würde zum einen noch volatile davor schreiben,
außerdem adc_value= ADC (ist einfacher)

UND da adc_value aus 2 Bytes besteht den Interrupt sperren wenn ich es 
im main auslese.

und die Anzeige wird häßlich flimmern
Gast #2431985
Lesenswert?

DANKE für alle Tips, ich hab jetzt was geändert und es funktioniert 
soweit.

Frage: Warum fängt der angezeigte Wert bei 21 an und nicht bei Null.
Bei voll aufgedrehtem Poti wird 955 angezeigt und nicht 1024 (10 bit).

Ist das einfach so eine Art Streuung, und muss ich einfach 21 vom Wert 
abziehen?.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "lcd.h"
4
#include <util/delay.h>
5

6
#define ADC_CHANNEL    1
7

8
volatile unsigned int adc_data;
9
char buffer[7];
10

11
ISR (ADC_vect)
12
{
13
  adc_data= ADC;
14
}
15

16

17
int main(void)
18
{
19

20
  ADMUX= (1<<REFS1)|(1<<REFS0);//Interne Referenz
21
  ADMUX= (ADMUX & ~(0x1F))|(0&0x1F);// Kanal A0 auswählen
22
  ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADATE)|(1<<ADPS2)|(1<<ADPS0);
23

24
  lcd_init(LCD_DISP_ON);
25
  lcd_clrscr();
26
  sei();
27
  
28
    while(1)
29
    {
30
    lcd_gotoxy(0,0);
31
    lcd_puts("ADC: ");  
32
    _delay_ms(1000);
33
    lcd_clrscr();    
34
    lcd_gotoxy(6,0);
35
    cli();
36
    itoa(adc_data, buffer, 10);
37
    sei();
38
    lcd_puts(buffer);  
39
    
40
    }
41
}
Gast #2432004
Lesenswert?

..also ich hab jetzt mal die Interrupt- Dinge rauskommentiert und der 
ADC funktioniert immer noch, soll wohl heissen, dass mein Programm so 
nicht funktioniert. Was kann das sein ?

[c]#include <avr/io.h>
#include <avr/interrupt.h>
#include "lcd.h"
#include <util/delay.h>

#define ADC_CHANNEL    1

volatile unsigned int adc_data;
char buffer[7];

//ISR (ADC_vect)
//{
  //adc_data= ADC;
//}


int main(void)
{

  ADMUX= (1<<REFS1)|(1<<REFS0);//Interne Referenz
  ADMUX= (ADMUX & ~(0x1F))|(0&0x1F);// Kanal A0 auswählen
  ADCSRA = 
(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADATE)|(1<<ADPS2)|(1<<ADPS0);

  lcd_init(LCD_DISP_ON);
  lcd_clrscr();
  //sei();

    while(1)
    {
    lcd_gotoxy(0,0);
    lcd_puts("ADC: ");
    _delay_ms(1000);
    lcd_clrscr();
    lcd_gotoxy(6,0);
    //cli();
    itoa(ADC, buffer, 10);
    //sei();
    lcd_puts(buffer);

    }
}[c]
Gast #2432015
Lesenswert?

@Karl Heinz Buchegger
@avrGerd

Das ist ein selber gebasteltes Experimentierboard, wo die Leitungen 
etwas länger sind (ca 30cm), kann das schon einen Einfluss haben?

Der Grund für die langen Leitungen: Eigentlich ist das Board für PIC 
Prozessoren, aber ich hab einfach vom Pollin Board die Ausgänge auf eine 
Stiftleiste gelötet und in den Textool Sockel vom PIC- Board 
reingesteckt. Vielleicht gibts da Nebeneffekte.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren