SLEEP_MODE_ADC stört USART (und Piepton)

Auf einem AVR ATmega328P mache ich einmal pro Sekunde 3 AD-Konvertierungen unmittelbar nacheinander mit 16-fachem Oversampling mit SLEEP_MODE_ADC wie folgt:

EMPTY_INTERRUPT(ADC_vect);

uint16_t getVoltage(uint8_t pin) {
    ADMUX = (0b11110000 & ADMUX) | pin;

    uint32_t overValue = 0;
    for (uint8_t i = 0; i < 16; i++) {
        sleep_mode();
        overValue += ADC;
    }
    int16_t mV = (((overValue >> 2) * AREF_MV) >> 12);

    return mV;
}

Es funktioniert gut.

Gleichzeitig erzeuge ich einen 4-kHz-Piepton mit einem Timer, der einen Ausgangspin umschaltet, und ich lese und schreibe Daten über USART.

Der Piepton hat einmal pro Sekunde einen kurzen Klick, der so aussieht:Geben Sie hier die Bildbeschreibung ein

Und hin und wieder wird ein über USART gesendetes Zeichen verstümmelt.

Während ich erwarten würde, dass der Beep-Timer während der AD-Konvertierung in den Ruhezustand versetzt wird, um das interne Rauschen zu reduzieren, habe ich nicht erwartet, dass USART tx/rx gestört wird.

Wenn ich den Schlafmodus nicht verwende und AD-Konvertierungen wie folgt durchführe:

    // sleep_mode();
    ADCSRA |= (1 << ADSC);
    loop_until_bit_is_clear(ADCSRA, ADSC);

der Piepton ist „sauber“, es gibt keine USART tx/rx-Probleme mehr, und nach einigen ausführlichen Messungen bin ich mir ziemlich sicher, dass die AD-Konvertierungsergebnisse genauso genau sind wie im Schlafmodus.

Da wundern mich zwei Dinge:

  1. Wird erwartet, dass USART tx/rx durch SLEEP_MODE_ADC gestört wird?
  2. Macht der Schlafmodus in Kombination mit Oversampling überhaupt Sinn? Hilft ein gewisses Rauschen vielleicht nicht einmal zur Erhöhung der Genauigkeit (Dithering) oder gilt das nur für Rauschen, das von den Sensoren kommt?
Müssen wir raten, welche Hardware Sie verwenden?
Ups, Entschuldigung - hinzugefügt.
Verwenden Sie die seriellen Routinen von Arduino oder etwas anderes? Wenn die von Arduino, können Sie Serial.flush() vor dem Schlafen ausprobieren. Wenn Sie Ihre eigenen Routinen verwenden, versuchen Sie, auf das Senden eines beliebigen Zeichens im Puffer zu warten, bevor Sie schlafen gehen. Soweit ich mich erinnere, deaktiviert der Schlafmodus die Uhr für den USART-Baudgenerator, was bedeutet, dass ein Zeichen, das gerade gesendet wird, beschädigt wird.
Ich verwende eigene Routinen und werde einfach versuchen, was Sie vorschlagen ...
Ich habe es versucht loop_until_bit_is_set(UCSR0A, UDRE0);(USART Data Register Empty), bevor ich schlafen ging, aber es hat nicht geholfen. Ein _delay_ms(10)vor dem Betreten der Schleife hilft, ist aber nicht sehr schön, denke ich. Außerdem erhalte ich beschädigte Daten, die an den AVR gesendet werden, und ich habe keine Ahnung, wie ich den Empfang von Daten während dieser 3*16-Aufrufe von sleep_mode() vermeiden kann.

Antworten (1)

  1. Wird erwartet, dass USART tx/rx durch SLEEP_MODE_ADC gestört wird?

Absolut. Sowohl der USART als auch die Timer verwenden clk IO für den Betrieb, und dies ist im ADC-Rauschunterdrückungsmodus deaktiviert.

  1. Macht der Schlafmodus in Kombination mit Oversampling überhaupt Sinn? Hilft ein gewisses Rauschen vielleicht nicht einmal zur Erhöhung der Genauigkeit (Dithering) oder gilt das nur für Rauschen, das von den Sensoren kommt?

Sie möchten tatsächlich etwas Rauschen, wenn Sie Oversampling und Dezimierung so durchführen , wie Sie es tun, daher glaube ich nicht, dass der ANR-Modus hier sinnvoll wäre. Beschränken Sie sich auf den Ruhemodus ( SLEEP_MODE_IDLE), um den USART und die Timer am Leben zu erhalten.

Hübsch. Mit SLEEP_MODE_IDLE funktioniert mein ursprünglicher Code einwandfrei, kein Klicken im Piepton und keine USART RX/TX-Probleme. Und keine Notwendigkeit zu verwenden loop_until_bit_is_clear(ADCSRA, ADSC). Danke!