Forum: Mikrocontroller und Digitale Elektronik AREF intern nutzen (umschalten) bei ADC


von Jens (Gast)


Lesenswert?

Hallo,

bisher hatte ich immer AREF pin mit AVCC verbunden, Kondensator an Masse 
und Drossel an VCC.

Alles war wunderbar.

Nun möchte ich aber zwischendurch mal die interne Ref. von 1,1V nutzen, 
um die Batteriespannung zu prüfen.

Also habe ich AREF abgetrennt von AVCC, den Kondensator aber gelassen

Vorher möchte ich aber wie bisher "wandeln"

1. Test also: Intern: AVCC mit AREF verbinden durch setzen von REFS0 in 
ADMUX.

Aber keine vernünftige Wandlung kommt zustande
-- warum?


REFS1   REFS0   Voltage Reference Selection

0   0   AREF, Internal Vref turned off
0   1   AVCC with external capacitor at AREF pin
1   0   Reserved
1   1   Internal 1.1V Voltage Reference with external
                   capacitor   at AREF pin

Danke für Hilfe ...

bin erst nachmittags wieder da und kann dann reagieren

von Andreas K. (a-k)


Lesenswert?

Jens wrote:

> Aber keine vernünftige Wandlung kommt zustande
> -- warum?

Lange genug gewartet? Wenn du die Referenz umschaltest muss der 
Kondensator umgeladen werden.

von Jens (Gast)


Lesenswert?

Ja, habe ich ...

selbst wenn ich das gleich von Anfang an mache, also so starte - geht es 
nicht ...

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

>bisher hatte ich immer AREF pin mit AVCC verbunden, Kondensator an Masse
>und Drossel an VCC.
???
Also generell kommt an AREF ein Kondesator und ans andere Beinchen des 
Kondesators kommt GND!
Dann sollte es auch mit der Internen referenz klappen...

von Lowtzow .. (lowtzow)


Lesenswert?

Andreas Kaiser wrote:
> Jens wrote:
>
>> Aber keine vernünftige Wandlung kommt zustande
>> -- warum?
>
> Lange genug gewartet? Wenn du die Referenz umschaltest muss der
> Kondensator umgeladen werden.


hallo

wie lang muss man warten um umzuschalten? habe ein ähnliches problem.

mega8
1. vcc als referenz
wenn die spannung kleiner als 2,56V ist soll er auf die interne 
umschalten

2. int 2.56 als referenz


beides einzeln funktioniert, jedoch hintereinader funktionierts nicht 
(s.o.)
wille jedoch recht schnelle werte haben und nicht sekunden warten.
der code funktioniert, jedoch halt leider ungenau

hat wer einen tipp??

1
uint16_t wert = readADC(0);  //adc0 wird ausgelesen
2
    wert2=wert;          //der int wert aus dem adc wird übergeben
3
    wert2=wert2*5/1024;      //der adc wert wird in aus 0-1024 in 0-5V umgerechnet
4
5
    
6
    if(wert2>=2.56)
7
    {
8
9
    lcd_gotoxy(0,0);      
10
         char text[77];        //wird für die übergabe für sprintf benötigt
11
    sprintf(text,"ADC0=%2.3fV  %02d", wert2,hilfs); //ausgabe adc0 und akt.intervall via sprintf
12
    lcd_puts(text);        //text aus sprintf wird auf dem lcd ausgegeben
13
    }
14
    else
15
    {
16
    wert3 = readADC256(0);
17
    wert3=wert3;          //der int wert aus dem adc wird übergeben
18
    wert3=wert3*2.56/1024;
19
    lcd_gotoxy(0,0);      
20
         char text[77];        //wird für die übergabe für sprintf benötigt
21
    sprintf(text,"ADC0=%2.3fV  %02d", wert3,hilfs); //ausgabe adc0 und akt.intervall via sprintf
22
    lcd_puts(text);
23
    }

von Oliver (Gast)


Lesenswert?

>wie lang muss man warten um umzuschalten?

In einigen Datenblättern steht dazu:

"The first ADC conversion result after switching reference voltage 
source
may be inaccurate, and the user is advised to discard this result."

Versuchs mal mit einem dummy-Read.

Oliver

von Johannes M. (johnny-m)


Lesenswert?

Alex Alex wrote:
> der code funktioniert, jedoch halt leider ungenau
> [...]
>     wert2=wert2*5/1024;      //der adc wert wird in aus 0-1024 in 0-5V
Was für einen Datentyp hat wert2?

Wie wäre es mal mit Code, der alles zeigt, was relevant ist?

Und "schnell" und Gleitkommaoperationen auf einem AVR beißen sich 
ebenfalls... Festkommaarithmetik ist da meist sinnvoller.

von Lowtzow .. (lowtzow)


Lesenswert?

wert2 und wert 3 sind natürlich double!
danke, jedoch ein dummyread verwende ich schon!

vielleicht mehr dummyreads hintereinander?!



