SLEEP_MODE_ADC мешает работе USART (и звуковому сигналу)

На 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 такие же точные, как и в спящем режиме.

Итак, меня интересуют две вещи:

  1. Ожидается ли, что SLEEP_MODE_ADC потревожит tx/rx USART?
  2. Действительно ли спящий режим имеет смысл в сочетании с передискретизацией? Возможно, некоторый шум даже не помогает повысить точность (дизеринг) или это относится только к шуму, исходящему от датчиков?
Должны ли мы угадывать, какое оборудование вы используете?
Упс, извините - добавил.
Используете ли вы подпрограммы Arduino Serial или что-то еще? Если Arduino, можете ли вы попробовать Serial.flush() перед сном. Если ваши собственные процедуры, попробуйте дождаться отправки любого символа в буфере перед тем, как заснуть. Насколько я помню, спящий режим отключит часы для генератора бода USART, что означает, что если символ находится в середине отправки, он будет поврежден.
Я использую собственные процедуры, и я просто попробую то, что вы предлагаете...
Я пробовал loop_until_bit_is_set(UCSR0A, UDRE0);(пустой регистр данных USART) перед сном, но это не помогло. A _delay_ms(10)перед входом в цикл действительно помогает, но, я думаю, не очень приятно. Кроме того, я получаю поврежденные данные, отправленные на AVR, и я понятия не имею, как избежать получения данных во время этих 3 * 16 вызовов sleep_mode().

Ответы (1)

  1. Ожидается ли, что SLEEP_MODE_ADC потревожит tx/rx USART?

Абсолютно. И USART, и таймеры используют clk IO для работы, и это отключено в режиме шумоподавления АЦП.

  1. Действительно ли спящий режим имеет смысл в сочетании с передискретизацией? Возможно, некоторый шум даже не помогает повысить точность (дизеринг) или это относится только к шуму, исходящему от датчиков?

На самом деле вам нужен некоторый шум при выполнении передискретизации и прореживания , поэтому я не думаю, что режим ANR будет иметь здесь смысл; ограничить себя режимом ожидания ( SLEEP_MODE_IDLE), чтобы сохранить работоспособность USART и таймеров.

Хороший. С SLEEP_MODE_IDLE мой исходный код работает нормально, нет щелчка в звуковом сигнале и нет проблем с USART RX/TX. И не надо использовать loop_until_bit_is_clear(ADCSRA, ADSC). Спасибо!