mikrocontroller.net

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


Autor: Jens (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jens wrote:

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

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

Autor: Jens (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, habe ich ...

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

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Lowtzow .... (lowtzow)
Datum:

Bewertung
0 lesenswert
nicht 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??

uint16_t wert = readADC(0);  //adc0 wird ausgelesen
    wert2=wert;          //der int wert aus dem adc wird übergeben
    wert2=wert2*5/1024;      //der adc wert wird in aus 0-1024 in 0-5V umgerechnet

    
    if(wert2>=2.56)
    {

    lcd_gotoxy(0,0);      
         char text[77];        //wird für die übergabe für sprintf benötigt
    sprintf(text,"ADC0=%2.3fV  %02d", wert2,hilfs); //ausgabe adc0 und akt.intervall via sprintf
    lcd_puts(text);        //text aus sprintf wird auf dem lcd ausgegeben
    }
    else
    {
    wert3 = readADC256(0);
    wert3=wert3;          //der int wert aus dem adc wird übergeben
    wert3=wert3*2.56/1024;
    lcd_gotoxy(0,0);      
         char text[77];        //wird für die übergabe für sprintf benötigt
    sprintf(text,"ADC0=%2.3fV  %02d", wert3,hilfs); //ausgabe adc0 und akt.intervall via sprintf
    lcd_puts(text);
    }

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Lowtzow .... (lowtzow)
Datum:

Bewertung
0 lesenswert
nicht 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
/*************************************************************************
Title:    Augabe von ADC0 an das LCD (pfleury_lcd LCD library)
      Anzeige "akku wird geladen"/ "akku voll"
      Display wird mittels Timer0 aktualisiert
      LCD an PD1-PD7
Author:   
File:     
Software: AVR-GCC 4.14
Hardware: HD44780 compatible LCD text display
          Poti
         
**************************************************************************/
#include <stdlib.h>
#include <avr/io.h>
//#include <avr/pgmspace.h>
#include "lcd.h"
#include <avr/signal.h> 


uint8_t sek=0;            //sek werden mit 0 initialisiert
uint8_t hilfs=0;          //hilfswert mit dem das lcd aktualisiert wird
double wert2;            //wird für kommaausgabe benötigt
double wert3;
  
//char buffer[10];
void timerconfig();          //prototyp: der timer0 wird konfiguriert s.u.
uint16_t readADC(uint8_t channel);  //Prototyp: adc wird konfiguriert und ausgelsen
uint16_t readADC256(uint8_t channel);

int main(void)            //hauptprogramm
{

  timerconfig();          //timer config aufruf für lcd aktualisierung 
    lcd_init(LCD_DISP_ON);      // initialize display, cursor off
      
    for (;;) {             //endlosschleife

      lcd_gotoxy(0,0);      //zu anfangskoordinaten des lcd springen
  
        
  if(sek!=hilfs)  {          //abfrage wird alle 0,1sek abgefragt
      
    
    lcd_clrscr();        //lcd wird gelöscht
    
    uint16_t wert = readADC(0);  //adc0 wird ausgelesen
    wert2=wert;          //der int wert aus dem adc wird übergeben
    wert2=wert2*5/1024;      //der adc wert wird in aus 0-1024 in 0-5V umgerechnet

    
    if(wert2>=2.56)
    {

    lcd_gotoxy(0,0);      
         char text[77];        //wird für die übergabe für sprintf benötigt
    sprintf(text,"ADC0=%2.3fV  %02d", wert2,hilfs); //ausgabe adc0 und akt.intervall via sprintf
    lcd_puts(text);        //text aus sprintf wird auf dem lcd ausgegeben
    }
    else
    {
    wert3 = readADC256(0);
    wert3=wert3;          //der int wert aus dem adc wird übergeben
    wert3=wert3*2.56/1024;
    lcd_gotoxy(0,0);      
         char text[77];        //wird für die übergabe für sprintf benötigt
    sprintf(text,"ADC0=%2.3fV  %02d", wert3,hilfs); //ausgabe adc0 und akt.intervall via sprintf
    lcd_puts(text);
    }

    /*if (wert2<4.3)             //hier wird die akkuspannung verglichen, Schwellwert kann hier eingestellt werden ab 4,3v wird akku voll angezeigt
    {   lcd_gotoxy(1,1);
      wert2=readADC(1);
      wert2=wert2*5/1024;
      sprintf(text,"ladevorgang");
      lcd_puts(text);
    }
    else{
      lcd_gotoxy(1,1);
      wert2=readADC(1);
      wert2=wert2*5/1024;
      sprintf(text,"akku voll");
      lcd_puts(text);
      }*/

      hilfs=sek;            //wird gleichgesetzt damit die abfrage erst wieder in 85µs abgefragt wird                         
          }        //if schleife ende
          }          //endlosschleife ende
}                   //main ende




void timerconfig()  {        //  timer config für 85µsek
  
  TIMSK |= (1<<TOIE0);      //Timer 0 Timer/Counter0 Overflow Interrupt Enable
  
  TCCR0 |= (1<<CS00) | (1<<CS02);  //256Teiler  
     sei ();              //
          }





uint16_t readADC(uint8_t channel) {
  uint8_t i;
  uint16_t result = 0;
    
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1)| (1<<ADPS0); //der adc wird aktiviert und auf 128 teilungsfaktor
  ADMUX = channel;        // Kanal des Multiplexers waehlen
  ADMUX |=  (1<<REFS0);      // AVCC als Referenzspannung & hier braucht man volle 12bit! also adlar weg
    
  ADCSRA |= (1<<ADSC);      // Den ADC initialisieren und einen sog. Dummyreadout machen
  while(ADCSRA & (1<<ADSC));    // Jetzt 3x die analoge Spannung and Kanal channel auslesen
    
  for(i=0; i<3; i++) {       // und dann Durchschnittswert ausrechnen.
    
    ADCSRA |= (1<<ADSC);    // Eine Wandlung
    while(ADCSRA & (1<<ADSC));  // Auf Ergebnis warten...
    result += ADCW;        // wird zu result addiert
            }
  
  ADCSRA &= ~(1<<ADEN);      // ADC wieder deaktivieren
  result /= 3;          // result /3 um zu richtigen wert zu gelangen
  
  return result;          // wird zurückggegeben
                  }


uint16_t readADC256(uint8_t channel) {
  uint8_t i;
  uint16_t result = 0;
    
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1)| (1<<ADPS0); //der adc wird aktiviert und auf 128 teilungsfaktor
  ADMUX = channel;        // Kanal des Multiplexers waehlen
  ADMUX |=  (1<<REFS0)|(1<<REFS1);// 2,56 als referenz & hier braucht man volle 12bit! also adlar weg
    
  ADCSRA |= (1<<ADSC);      // Den ADC initialisieren und einen sog. Dummyreadout machen
  while(ADCSRA & (1<<ADSC));    // Jetzt 3x die analoge Spannung and Kanal channel auslesen
    
  for(i=0; i<3; i++) {       // und dann Durchschnittswert ausrechnen.
    
    ADCSRA |= (1<<ADSC);    // Eine Wandlung
    while(ADCSRA & (1<<ADSC));  // Auf Ergebnis warten...
    result += ADCW;        // wird zu result addiert
            }
  
  ADCSRA &= ~(1<<ADEN);      // ADC wieder deaktivieren
  result /= 3;          // result /3 um zu richtigen wert zu gelangen
  
  return result;          // wird zurückggegeben
                  }




ISR(TIMER0_OVF_vect)  {  
    sek++;            //"pseudo"sek (85µsek) wird erhöht
            }


Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Lowtzow .... (lowtzow)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörn Paschedag (jonnyp)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.