achja hab noch ein problem, wenn ich schon den code poste vielleicht 
kann mir auch da wer helfen.
und zwar die erste zeile in meiner endlosschleife nach for
lcd_gotoxy(0,0);  wenn ich diesen befehl weg nehme und ihn meine 
schleife reinpack (die alle ca85µs durchlaufen wird) dann wird am lcd 
nichts angezeigt.

danke & mfg
1
/*************************************************************************
2
Title:    Augabe von ADC0 an das LCD (pfleury_lcd LCD library)
3
      Anzeige "akku wird geladen"/ "akku voll"
4
      Display wird mittels Timer0 aktualisiert
5
      LCD an PD1-PD7
6
Author:   
7
File:     
8
Software: AVR-GCC 4.14
9
Hardware: HD44780 compatible LCD text display
10
          Poti
11
         
12
**************************************************************************/
13
#include <stdlib.h>
14
#include <avr/io.h>
15
//#include <avr/pgmspace.h>
16
#include "lcd.h"
17
#include <avr/signal.h> 
18
19
20
uint8_t sek=0;            //sek werden mit 0 initialisiert
21
uint8_t hilfs=0;          //hilfswert mit dem das lcd aktualisiert wird
22
double wert2;            //wird für kommaausgabe benötigt
23
double wert3;
24
  
25
//char buffer[10];
26
void timerconfig();          //prototyp: der timer0 wird konfiguriert s.u.
27
uint16_t readADC(uint8_t channel);  //Prototyp: adc wird konfiguriert und ausgelsen
28
uint16_t readADC256(uint8_t channel);
29
30
int main(void)            //hauptprogramm
31
{
32
33
  timerconfig();          //timer config aufruf für lcd aktualisierung 
34
    lcd_init(LCD_DISP_ON);      // initialize display, cursor off
35
      
36
    for (;;) {             //endlosschleife
37
38
      lcd_gotoxy(0,0);      //zu anfangskoordinaten des lcd springen
39
  
40
        
41
  if(sek!=hilfs)  {          //abfrage wird alle 0,1sek abgefragt
42
      
43
    
44
    lcd_clrscr();        //lcd wird gelöscht
45
    
46
    uint16_t wert = readADC(0);  //adc0 wird ausgelesen
47
    wert2=wert;          //der int wert aus dem adc wird übergeben
48
    wert2=wert2*5/1024;      //der adc wert wird in aus 0-1024 in 0-5V umgerechnet
49
50
    
51
    if(wert2>=2.56)
52
    {
53
54
    lcd_gotoxy(0,0);      
55
         char text[77];        //wird für die übergabe für sprintf benötigt
56
    sprintf(text,"ADC0=%2.3fV  %02d", wert2,hilfs); //ausgabe adc0 und akt.intervall via sprintf
57
    lcd_puts(text);        //text aus sprintf wird auf dem lcd ausgegeben
58
    }
59
    else
60
    {
61
    wert3 = readADC256(0);
62
    wert3=wert3;          //der int wert aus dem adc wird übergeben
63
    wert3=wert3*2.56/1024;
64
    lcd_gotoxy(0,0);      
65
         char text[77];        //wird für die übergabe für sprintf benötigt
66
    sprintf(text,"ADC0=%2.3fV  %02d", wert3,hilfs); //ausgabe adc0 und akt.intervall via sprintf
67
    lcd_puts(text);
68
    }
69
70
    /*if (wert2<4.3)             //hier wird die akkuspannung verglichen, Schwellwert kann hier eingestellt werden ab 4,3v wird akku voll angezeigt
71
    {   lcd_gotoxy(1,1);
72
      wert2=readADC(1);
73
      wert2=wert2*5/1024;
74
      sprintf(text,"ladevorgang");
75
      lcd_puts(text);
76
    }
77
    else{
78
      lcd_gotoxy(1,1);
79
      wert2=readADC(1);
80
      wert2=wert2*5/1024;
81
      sprintf(text,"akku voll");
82
      lcd_puts(text);
83
      }*/
84
85
      hilfs=sek;            //wird gleichgesetzt damit die abfrage erst wieder in 85µs abgefragt wird                         
86
          }        //if schleife ende
87
          }          //endlosschleife ende
88
}                   //main ende
89
90
91
92
93
void timerconfig()  {        //  timer config für 85µsek
94
  
95
  TIMSK |= (1<<TOIE0);      //Timer 0 Timer/Counter0 Overflow Interrupt Enable
96
  
97
  TCCR0 |= (1<<CS00) | (1<<CS02);  //256Teiler  
98
     sei ();              //
99
          }
100
101
102
103
104
105
uint16_t readADC(uint8_t channel) {
106
  uint8_t i;
107
  uint16_t result = 0;
108
    
109
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1)| (1<<ADPS0); //der adc wird aktiviert und auf 128 teilungsfaktor
110
  ADMUX = channel;        // Kanal des Multiplexers waehlen
111
  ADMUX |=  (1<<REFS0);      // AVCC als Referenzspannung & hier braucht man volle 12bit! also adlar weg
112
    
113
  ADCSRA |= (1<<ADSC);      // Den ADC initialisieren und einen sog. Dummyreadout machen
