Hallo Feno,
an VCC brauchst du natürlich auch Betriebsspannung. Egal, es geht und ich erkläre dir nun mal die Kalibrierung und Offsetberechnung.
Zuerst mal zur Kalibrierung:
Die beiden ADC Module des Mikrocontrollers sind von Werk aus kalibriert, hierfür sind im NonVolatileMemory (NVM) Kalibrierungswerte hinterlegt. Diese muss man in seinem Programm selber in die Kalibrierungsregister CALL und CALH kopieren. Das geht folgendermaßen:
Code:
// Folgendes einbinden
#include <stddef.h>
#include "avr_compiler.h"
#include <avr/pgmspace.h>
Code:
// Kalibrierungsbytes lesen und in CAL Register kopieren
NVM_CMD = NVM_CMD_READ_CALIB_ROW_gc;
ADCA.CALL = pgm_read_byte(offsetof(NVM_PROD_SIGNATURES_t, ADCACAL0));
ADCA.CALH = pgm_read_byte(offsetof(NVM_PROD_SIGNATURES_t, ADCACAL1));
NVM_CMD = NVM_CMD_NO_OPERATION_gc;
Jetzt haben wir die Kalibrierungsbytes in die CAL Register des ADCA kopiert.
Nun folgt die Offsetermittlung:
Der Xmega ist sehr flexibel bezüglich der Kanalwahl. Im Prinzip funktioniert die Offsetermittlung so: Du nimmst dir einen Channel, hier zum Beispiel CH1, stellst diesen auf Differentialmessung ein, die Verstärkung auf x1. Bei der Differentialmessung hast du ja normalerweise einen positiven und einen negativen Pin, du wählst hier den gleichen Pin aus, im Beispiel PIN1. Danach stellst du Prescaler, Referenz ein und aktivierst das ADCA Modul. Danach einen Moment warten, sonst sind die ersten Messungen schlecht.
Im Beispiel mache ich 8 Single Conversions, summiere das Ergebnis, teile danach durch 8, habe also einen Mittelwert, der ist int (int16_t). ADCA_Offset habe ich mal global definiert.
Im Idealfall sollte für den Offset 0 herauskommen, das wird aber nicht der Fall sein. Den ADCA deaktiviere ich nach der Offsetermittlung wieder.
Wenn du nun Messungen machst musst du ADCA_Offset von deinem Ergebnis abziehen, der Offset gilt für das ganze ADCA Modul, es ist also egal welche Pins du welchen Channeln zuordnest.
Mal eine Frage, ist es ein Projekt für eine Abschlußarbeit, Diplomarbeit o.ä., weil du unter Zeitdruckt bist?
Hier nochmal alles zusammen (Alle Angaben natürlich wie immer ohne Gewähr
):
Ich hoffe ich konnte dir weiterhelfen.
Grüße,
Dirk
Code:
void ADC_Init(void)
{
uint8_t i;
int16_t offset;
// Kalibrierungsbytes lesen
NVM_CMD = NVM_CMD_READ_CALIB_ROW_gc;
ADCA.CALL = pgm_read_byte(offsetof(NVM_PROD_SIGNATURES_t, ADCACAL0));
ADCA.CALH = pgm_read_byte(offsetof(NVM_PROD_SIGNATURES_t, ADCACAL1));
NVM_CMD = NVM_CMD_NO_OPERATION_gc;
// Offset von dem ADCA Module ermitteln
ADCA.CH1.CTRL = ADC_CH_INPUTMODE_DIFF_gc | ADC_CH_GAIN_1X_gc;
ADCA.CH1.MUXCTRL = ADC_CH_MUXPOS_PIN1_gc | ADC_CH_MUXNEG_PIN1_gc;
ADCA.PRESCALER = 0b010; // DIV16 -> 32MHz/16 = 2MHz
ADCA.REFCTRL = (ADCA.REFCTRL & ~(ADC_REFSEL_gm)) | ADC_REFSEL_VCC_gc;
ADCA.CTRLA = 0b00000001; // ENABLE=1
_delay_ms(10);
ADCA.CTRLA |= 0b00001000; // Dummy single conversion
while(!ADCA.CH1.INTFLAGS) { }; // warte auf virtual channel1 complete
ADCA.CH1.INTFLAGS |= 1;
offset = 0;
for (i=0; i<8; i++)
{
ADCA.CTRLA |= 0b00001000; // CHSTART1=1 single conversion
while(!ADCA.CH1.INTFLAGS) { }; // warte auf virtual channel1 complete
offset += ADCA.CH1RES;
ADCA.CH1.INTFLAGS |= 1;
}
ADCA_Offset = (int8_t)(offset >> 3);
ADCA.CTRLA = 0b00000000; // ENABLE=0
}