Forum: Mikrocontroller und Digitale Elektronik ADC - interne Refspannung


von Hans B. (hans_b92)


Lesenswert?

Liebe Alle,

ich versuche mich derzeit am ADC. Den Schaltungsaufbau bei Nutzung der 
internen Referenzspannung des Atmega32 habe ich aus dem Tutorial (ARef 
über Kondensator an Masse, AGND über Kondensator an Masse, AVCC über 
Kondensator an Masse und 47 Ohm Widerstand an VCC).

Nun habe ich über einen Poti auf den Pin A0 unterschiedliche Spannungen 
geschickt und lasse mir den Rückgabewert des ADC über den UART ausgeben: 
leider derzeit konstant der 1023-ger Wert, der eigentlich für die 
Referenzspannung stehen sollte.

Ich hänge den Code an und wäre dankbar für einen Tipp was da im argen 
liegt.

Vielen Dank
Hans
1
#define F_CPU 8000000UL   
2
3
#include <stdlib.h>
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include <util/delay.h>
7
#include <string.h>
8
#include <stdio.h>
9
10
#define UART_BAUDRATE  4800
11
#define UART_SETTING  ((F_CPU/16L/UART_BAUDRATE)-1)
12
13
14
volatile uint16_t sekunden, msekunden;
15
16
17
18
ISR(TIMER2_COMP_vect)
19
{
20
  static int count, count_sek;
21
  
22
  count_sek++;
23
24
  if(count_sek == 10)
25
  {
26
    msekunden++;
27
    count_sek = 0;
28
29
    if(msekunden == 1000)
30
    {
31
      sekunden++;
32
      msekunden = 0;
33
    }
34
  }
35
}
36
37
void init_time()
38
{
39
  TIMSK|=(1<<OCIE2);
40
  TCCR2 |= (1<<WGM21) | (1<<CS21);  
41
  OCR2 = F_CPU/8/10000;      
42
}
43
44
45
46
/* ADC initialisieren */
47
void ADC_Init(void) {
48
 
49
  uint16_t result;
50
 
51
52
  ADMUX = (1<<REFS1) | (1<<REFS0);      // interne Referenzspannung nutzen
53
54
  // Bit ADFR ("free running") in ADCSRA steht beim Einschalten
55
  // schon auf 0, also single conversion
56
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
57
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
58
 
59
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
60
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
61
 
62
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
63
 
64
  while (ADCSRA & (1<<ADSC) ) {}        // auf Abschluss der Konvertierung warten
65
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
66
     Wandlung nicht übernommen. */
67
  result = ADCW;
68
}
69
 
70
/* ADC Einzelmessung */
71
uint16_t ADC_Read( uint8_t channel )
72
{
73
  // Kanal waehlen, ohne andere Bits zu beeinflußen
74
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
75
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
76
  while (ADCSRA & (1<<ADSC) ) {}  // auf Abschluss der Konvertierung warten
77
  return ADCW;                    // ADC auslesen und zurückgeben
78
}
79
 
80
/* ADC Mehrfachmessung mit Mittelwertbbildung */
81
uint16_t ADC_Read_Avg( uint8_t channel, uint8_t average )
82
{
83
  uint32_t result = 0;
84
 
85
  for (uint8_t i = 0; i < average; ++i )
86
    result += ADC_Read( channel );
87
 
88
  return (uint16_t)( result / average );
89
}
90
91
void setup_uart()
92
{
93
  UBRRH = (char) (UART_SETTING >> 8);
94
  UBRRL = (char) (UART_SETTING);
95
  UCSRB = (1<<RXEN) | (1<<TXEN);
96
97
  UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
98
}
99
100
void uart_putchar(char c)
101
{
102
  // Warten bis Buffer bereit ...
103
  while (!(UCSRA & (1 << UDRE)))
104
    ;
105
106
  // Senden...
107
  UDR = c;
108
}
109
110
void uart_putstring(char *str)
111
{
112
  unsigned char i;
113
114
  for (i=0;i<255;i++) 
115
  {
116
    if (str[i] != 0)
117
      uart_putchar(str[i]);
118
    else
119
      break; // Ende des Strings erreicht
120
  }
121
}
122
123
124
125
char uart_getchar()
126
{
127
  // Ist schon ein Zeichen im Buffer?
128
  if (bit_is_set(UCSRA, RXC))
129
    return UDR;
130
  else 
131
    return -1;
132
}
133
134
void uart_readline(char *str)
135
{
136
  char c;
137
  unsigned char index;
138
  
139
  index = 0;
140
141
  while (1)
142
  {
143
    c = uart_getchar();
144
    if (c != -1)
145
    {
146
    
147
148
149
      if (c == 13) 
150
      {
151
        str[index] = 0;
152
153
        return;
154
      }
155
      else 
156
      {
157
158
    
159
        str[index] = c;
160
        index++;
161
      }
162
    }
163
  }
164
}
165
166
167
168
 