114
  while(ADCSRA & (1<<ADSC));    // Jetzt 3x die analoge Spannung and Kanal channel auslesen
115
    
116
  for(i=0; i<3; i++) {       // und dann Durchschnittswert ausrechnen.
117
    
118
    ADCSRA |= (1<<ADSC);    // Eine Wandlung
119
    while(ADCSRA & (1<<ADSC));  // Auf Ergebnis warten...
120
    result += ADCW;        // wird zu result addiert
121
            }
122
  
123
  ADCSRA &= ~(1<<ADEN);      // ADC wieder deaktivieren
124
  result /= 3;          // result /3 um zu richtigen wert zu gelangen
125
  
126
  return result;          // wird zurückggegeben
127
                  }
128
129
130
uint16_t readADC256(uint8_t channel) {
131
  uint8_t i;
132
  uint16_t result = 0;
133
    
134
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1)| (1<<ADPS0); //der adc wird aktiviert und auf 128 teilungsfaktor
135
  ADMUX = channel;        // Kanal des Multiplexers waehlen
136
  ADMUX |=  (1<<REFS0)|(1<<REFS1);// 2,56 als referenz & hier braucht man volle 12bit! also adlar weg
137
    
138
  ADCSRA |= (1<<ADSC);      // Den ADC initialisieren und einen sog. Dummyreadout machen
139
  while(ADCSRA & (1<<ADSC));    // Jetzt 3x die analoge Spannung and Kanal channel auslesen
140
    
141
  for(i=0; i<3; i++) {       // und dann Durchschnittswert ausrechnen.
142
    
143
    ADCSRA |= (1<<ADSC);    // Eine Wandlung
144
    while(ADCSRA & (1<<ADSC));  // Auf Ergebnis warten...
145
    result += ADCW;        // wird zu result addiert
146
            }
147
  
148
  ADCSRA &= ~(1<<ADEN);      // ADC wieder deaktivieren
149
  result /= 3;          // result /3 um zu richtigen wert zu gelangen
150
  
151
  return result;          // wird zurückggegeben
152
                  }
153
154
155
156
157
ISR(TIMER0_OVF_vect)  {  
158
    sek++;            //"pseudo"sek (85µsek) wird erhöht
159
            }

von Johannes M. (johnny-m)


Lesenswert?

Alex Alex wrote:
> wert2 und wert 3 sind natürlich double!
Der AVR-GCC kann keine echten (64-Bit) doubles. Die werden wie floats 
behandelt. Abgesehen davon ist das, was Du da machst, ein klassischer 
Fall für Festkommaarithmetik. GLeitommaoperationen sind hier absolut 
überflüssig und führen nur zu Problemen.

Außerdem machst Du eine Mittelwertbildung über drei Werte, was auch 
unsinnig ist, weil die Rückrechnung eine echte Division erfordert. Nimm 
eine Zweierpotenz, also z.B. 4 Messwerte.

>   if(sek!=hilfs)  {          //abfrage wird alle 0,1sek abgefragt
Variablen, die in Interrupt Handlern und im Hauptprogramm verwendet 
werden, müssen volatile deklariert sein, sonst sind sie gefundenes 
Fressen für den Optimizer. Und sek ist hier nicht volatile!

Übrigens hat Dein Problem nicht wirklich viel mit dem ursprünglichen 
Thema des Threads zu tun. Es war absolut unsinnig, einen so alten Thread 
dafür wieder rauszukramen!

von Lowtzow .. (lowtzow)


Lesenswert?

danke für die tipps, werde ich mir am wochenende genauer anschauen.


aber, kann ich die gleitkomma dann auch so angenehm über einen string 
ausgeben, habe da schon im vorfeld probleme mit dem komma geortet und 
war dann froh über die jetzige lösung.
aja zum makefile ist auch eine lib dazugefügt damit überhapt die komma 
gehen, habe ich auch in diesem forum gefunden und auch desahlb gedacht, 
dass es so ok ist

jedoch hat das programm wie ich schon gesagt hatte funktioniert, wenn 
ich nur mit 2,56ref oder gvcc adc gemessen habe!

die große meßunignauigkeit hatte ich nur bei der kombination aus beiden 
adc referenzen, wenn ich sie hintereiander abfarge, so wie im programm 
oben gepostet.


da ist mir noch eine frage eingefallen zu dem
if(sek!=hilfs)
macht man das so oder gibt es eine bessere lösung?
 wollte auch nicht mein ganzes programm in die isr schreiben.


danke &mfg
alex

von Jörn P. (jonnyp)


Lesenswert?

Abgesehen von eventuellen Softwarefehlern sei mal wieder darauf 
hingewiesen, das an AREF nichts außer einem Kondensator angeschlossen 
wird. Es sei denn, es wird eine andere als die internen 
Referenzspannungen verwendet. Betrachtet man z.B. beim atmega8 /644 das 
Blockschaltbild des ADC, so erkennt man das AREF direkt mit dem Eingang 
des ADC verbunden ist. Bei Verwendung der intern wählbaren Quellen ist 
daher AREF als (hochohmiger) Ausgang zu betrachten.

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.