Forum: Mikrocontroller und Digitale Elektronik Atmega328P ADC Problem


von Patrick (Gast)


Lesenswert?

Hallo zusammen,

ich habe ein kleine Problem mit meiner ADC Messung.

Kurze Beschreibung der Schaltung.

ARef wurde mit einem 100nF Kond. auf GND gelegt.
Dann habe ich die Vee von meinem LCD Display mit einem 4,7K Widerstand 
an PC0 angeschlossen.

Wollte dort mal die Spannung messen als erstes Beispiel.

Leider bekomme ich nur den Wert 1023 heraus.

Keine Ahnung warum (habe ebend erst mit ADC angefangen).

Verzeit mir den GruselCode.
Haben es einfach "zusammengeklatsch".

Könnte ihr den Fehler erkennen?

Besten Dank
Patrick
1
// ************************************************************************************************
2
//    Absolute Beginner Projekt 04
3
//
4
//  Textanzeige auf einem LCD
5
// ************************************************************************************************
6
// Copyright keins
7
// Version
8
/*
9
* Chip type           : ATMEGA 88
10
* Clock frequency     : Internal clock 1 Mhz (The device is shipped with this option selected.)
11
* Fuse Bits einfach auf Auslieferungszustand lassen!
12
13
Ein- und Ausgänge
14
PORT B 0 (14) =
15
PORT B 1 (15) =
16
PORT B 2 (16) =
17
PORT B 3 (17) =
18
PORT B 4 (18) =
19
PORT B 5 (19) =
20
PORT B 6 ( 9) =
21
PORT B 7 (10) =
22
23
PORT C 0 (23) =
24
PORT C 1 (24) =
25
PORT C 2 (25) =
26
PORT C 3 (26) =
27
PORT C 4 (27) =
28
PORT C 5 (28) =
29
30
PORT D 0 ( 2) = Anschluss 11 am LCD = DB4
31
PORT D 1 ( 3) = Anschluss 12 am LCD = DB5
32
PORT D 2 ( 4) = Anschluss 13 am LCD = DB6
33
PORT D 3 ( 5) = Anschluss 14 am LCD = DB7
34
PORT D 4 ( 6) = Anschluss  4 am LCD = RS
35
PORT D 5 (11) = Anschluss  6 am LCD = E Enable
36
PORT D 6 (12) =
37
PORT D 7 (13) =
38
*/
39
40
41
// Main.c
42
//
43
44
// ************************************************************************************************
45
// Include Dateien laden
46
// ************************************************************************************************
47
48
#include <avr/io.h>
49
#include "lcd-routines.h"
50
#include <util/delay.h>
51
#define F_CPU 8000000 //8.000.000
52
53
54
uint16_t readADC(uint8_t channel) {
55
  uint8_t i;
56
  uint16_t result = 0;
57
  
58
  // Den ADC aktivieren und Teilungsfaktor auf 64 stellen
59
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
60
61
  // Kanal des Multiplexers waehlen
62
  // Interne Referenzspannung verwenden (also 2,56 V)
63
  ADMUX = channel | (1<<REFS1) | (1<<REFS0);
64
  
65
  // Den ADC initialisieren und einen sog. Dummyreadout machen
66
  ADCSRA |= (1<<ADSC);
67
  while(ADCSRA & (1<<ADSC));
68
  
69
  // Jetzt 3x die analoge Spannung and Kanal channel auslesen
70
  // und dann Durchschnittswert ausrechnen.
71
  for(i=0; i<3; i++) {
72
    // Eine Wandlung
73
    ADCSRA |= (1<<ADSC);
74
    // Auf Ergebnis warten...
75
    while(ADCSRA & (1<<ADSC));
76
    
77
    result += ADCW;
78
  }
79
  
80
  // ADC wieder deaktivieren
81
  ADCSRA &= ~(1<<ADEN);
82
  
83
  result /= 3;
84
  
85
  return result;
86
}
87
88
89
int main(void)
90
{
91
  
92
  //DDRB |= (1 << PB0);
93
  // Initialisierung des LCD
94
  // Nach der Initialisierung müssen auf dem LCD vorhandene schwarze Balken
95
  // verschwunden sein
96
  lcd_init();
97
  
98
  // Text in einzelnen Zeichen ausgeben
99
  lcd_data( 'T' );
100
  lcd_data( 'e' );
101
  lcd_data( 's' );
102
  lcd_data( 't' );
103
  lcd_data( ' ' );
104
  // erneut Text ausgeben, aber diesmal komfortabler als String
105
  lcd_string("Hello World");
106
107
  // Die Ausgabemarke in die 2te Zeile setzen
108
  lcd_setcursor( 0, 2 );
109
  
110
  
111
  // Beispiel
112
  int variable = 14236;
113
  // Ausgabe der Variable als Text in dezimaler Schreibweise
114
  {
115
    // ... umwandeln siehe FAQ Artikel bei http://www.mikrocontroller.net/Articles/FAQ
116
    // WinAVR hat eine itoa()-Funktion, das erfordert obiges #include <stdlib.h>
117
    char Buffer[20]; // in diesem {} lokal
118
    itoa( variable, Buffer, 10 );
119
    
120
    // ... ausgeben
121
    lcd_string( Buffer );
122
  }
123
  lcd_data( 'k' );
124
  lcd_data( 'm' );
125
  lcd_data( '/' );
126
  lcd_data( 'h' );
127
128
  DDRB  = 0xff;
129
  int i = 0;
130
  _delay_ms(5000);
131
  while(1) {
132
    
133
    lcd_clear();
134
    lcd_setcursor( 0, 1 );
135
    uint16_t result = readADC(0);  //Auslesen der analogen Spannungen an Pin 0,
136
    // also ADC0. In result steht das Ergebnis.
137
    char Buffer[20]; // in diesem {} lokal
138
    char Buffer2[20]; // in diesem {} lokal
139
    itoa(i, Buffer, 10 );
140
    itoa(result , Buffer2, 10 );
141
    lcd_string( Buffer );
142
    lcd_setcursor( 0, 2 );
143
    lcd_string( Buffer2 );
144
    PORTB |= (1<<PB0);    //Bit setzen
145
    _delay_ms(500);       // halbe sekunde warten
146
    PORTB &= ~(1<<PB0);   // Bit loeschen
147
    _delay_ms(500);       // halbe sekunde warten
148
    
149
    i++;
150
  }
151
  
152
  return 0;
153
}