169
int main()
170
{
171
172
  uint16_t adcval;
173
174
  int last_sek;
175
 
176
  char Buffer[25];
177
 
178
179
  ADC_Init();
180
181
  DDRB=0xff;
182
  PORTB=0x00;
183
184
  sei();                                // Interrupts global an
185
 
186
  last_sek = 0;
187
  sekunden = 0;
188
  msekunden = 0;
189
190
191
  init_time();
192
  setup_uart();
193
194
  uart_putstring("Setup UART: check\r\n");
195
  uart_putstring("Setup ADC: ");
196
 
197
  _delay_ms(1000);
198
  
199
  uart_putstring("check\r\n");
200
201
202
  while( 1 ) 
203
  {
204
205
    if(sekunden>last_sek)
206
    {
207
  last_sek = sekunden;
208
    adcval = ADC_Read_Avg(0,5); 
209
210
211
 
212
    sprintf( Buffer, "Wert: %d", adcval );
213
214
  uart_putstring(Buffer);
215
  }
216
 
217
  }
218
}

von Hubert G. (hubertg)


Lesenswert?

AGND gehört direkt mit Masse verbunden, am besten bei einem Knotenpunkt

von Hans B. (hans_b92)


Lesenswert?

Ich danke verbindlichst und freue mich an den Messwerten zwischen 0 und 
1023 :) Grüße

von Krapao (Gast)


Lesenswert?

> AVCC über Kondensator an Masse

Aber hoffentlich auch an Vcc?


AVcc o------+------o Vcc
            |
           --- C
           --- 100 nF
            |
AGND o------+------o GND
            |
           --- C
           --- 100 nF
            |
AREF o------+

von Krapao (Gast)


Lesenswert?

> aus dem Tutorial (ARef über Kondensator an Masse, AGND über Kondensator
> an Masse, AVCC über Kondensator an Masse und 47 Ohm Widerstand an VCC)

Hast du da einen Link parat?

von Hans B. (hans_b92)


Lesenswert?

http://www.mikrocontroller.net/articles/AVR-Tutorial:_ADC#Interne_Referenzspannung

So wie hier an der rechten Seite - der ursprüngliche Fehler wurde dabei 
übersehen. Muss ich daran noch etwas ändern? Ich geh über den Widerstand 
von AVCC auf VCC (gem. des nebenstehenden Textes kann die Spule durch 
einen Widerstand ersetzt werden)

von Hans B. (hans_b92)


Lesenswert?

Ach, und wenn ich schon am Fragen bin:

Kann ich ADC0 auch im single ended inupt mit dem 10 x gain nutzen? Die 
Table 84 des Datenblatts verstehe ich anders. Da mein INA333 aber leider 
nur ne 1000fache Verstärkung liefert, würde ich gern noch den gain 
dazuschalten.

von Karl H. (kbuchegg)


Lesenswert?

Hans B. schrieb:
> Ach, und wenn ich schon am Fragen bin:
>
> Kann ich ADC0 auch im single ended inupt mit dem 10 x gain nutzen? Die
> Table 84 des Datenblatts verstehe ich anders.

Du vesrstehst die Tabelle richtig. Singel Ended gibt es keinen Gain.

> Da mein INA333 aber leider
> nur ne 1000fache Verstärkung liefert, würde ich gern noch den gain
> dazuschalten.

Du kannst ja auch deine eigene Referenzspannung zur Messung hernehmen, 
die dann eben nur 1/10 der bereitgestellten ausmacht. Das müssten dann 
allerdings 0.25 Volt sein. Und die reicht dir nicht, obowhl du dein 
Signal schon um das 1000-fache verstärkt hast? Was misst du da?

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.