Почему АЦП сообщает 0 в этом скетче?

Этот скетч всегда сообщает 0 для показаний АЦП.

Я думаю, что это окажется чем-то глупым, но я не могу найти источник. Я внимательно просмотрел эскизные линии АЦП, и они кажется правильными, так что, возможно, проблема с физическими соединениями или с тем, как я пытаюсь сообщить о выходе АЦП, или с порядком выполнения задач. Функции capture_FID() и т. д. основаны на примере из раздела 9.2.4 книги Нормана Данбара Внутреннее устройство программного обеспечения Arduino. Единственная разница - это позиция ADCSRA |= (1 << ADEN);, которую я переместил сразу после включения питания на основе этого ответить. Это не имело значения.


void init();
void setup() {
  Serial.begin(115200);
  capture_FID();
}
void loop() {
}

void capture_FID() {

  volatile uint16_t ADC_output = 0;  // максимальное значение 65536

  config_ADC();
  start_ADC();
  for (int i = 1; i <= 5; i++) {
    Serial.print("\ti = ");
    Serial.print(i);
    Serial.print(" value = ");
    Serial.println(ADC_output);
  }
  stop_ADC();
}

// Конфигурация АЦП
void config_ADC() {
  Serial.println("Configuring the ADC...");
  PRR &= ~(1 << PRADC);                                            // включаем АЦП
  ADCSRA |= (1 << ADEN);                                           // включаем АЦП
  ADCSRA = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);             // замедляем ход часов
  ADMUX = (0 << REFS1) | (1 << REFS0);                             // используем внутреннее опорное напряжение 5 В
  ADMUX &= ~(1 << ADLAR);                                          // выравниваем по правому краю 10-битный вывод в пространстве размером 2 байта/16 бит
  ADMUX |= (0 << MUX3) | (0 << MUX2) | (0 << MUX1) | (0 << MUX0);  // вход мультиплексора; используйте А0
  DIDR0 |= (1 << ADC0D);                                           // отключаем цифровой вход на контакт A0
  ADCSRA |= (1 << ADIE);                                           // устанавливаем прерывание для уведомления о доступности данных для дальнейшего использования
  ADCSRA |= (1 << ADATE);                                          // автозапуск включен
  ADCSRB = 0;                                                      // автономный режим
  delay(20);                                                       // ждем, пока напряжение стабилизируется
}

// Запускаем АЦП = начинаем сбор данных
void start_ADC() {
  Serial.println("Starting the ADC...");
  ADCSRA |= (1 << ADSC);
}

// Остановить АЦП = прекратить сбор данных
void stop_ADC() {
  Serial.println("Stopping the ADC...");
  ADCSRA |= (0 << ADSC);
}

ISR(ADC_vect) {
  volatile uint16_t ADC_output;  // максимальное значение 32767
  ADC_output = ADCW;
}

Оборудование:

  • Ардуино R3
  • Ограничение 0,1 мкФ между GND и AREF
  • Функциональный генератор PicoScope подает сигнал смещения 500 Гц, 500 мВ, 1 В; отрицательный выход подключен к GND на Arduino, положительный выход подключен к A0.
  • Эскиз, который не предполагает автономный запуск и автоматический запуск, который я нашел на сайте Ника Гаммона, работает нормально, так что с доской все в порядке. Это также означает, что с аппаратными подключениями и настройками области все в порядке.

, 👍0


1 ответ


3

У вас есть две разные переменные с именем ADC_output:

  • один, который является локальным для capture_FID() и всегда равен нулю (никогда не является присвоено другое значение)
  • один локальный для ISR(ADC_vect), который установлен, но никогда не используется.

Вы должны использовать только одну такую переменную.

В этом коде есть еще несколько проблем:

  • capture_FID() печатает один и тот же результат несколько раз без проверка поступления новых данных
  • доступ к ADC_output за пределами ISR не защищен в критическом раздел
  • регистр ADC называется ADC, а не ADCW.
  • ADCSRA |= (0 << ADSC) не работает
  • нет смысла объявлять init()
  • наверное больше, я не до конца прочитал…
,

Ах, значит, проблема в моем ограниченном опыте работы с C. Позвольте мне немного покопаться. Спасибо., @Bryan Hanson