von Erik S. (erik_s)


Lesenswert?

1023 bekommst du bei Vollaussteuerung oder Übersteuerung des ADC, also 
wenn die Eingangsspannung größer als die Refernzspannung ist:

Die Referenzspannungsquelle des ADC muss den Pufferkondensator am 
Aref-Pin erst laden, das dauert länger als ein paar CPU-Takte. Du 
könntest entweder den ADC an lassen, wenn es auf dessen Stromaufnahme 
nicht ankommt, oder eine Warteschleife zwischen Aktivierung der Referenz 
und Beginn der Wandlungen setzen.

Edit: Der ATMega328P hat laut Datenblatt keine interne 
2,56V-Referenzspannungsquelle, sondern nur 1,1V.

: Bearbeitet durch User
von Thomas (kosmos)


Lesenswert?

Evtl sind die internen Pullup Widerstände aktiviert dann liegt VCC am 
Eingangspin an.

von Walter S. (avatar)


Lesenswert?

miss mal die Spannung an PC0, vielleicht ist sie größer als 1,1 Volt

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Patrick schrieb:
> #include <util/delay.h>
> #define F_CPU 8000000 //8.000.000

Da solltest du eine Fehlermeldung bekommen, weil <util/delay.h> schon 
F_CPU benötigt. Tausch einfach mal die Zeilen. Das ist bei IDEs wie 
Atmel Studio allerdings nicht nötig, da F_CPU in den Projekt 
Einstellungen gesetzt wird. Um dabei Verwirrungen zu vermeiden, kannst 
du sowas machen
1
#ifndef F_CPU
2
#define F_CPU 8000000UL
3
#endif
Entscheide dich auch für die wahre Taktfrequenz. Im Header schreibst du 
was von Auslieferzustand, setzt dann aber statt 1MHz die 8MHz.
Patrick schrieb:
> // Den ADC initialisieren und einen sog. Dummyreadout machen
>   ADCSRA |= (1<<ADSC);
>   while(ADCSRA & (1<<ADSC));
Mach den Readout ruhig und verwirf das Ergebnis.

Es ist übrigens nicht nötig, jedesmal den ADC zu initialisieren. Das 
kannst du einmal machen und dann in einer ADCRead Routine nur noch 
starten und abfragen.

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

Matthias S. schrieb:
> #ifndef F_CPU
> #define F_CPU 8000000UL
> #endif

Das kann man machen. Ideal ist das aber nicht. Deswegen bevorzuge ich 
die härtere Gangart:
1
#ifndef F_CPU
2
 #error F_CPU not defined.
3
#endif

: Bearbeitet durch User
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.