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:
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:
- 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.
- 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.
loop_until_bit_is_clear(ADCSRA, ADSC)
. Danke!
Eugen Sch.
Torsten Römer
Tom Tischler
Torsten Römer
Torsten Römer
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.