ADC seltsames Verhalten (ATmega)

Ich baue ein Hobby-Oszilloskop auf ATmega16. Ich teste den ADC, indem ich eine Rechteckwelle bei 2 kHz mit kleiner Amplitude erzeuge und sie über einen kapazitiven Eingang mit einem Spannungsteiler an den ADC-Pin anlege, um den Nullpegel zu verschieben.

schematisch

So sieht das Signal nach der Abtastung durch ADC aus:schematisch

Es sieht gut aus, aber nachdem ich anfange, den Nullpegel durch Einstellen des Potentiometers zu verschieben, bekomme ich diese seltsamen Spitzen:schematisch

Nachdem ich den Pegel etwas höher verschoben habe, sieht es wieder gut aus:schematisch

Und dann wiederholt sich das Muster:schematisch schematisch schematisch

Insgesamt erhalte ich 3 Bereiche, in denen die Spitzen erscheinen.

Einige Informationen

  • AVR läuft mit 16MHz
  • ADC verwendet eine interne 2,56-Referenzspannung
  • ADC ist im Freilaufmodus bei 125 kHz (Prescaler=128)
  • Ich übertrage Daten über CP210 auf ein Android-Tablet, das für Echtzeit-Plotten verwendet wird. Die Schaltung wird auch vom Tablet mit Strom versorgt. Ich erhalte die gleichen Ergebnisse, wenn die Schaltung an den PC angeschlossen ist.
  • Die USART-Baudrate beträgt 500000 b/s (UBRR=1)
  • AVcc und AREF sind nicht verbunden. Ich habe auch versucht, AVcc mit Vcc zu verbinden und eine 0,1-uF-Kappe zwischen Gnd und AVcc hinzuzufügen, aber dies hatte keine Wirkung.

Noch ein paar Infos

  • dieses Rauschen kommt nicht vom Generator (getestet mit analogem Oszilloskop)
  • Dieses Geräusch kommt nicht vom Potentiometer
  • LFUSE = 0xFF, HFUSE = 0x89.

ADC-Initialisierungsroutine

ADMUX = (1 << REFS0); // AVCC with external capacitor at AREF pin
ADCSRA = (1 << ADEN)
        | (1 << ADIE)
        | (1 << ADATE) 
        | (1 << ADPS0)
        | (1 << ADPS1)
        | (1 << ADPS2); // Division factor = 128
MCUCR |= 1 << SM0;
MCUCR |= 1 << SE; // Sleep-mode enabled
ADCSRA |= (1 << ADSC);

ADC-Datenübertragungsroutine

volatile uint8_t adcLow;
volatile uint8_t adcHigh;

int main(void) {
    ....
    while (1) {
        if (ADCSRA != 0x00) {
            USARTSendByte(adcLow);
            USARTSendByte(adcHigh);
        }
    }
}

ISR(ADC_vect) {
    adcLow = ADCL;
    adcHigh = ADCH;
}
Hast du es mal mit einem anderen Topf versucht?
Ja, habe ich. Der Topf verursacht das Problem nicht.
Handelt es sich um einen einzelnen Datenpunkt in Ihren Daten oder gibt es mehrere Datenpunkte, die diese Spitze ausmachen? Oder anders gefragt: Ist es nur eine einzige Messung, die den Spike verursacht? Außerdem: Tritt das auch auf, wenn Sie mit niedrigerer Geschwindigkeit sampeln?
Wenn Sie avr-gcc verwenden, können Sie die folgende Verknüpfung verwenden:uint16_t adcValue = ADC;
Ich habe gerade keinen Generator, also muss ich das morgen testen. Ein Sampling mit niedrigerer Geschwindigkeit ist nicht möglich, da der Prescaler 128 ist (was der höchstmögliche Wert ist). Ich habe jedoch versucht, eine langsamere usart-Datenrate zu verwenden, aber es hat nicht geholfen.
@jippie danke für den Tipp, aber ich habe die ADC-Ergebnisse absichtlich aufgeteilt, da ich jeweils nur ein Byte über usart senden kann.
Ich denke, es ist besser, ein eigenes Flag in der ISR zu setzen, als von ADCSRA abhängig zu sein. Ich denke, Sie haben eine Run-Bedingung mit ADSC und ADIF. Oder testen Sie ein bestimmtes Bit im Register.

Antworten (1)

Die Spitzen schneiden eindeutig auf ganz bestimmte Werte ab (wahrscheinlich eine Zweierpotenz) oder Sie verwenden vorzeichenbehaftete Ganzzahlen, die zu klein sind, um den gesamten Wert zu enthalten.

Sie haben keinen vollständigen Quellcode angegeben, also vermute ich hier. Sie versuchen wahrscheinlich, den gemessenen Wert in eine zu kleine ganze Zahl einzupassen. Machen Sie einen Speicherauszug aus den Werten, die Sie erhalten, und finden Sie die Spitzen darin. Sehen Sie sich dann die binäre Darstellung dieser Zahlen an und sehen Sie, ob Sie Gemeinsamkeiten finden können.

Bei schneller Schätzung beträgt der Abstand zwischen zwei Spitzen etwa 1,28 V, etwas zu zufällig nahe an der Größe einer vorzeichenbehafteten 8-Bit-Ganzzahl.

Ich empfehle, Typdefinitionen wie int8_t[-128:127], uint8_t[0:255], int16_t[-32768:32767], uint16_t[0:65535], int32_t[-2147483648:2147483647] und uint32_t[0:4294967295] zu verwenden, was deutlich zeigt, wie groß ist die Variable.

Entschuldigung, ich habe meine Frage mit dem Quellcode aktualisiert. adcLowund adcHighsind vom uint8_tTyp, sodass die Größe ausreicht, um ADC-Werte zu speichern.
Also vom Type-Casting-Bug gebissen?
Dies könnte der Fall sein. Ich konvertiere empfangene Werte wie folgt: int value = (buffer[i + 1] << 8 | (buffer[i] & 0xFF))in Java.
Sie hatten Recht, dass diese Spitzen softwarebedingt sind. Ich habe gerade entdeckt, dass sie aufgrund von Übertragungsfehlern auftreten. Ich habe hier nochmal eine Frage gestellt
Warten Sie ... ist nicht uint8_t [0, 255] und int8_t [-128, 127] ? Hat das U nicht den Typ unsigned gemacht?
@geoh whoops, lass uns das korrigieren. Guter Fang.