Forum: Mikrocontroller und Digitale Elektronik Atmega644; ADC inbetriebnahme funktioniert nicht


von adcproblem (Gast)


Lesenswert?

Hi,
ich versuche nun seit geraumer Zeit beim Mega644 den ADC zum laufen zu 
bringen.

Allerdings kommen nur seltsame Werte bei raus:
1
#include <avr/interrupt.h>
2
#include <avr/io.h>
3
#include "adc/adc.h"
4
5
6
#include <stdio.h>
7
#include <string.h>
8
#include <stdlib.h>
9
10
#include "uart/uart.h"
11
12
#define nop() asm volatile("nop")
13
#define ADC_DEBUG
14
15
void adc_init(void)
16
{
17
  unsigned int tmp_adc_level;
18
19
  DDRA = 0x00; //Input
20
  PORTA = 0x00;
21
22
  ADMUX  = (1 << REFS1) | (1 << REFS0); //AVCC with external capacitor at AREF pin
23
  ADMUX |= (0 << ADLAR); //Right adjusting
24
  ADMUX |= (0 << MUX4) | (0 << MUX3) | (1 << MUX2) | (0 << MUX1) | (0 << MUX0); //ADC4
25
26
  ADCSRA  = (1 << ADEN) | (0 << ADSC) | (0 << ADATE); //Enable; Don't start conv here; No auto trig
27
  ADCSRA |= (1 << ADIF) | (0 << ADIE); //Clear interrupt flag; ADC interrupt disable
28
  ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); //Prescaler = 128 (125kHz/FCPU=16MHz)
29
30
  ADCSRA |= (1 << ADSC);  // Start ACD conversion
31
  while ((ADCSRA & (1<<ADIF))==0)
32
    nop();  //Wait for conversion finished
33
  tmp_adc_level = ADCW; //(ADCH << 8) + ADCL
34
}
35
36
unsigned int adc_get(void)  //TODO uint8 channel
37
{
38
  unsigned int tmp_adc_level;
39
#ifdef ADC_DEBUG
40
  char buffer[20];
41
  unsigned int i = 0;
42
#endif
43
  ADCSRA |= (1 << ADSC);  // Start ACD conversion
44
  
45
  while ((ADCSRA & (1<<ADIF))==0)
46
    nop();  //Wait for conversion finished
47
48
  ADCSRA |= (1<<ADIF);                     // Clear ISR flag, usually done by HW
49
50
#ifdef ADC_DEBUG
51
  sprintf(buffer, "ADCL := %i\n\r", ADCL);
52
  uart_puts("\n\r\n\r");
53
  uart_puts(buffer);
54
55
  sprintf(buffer, "ADCH := %i\n\r", ADCH);
56
  uart_puts(buffer);
57
  uart_puts("\n\r\n\r");
58
59
  sprintf(buffer, "ADCW := %i\n\r", ADCW);
60
  uart_puts(buffer);
61
  uart_puts("\n\r\n\r");
62
63
  cli();
64
  tmp_adc_level = ADCL + (ADCH << 8);
65
  sei();
66
  sprintf(buffer, "ADC := %i\n\r", tmp_adc_level);
67
  uart_puts(buffer);
68
  uart_puts("\n\r\n\r");
69
70
  uart_puts("--------------------");
71
  uart_puts("\n\r\n\r");
72
#endif
73
  return tmp_adc_level;
74
}
adc_get() wird periodisch in main while(1) aufgerufen.

Ich habe einen Trace mit putty aufgenommen und bekomme für
ADCL werte Zwischen 10 und 60
ADCH immer 1
ADCW Werte zwischen 270 und 330.

Das große Problem hier ist, am ADC liegen NULL VOLT an.
Ich habe das Ganze mit dem ADC4, 3, und 2 ausprobiert.

Am Referenzpin liegen 4,87 Volt an.
Ich habe auch versucht die interne 2,5V Referenz zu benutzen, gleiches 
Ergebnis.

Habe ich irgend etwas bei der initialisierung vergessen?
Mache ich irgend was in meinem Code falsch?
Oder ist mein Mega hin?

Gruß

von spess53 (Gast)


Lesenswert?

Hi

> while ((ADCSRA & (1<<ADIF))==0)

Warum machst du es nicht, wie alle anderen:

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Nutzung_des_ADC

MfG Spess

von adcproblem (Gast)


Lesenswert?

Hallo, danke für den Hinweis,...
ich habe die im Tutorial empfohlene funktionen weitestgehend übernommen:
1
#define ADC_DEBUG
2
3
void adc_init(void)
4
{
5
    uint16_t result;
6
7
    ADMUX = (0<<REFS1) | (1<<REFS0);      // AVcc als Referenz benutzen
8
  //  ADMUX = (1<<REFS1) | (1<<REFS0);      // interne Referenzspannung nutzen
9
    ADMUX |= 0x02; //ADC2
10
    ADCSRA = (1<<ADPS2) | (1<<ADPS1);     // Frequenzvorteiler => 250kHz
11
    ADCSRA |= (1<<ADEN);                  // ADC aktivieren
12
13
    /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
14
       also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
15
16
    ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung
17
    while (ADCSRA & (1<<ADSC) ) {}        // auf Abschluss der Konvertierung warten
18
    /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
19
       Wandlung nicht übernommen. */
20
    result = ADCW;
21
22
}
23
24
unsigned int adc_get( void )
25
{
26
  unsigned char channel = 2; //ADC2
27
  char buffer[20];
28
29
  // Kanal waehlen, ohne andere Bits zu beeinflußen
30
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
31
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
32
  while (ADCSRA & (1<<ADSC) ) {}  // auf Abschluss der Konvertierung warten
33
#ifdef ADC_DEBUG
34
  sprintf(buffer, "ADCW := %i\n\r", ADCW);
35
  uart_puts(buffer);
36
  uart_puts("--------------------");
37
  uart_puts("\n\r\n\r");
38
#endif
39
  return ADCW;                    // ADC auslesen und zurückgeben
40
}

Leider mit gleichem Ergebnis :-(
Habe ich vlt. einen Fehler bei meiner sprintf Benutzung?

Gruß

von Helfer (Gast)


Lesenswert?

> Habe ich vlt. einen Fehler bei meiner sprintf Benutzung?

Nö. Ich würde aber ADCW nicht doppelt auslesen, sondern einmal nach dem 
while in eine lokale Variable und dann diese Variable ggf. im Debugfall 
ausgeben und immer regulär als Rückgabewert.

von Helfer (Gast)


Lesenswert?

Zum Problem an sich würde ich mir mindestens den Schaltplan besser noch 
zusätzlich ein Foto vom Aufbau wünschen. Denn ich bezweifele, dass es 
eine Softwareursache gibt, jedenfalls soweit es den gezeigten Ausschnitt 
betrifft.

von Purzel H. (hacky)


Lesenswert?

Zusaetzlich koennte der JTAG noch auf dem ADC liegen ... pruef das mal.

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.