Forum: Mikrocontroller und Digitale Elektronik ADC XMega 8e5 automatische Korrektur CORREN


von Christoph M. (chrito)


Lesenswert?

Hallo Forum!

Mein Atxmega 8e5 macht munter ADC-Wandlungen mit folgenden 
Einstellungen:

- Verstärkung = 16-fach
- Referenz ist 1,0 Volt
- Messbereich von -0,059 Volt bis + 0,059 Volt
        (enstpricht -2048 bis +2047)

Überschreite ich den Messbereich, z.B. mit 0,1 Volt, dann ist das 
Ergebnis +2047 (RES=2047). Es ist sozusagen in "Sättigung".

Wenn ich jetzt die Kalibrierung einschalte (CORREN =1), ist alles 
schick, solange wie ich  nicht den Messbereich verlasse. Beim 
Überschreiten springt das Ergebnis jedoch in den negativen Bereich! 
Hätte erwartet, dass es ebenfalls bei 2047 hängen bleibt. Das ist für 
die meisten Anwendungen ungünstig.

Gibt's da irgendwie nen Trick, den Sprung ins negative zu vermeiden?

Unten meine Quellen, er kann zwischen 1-facher und 16-facher Verstärkung 
umschalten und jeweils kalibrieren (und das funktioniert einwandfrei).

Danke für Tipps!

VG
Christoph

