Forum: Mikrocontroller und Digitale Elektronik ADC Wandlung mit Interrupt geht nicht


von andi (Gast)


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
}

von Stefan E. (sternst)


Lesenswert?


von Vincent H. (vinci)


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.

von Lutz B. (lutzbroszio)


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

von Bernd (Gast)


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

von captnhanky (Gast)


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
}

von Karl H. (kbuchegg)


Lesenswert?

Wie hast du denn dein Poti angeschlossen?

(Nimm es halt mal raus und verbinden den ADC Eingang direkt mit GND. 
Dann muss deine Anzeige 0 sein. Genauso muss die Anzeige, wenn du die 
Referenzspannung misst, 1023 sein)

von avrGerd (Gast)


Lesenswert?

Nein, es ist keine Streuung. So große Abweichungen solltest Du nicht 
bekommen.

Wie sieht den der Schaltplan und Layout aus?

Hier ist ein vernünftiger Aufbau wichtig.


Gruß,
avrGerd

von captnhanky (Gast)


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]

von captnhanky (Gast)


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.

von Karl H. (kbuchegg)


Lesenswert?

captnhanky schrieb:
> @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?

30cm sind kein Problem.

Miss doch mal GND bzw. die Referenzspannung!
Dann weißt du, obs am Programm liegt oder der Hardware.

von captnhanky (Gast)


Lesenswert?

Ist tatsächlich das Board, den PIN 40 vom Atmega32 kurzgeschlossen 
ergibt 0.

von Karl H. (kbuchegg)


Lesenswert?

captnhanky schrieb:
> Ist tatsächlich das Board, den PIN 40 vom Atmega32 kurzgeschlossen
> ergibt 0.

Dann würde ich aber eher auf das Poti tippen, welches seinen Schleifer 
eben nicht ganz bis an die Widerstandsbahnenden verdrehen kann, so dass 
immer ein kleiner Spannungsteiler übrig bleibt.

von captnhanky (Gast)


Lesenswert?

Ja kann durchaus sein, schaut ziemlich billig aus..

Danke für den Hinweis

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.