На AVR ATmega328P один раз в секунду я выполняю 3 преобразования AD, следующих друг за другом с 16-кратной передискретизацией, используя SLEEP_MODE_ADC, например:
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;
}
Это работает нормально.
В то же время я генерирую звуковой сигнал частотой 4 кГц с таймером, переключающим выходной контакт, и я читаю и записываю данные через USART.
Звуковой сигнал имеет короткий щелчок один раз в секунду, который выглядит следующим образом:
И время от времени символ, отправленный через USART, искажается.
Хотя я ожидал, что таймер звукового сигнала будет переведен в спящий режим во время преобразования AD, чтобы уменьшить внутренний шум, я не совсем ожидал, что USART tx/rx будет нарушен.
Когда я не использую спящий режим и делаю преобразования AD следующим образом:
// sleep_mode();
ADCSRA |= (1 << ADSC);
loop_until_bit_is_clear(ADCSRA, ADSC);
звуковой сигнал «чистый», проблем с USART tx/rx больше нет, и после некоторых обширных измерений я почти уверен, что результаты преобразования AD такие же точные, как и в спящем режиме.
Итак, меня интересуют две вещи:
- Ожидается ли, что SLEEP_MODE_ADC потревожит tx/rx USART?
Абсолютно. И USART, и таймеры используют clk IO для работы, и это отключено в режиме шумоподавления АЦП.
- Действительно ли спящий режим имеет смысл в сочетании с передискретизацией? Возможно, некоторый шум даже не помогает повысить точность (дизеринг) или это относится только к шуму, исходящему от датчиков?
На самом деле вам нужен некоторый шум при выполнении передискретизации и прореживания , поэтому я не думаю, что режим ANR будет иметь здесь смысл; ограничить себя режимом ожидания ( SLEEP_MODE_IDLE
), чтобы сохранить работоспособность USART и таймеров.
loop_until_bit_is_clear(ADCSRA, ADSC)
. Спасибо!
Евгений Ш.
Торстен Рёмер
Том Карпентер
Торстен Рёмер
Торстен Рёмер
loop_until_bit_is_set(UCSR0A, UDRE0);
(пустой регистр данных USART) перед сном, но это не помогло. A_delay_ms(10)
перед входом в цикл действительно помогает, но, я думаю, не очень приятно. Кроме того, я получаю поврежденные данные, отправленные на AVR, и я понятия не имею, как избежать получения данных во время этих 3 * 16 вызовов sleep_mode().