1
void initialisiere_ADC(void)
2
{   setze_ADC_auf_Standardeinstellungen();
3
    kalibriere_ADCA();
4
}
5
6
void setze_ADC_auf_Standardeinstellungen(void)
7
{  ADCA.CTRLB = 0b00010010;   // Auflösung auf 12 Bit, signed Modus, selbstlaufend/freerun == Bit 3, Ergebnis hat mehr als 12Bit (Bit2:1, S.365)
8
  ADCA.REFCTRL = ADC_REFSEL_INT1V_gc | ADC_BANDGAP_bm | ADC_TEMPREF_bm;
9
  // Bandgap einschalten, Referenz auf interne 1-Volt-Quelle, Temperaturreferenzspannung einschalten
10
  ADCA.PRESCALER = ADC_PRESCALER_DIV512_gc;  // ADC maximal 2 Megasample pro Sek. => 32MHz /512 = 62 KHz
11
  ADCA.CTRLA = ADC_ENABLE_bm;          // ADC einschalten 0b00000001
12
  
13
  if (DIP_Schalter & 0b00010000)  // 16-fache Verstärkung mit Spgsteiler 1 : 1,6  => 10-fach Verstärkung
14
  {  ADCA.CH0.CTRL =   0b00010011; // Diff. Signal, Verstärkung = 16x, MUXNEG für Pinne 4,5,6,7 + GND
15
    ADCA.CH0.MUXCTRL= 0b00111010; }  // Bits6:3(MUXPOS) == ADC7(PA7) | Bits2:0(MUXNEG) == ADC6(PA6)
16
  else            // 1-fache Verstärkung
17
  {  ADCA.CH0.CTRL =   0b00000011; // Diff. Signal, Verstärkung = 1x, MUXNEG für Pinne 4,5,6,7 + GND
18
    ADCA.CH0.MUXCTRL= 0b01000010; }  // Bits6:3(MUXPOS) == ADC8(PD0) | Bits2:0(MUXNEG) == ADC6(PA6)
19
20
  //ADCA.CH0.AVGCTRL = 0b00100010; // Achfaches Akkumulieren und nach rechts schieben
21
                    // Kann die Bereichsgrenzen nicht als Max und Min darstellen, bricht in neg. Bereich ein
22
}
23
24
void kalibriere_ADCA(void)  // Nach Anleitung ATXMEGA E Handbuch Seite 357
25
{  int16_t Summe;
26
  uint32_t Summe2;
27
  uint16_t Verstaerkung;
28
29
  ADCA.CALL =  lese_Kalibrierungsbyte(offsetof(NVM_PROD_SIGNATURES_t, ADCACAL0));
30
  ADCA.CALH =  lese_Kalibrierungsbyte(offsetof(NVM_PROD_SIGNATURES_t, ADCACAL1));
31
  
32
  ADCA.CH0.CORRCTRL &= 0b11111110;          // Korrektur abschalten
33
  
34
  for (Wartezaehler=0;  Wartezaehler<10;);  // 10 mSek warten
35
  
36
  // MUXPOS und MUXNEG auf den selben Eingang legen (beide auf ADC6 = 1,65V):
37
  ADCA.CH0.CTRL =   0b00000011;      // Diff. Signal, Verstärkung = 1x, MUXNEG für Pinne 4,5,6,7 + GND
38
  if (DIP_Schalter & 0b00010000)      // 10-fache Verstärkung
39
  {  ADCA.CH0.CTRL =   0b00010011;    // Diff. Signal, Verstärkung = 16x, MUXNEG für Pinne 4,5,6,7 + GND
40
    ADCA.CH0.MUXCTRL= 0b00110010;  }  // Bits 6:3 (MUXPOS) == ADC6 (PA6) | Bits 2:0 (MUXNEG) == ADC6 (PA6)
41
  else                  // 1-fache Verstärkung
42
  {  ADCA.CH0.CTRL =   0b00000011;    // Diff. Signal, Verstärkung = 1x, MUXNEG für Pinne 4,5,6,7 + GND
43
    ADCA.CH0.MUXCTRL= 0b00110010;  }  // Bits 6:3 (MUXPOS) == ADC6 (PA6) | Bits 2:0 (MUXNEG) == ADC6 (PA6)
44
45
  while (miss_Spannung()!=1);
46
    
47
  Summe=0;  
48
  for (uint8_t i=0; i<32; i++)            // 32 Messwerte holen
49
  {
50
    while (miss_Spannung()!=1);
51
    Summe+=gemessene_Spannung;
52
  }
53
  
54
  if (Summe<0)
55
  {  Summe = -Summe;    // positiv machen
56
    Summe>>=5;      // Dividieren durch Bitschieben
57
    Summe = -Summe;    // wieder negativ machen
58
  }
59
  else  Summe>>=5;    // durch 32
60
  
61
  ADCA.CH0.OFFSETCORR0 = Summe & 0b11111111;      // untere 8 Bit speichern
62
  ADCA.CH0.OFFSETCORR1 = Summe >> 8;          // obere 12 Bit speichern
63
64
  if (DIP_Schalter & 0b00010000)            
65
      Verstaerkung = 2000;              // 10-fache Verstärkung
66
  else  Verstaerkung = 1978;              // 1-fache Verstärkung
67
  
68
  ADCA.CH0.GAINCORR0 = Verstaerkung & 0b11111111;
69
  ADCA.CH0.GAINCORR1 = Verstaerkung >> 8;
70
  
71
  ADCA.CH0.CORRCTRL |= 0b00000001;          // Korrektur einschalten
72
    
73
  // Zurücksetzen auf ADC8 und ADC6
74
  setze_ADC_auf_Standardeinstellungen();
75
}
76
77
78
// nicht blockierende ADC-Abfrage
79
// Ergebnis fertig: Rückgabe des Messwertes in "gemessene_Spannung"
80
// Ergebnis nicht fertig: Rückgabe von -1
81
// *** physik. Messwert - dig. Wert: ***
82
// ADC kann auf Differenzeingängen zwischen 0..3,3V (absolut) messen, wobei die Differenz (bei 1V Referenz) von -0,95V bis +0,95V sein darf.
83
// (nicht, wie aus Datenblatt S.77 annehmbar zwischen 0..1,0V absolut, sondern 0..3,3V absolut)
84
// -0,95V entspricht -2047
85
// +0,95V entspricht +2047 
86
uint8_t miss_Spannung(void)  // Struktur  "ADC_Wandlungen", die die Konvertierung verwaltet
87
{  ADC_CH_t *Kanal;  // AD-Wandler hat bei XMEGAs bis zu vier Kanäle
88
  static uint8_t Erststart=1;  // aller erster Aufruf startet den ADC ohne Bedingung
89
  
90
  Kanal= &(ADCA.CH0);             // Kanal 0 messen (hier der einzig vorhandene)
91
  
92
  if (Kanal->INTFLAGS & 0b00000001)      // Ergebnis vorhanden?
93
  {  gemessene_Spannung = Kanal->RES;
94
    Kanal->INTFLAGS=0b00000001;        // Flag "Konvertierung fertig" wieder löschen
95
    Kanal->CTRL |= ADC_CH_START_bm;      // Neue Konvertierung starten  
96
    return 1;  }  
97
  else 
98
  {  if (Erststart)              // Noch nie gestartet
99
    {  Erststart=0;
100
      Kanal->CTRL |= ADC_CH_START_bm; }  // Neue Konvertierung starten
101
    return -1;
102
  }
103
}

: 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.