Инициализация ADC А0 пина
- Войдите на сайт для отправки комментариев
Пнд, 09/05/2022 - 08:29
void setup() {
int analog = analogRead(5); // 1 работает
ADMUX = 0 | _BV(ADLAR) | _BV(REFS0); // пин 0 - устанавливаем канал, используем 8 бит, ref=Vcc
ADCSRA = _BV(ADEN) | // ADC enable
_BV(ADSC) | // ADC start
_BV(ADATE) | // Auto trigger
_BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
// int analog = analogRead(5); // 2 - если тут тот код стопорится
Serial.begin(9600);
}
void loop() {
Serial.print("111111111111");
}
Здравствуйте. Помогите исправить настройку ADC порта А0, который перестает работать, если в коде есть еще операция чтения любого другого аналогового порта. Причем которая размещается именно ПОСЛЕ инициализации ADC.
Это происходит потому что ADMUX меняется.
int analogRead(uint8_t pin) { uint8_t low, high; #if defined(analogPinToChannel) #if defined(__AVR_ATmega32U4__) if (pin >= 18) pin -= 18; // allow for channel or pin numbers #endif pin = analogPinToChannel(pin); #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) if (pin >= 54) pin -= 54; // allow for channel or pin numbers #elif defined(__AVR_ATmega32U4__) if (pin >= 18) pin -= 18; // allow for channel or pin numbers #elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) if (pin >= 24) pin -= 24; // allow for channel or pin numbers #else if (pin >= 14) pin -= 14; // allow for channel or pin numbers #endif #if defined(ADCSRB) && defined(MUX5) // the MUX5 bit of ADCSRB selects whether we're reading from channels // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high). ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); #endif // set the analog reference (high two bits of ADMUX) and select the // channel (low 4 bits). this also sets ADLAR (left-adjust result) // to 0 (the default). #if defined(ADMUX) #if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) ADMUX = (analog_reference << 4) | (pin & 0x07); #else ADMUX = (analog_reference << 6) | (pin & 0x07); #endif #endif // without a delay, we seem to read from the wrong channel //delay(1); #if defined(ADCSRA) && defined(ADCL) // start the conversion sbi(ADCSRA, ADSC); // ADSC is cleared when the conversion finishes while (bit_is_set(ADCSRA, ADSC)); // we have to read ADCL first; doing so locks both ADCL // and ADCH until ADCH is read. reading ADCL second would // cause the results of each conversion to be discarded, // as ADCL and ADCH would be locked when it completed. low = ADCL; high = ADCH; #else // we dont have an ADC, return 0 low = 0; high = 0; #endif // combine the two bytes return (high << 8) | low; }1. После установки ADMUX надо паузу хотя бы 1ms
2. Надо дождаться ОКОНЧАНИЯ преобразования, считать данные и только после этого менять ADMUX
ПОдскажите, пожалуйста, как его восстанавливать? У меня не высокий уровень знаний.
На А0 стоит потенциометр, опрашивается в прерывании по таймеру на 1 мс, который запускается в Setup. Там же инициализируется ADC. На А7 (с внешним резистором) и, когда потенциометр не крутится, нажимается кнопка (просто цифровых уже нет свободных). Кнопка опрашивается в loop.
вот фрагмент кода обработки потенциометра
ADMUX = pin | _BV(ADLAR) | _BV(REFS0); // устанавливаем канал, используем 8 бит, ref=Vcc ADCSRA = _BV(ADEN) | // ADC enable _BV(ADSC) | // ADC start _BV(ADATE) | // Auto trigger // _BV(ADIE) | // Interrupt enable _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // 128:1 / 13 = 9615 Hz ADCSRB = 0; // Free run mode, no high MUX bit DIDR0 = 1 << pin; // Turn off digital input for ADC pin sei(); ADCSRA |= _BV(ADIE); // Enable sampling interrupt // сразу запускаем АЦП delay(10); //Настраиваем таймер0 на прерывание по совпадению //Раз в 1 msec OCR0A = 0xAF; TIMSK0 |= _BV(OCIE0A); // Enable processing interrupts // сразу запускаем Таймер sei(); // Enable interrupts // Serial.println((String)" init end "); } //Прерывания таймера 1 раз в msec ISR (TIMER0_COMPA_vect) { uint8_t val; // Serial.println(" prer t0 est"); if (abs(pedalCurrentPos - pedalAverADC) >= pedalStep) //поехали { pedalCurrentPos = pedalAverADC; // Serial.println((String)" pedalAverADC " + pedalAverADC); val = map (pedalCurrentPos, pedalStart, pedalStop, 0, pedalSteps); // от 0 до pedalSteps (127) if (val != pedalVal) { pedalVal = val; if (fSP == 0) { PedalAction(pedalVal); } else { PedalActionP(pedalVal); } } } } ISR(ADC_vect) { // ADC sampling interrupt uint8_t sample = ADCH; // 0-255 // Serial.println((String)" bbbb "); // uint8_t noiseCnt = 0; if (sample > pMax) sample = pMax; if (sample < pMin) sample = pMin; noiseCnt = 0; pedalAverADC = GetNextAvrg(sample); // Serial.println((String)" AverADC "+pedalAverADC);еще меня устроит применение библы "GyverButton.h", но примеров ее работы с аналоговыми портами совместно с непосредственной обработкой А0, как выше - не могу найти. Вот так только, что у меня не работает..
Если уровень знаний низкий зачем использовать прямой доступ к регистрам? Аналогрид делает то же самое практически с той же скоростью и совершенно без проблем? И совместим с другими библиотеками?
1. После установки ADMUX надо паузу хотя бы 1ms
2. Надо дождаться ОКОНЧАНИЯ преобразования, считать данные и только после этого менять ADMUX
Верно ли что 1) таймер никак не связан с проблемой, а преобразование ADC начинается после изменения напряжения на входе А0? 2) Как объяснить "стоп" выполнения кода, когда нет никакого преобразования, даже если не подключен потенциометр? 3) смена / установка ADMUX видимо осуществляется в момент команды analogRead? Значит надо типа так: считали А7 (кнопку) и в конце ее обработки обратно сразу вернули ADMUX на А0? Так?
Проект по моему заказу пишется программистом, не мной. Небольшую доработку хочется сделать самому. Вот и все. Что такое Аналогрид я не знаю, и на остальные вопросы, извиняюсь, дать ответа не могу. Если нужны уточнения - спрашивайте, и прошу помочь.
Верно, что что вопрос относится к мультиплексированию входных портов одного АЦП и нужно чтоб один порт работал по прерыванию, чтоб не менять уже отлаженного кода, а второй должен настроить я, чтоб опрашивался в цикле?
Что такое Аналогрид я не знаю
Это строки 3 и 11 в коде первого поста
ясно. У меня Grid ассоциировался с сеткой и массивом.
Кабсдец.))) АналогРид (AnalogRead)! В коде так и написано. Вы чего? От 1 мая не отошли ещё?)))
Ну он то думал Анало-грид.
Ну он то думал Анало-грид.
Ну как мне теперь это развидеть?!!!
Надеюсь на практическую помощь.
Так а какую именно помощь Вы надеетесь получить?
Физически АЦП один, следовательно, одновременно читать и из цикла и из прерывания невозможно. Надо как-то разносить по времени. А как - это уж Вам решать. Первое, что приходит в голову - устанавливать флаг и запрещать чтение либо оттуда, либо оттуда. Т.е. данные будут с пропусками. Надо расставлять приоритеты. Но скорее всего, никакой работы с регистрами для этого не понадобится. Т.е. все решается обычным analogRead(). Ну либо не решается никак.
Надеюсь на практическую помощь.
на какую, простите, нахрен, помощь?
Вы заказали проект программисту и, наверно, платите ему - так что мешает попросить его добавить в код еще один порт...? С какой целью тут людям выносить мозг - чтобы сэкономить пару сотен рублей?
Так а какую именно помощь Вы надеетесь получить?
Физически АЦП один, следовательно, одновременно читать и из цикла и из прерывания невозможно. Надо как-то разносить по времени. А как - это уж Вам решать. Первое, что приходит в голову - устанавливать флаг и запрещать чтение либо оттуда, либо оттуда. Т.е. данные будут с пропусками. Надо расставлять приоритеты. Но скорее всего, никакой работы с регистрами для этого не понадобится. Т.е. все решается обычным analogRead(). Ну либо не решается никак.
Я выше писал: "На А7 (с внешним резистором) и, когда потенциометр НЕ КРУТИТСЯ, нажимается кнопка (просто цифровых уже нет свободных)"
Это не означается разве, что есть "разноска по времени"? Мне не хочется влезать в отдельно оформленную кастомную библиотеку по обработке потенциометра. Надо найти решение именно ДОБАВИТЬ опрос кнопки. Вот типа такого можно?
void loop() { int analog = analogRead(7); if (analog < 200) { //// обработка кнопки на А7 //затем восстанавливаем чтение А0 ADMUX = pin | _BV(ADLAR) | _BV(REFS0); // устанавливаем канал, используем 8 бит, ref=Vcc ADCSRA = _BV(ADEN) | // ADC enable _BV(ADSC) | // ADC start _BV(ADATE) | // Auto trigger // _BV(ADIE) | // Interrupt enable _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); } }После любого переключения входов на ADC - первое измерение покажет ХЗчто. Это у вас в коде нигде не отрабатывается.
А почему не читать все аналоговые пины через прерывание ISR(ADC_vect) ? В прерывании сохранять значение АЦП и тут же запускать измерение на следующем канале. Даже если читать 8 каналов, то данные будут обновляться каждую мс. При этом в loop() читать сохраненные значения из нужного канала.
Сразу следующий не получится. Конденсатор в блоке АЦП один. Его надо перезарядить до уровня следующего канала на это надо время. Кто то задержки ставит, кто то два раза считывает и первое выбрасывает но в любом случае вподряд несколько разных каналов сразу без больших ошибок не получится. Единственная возможность сделать выходное сопротивление источника сигнала минимальным. Но это обычно из области фантастики без вложения денег.
Источник с выходным сопротивлением <= 10кОм вполне справляется. А вот опорное если меняется, то задержка нужна.
Я выше писал: "На А7 (с внешним резистором) и, когда потенциометр НЕ КРУТИТСЯ, нажимается кнопка (просто цифровых уже нет свободных)"
Это не означается разве, что есть "разноска по времени"?
МК не знает, КРУТИТСЯ потенциометр или нет. Поэтому никакого "разноса по времени" здесь не получится.
На всякий случай еще тут же приведу свой ответ на пост №6:
Верно ли что
1) таймер никак не связан с проблемой, а преобразование ADC начинается после изменения напряжения на входе А0?
Неверно.
2) Как объяснить "стоп" выполнения кода, когда нет никакого преобразования, даже если не подключен потенциометр?
Никак. МК не знает, подключен ли потенциометр.
Соответственно, если преобразование задано в коде, наличие или отсутствие потенциометра, а также вращается он или нет, преобразование произойдет в любом случае.
В общем, меняйте логику программы так, чтобы чтение АЦП либо ВСЕГДА присходило только в цикле, либо ВСЕГДА только в прерывании.