Не получается инициализировать несколько датчиков одновременно для ардуинки
- Войдите на сайт для отправки комментариев
Здравствуйте, уважаемые форумчане. Второй день не могу закончить по-человечески программу. Суть в том, что 3 датчика MQ-2 должны опрашиваться микроконтроллером. Результаты выводятся на дисплей 1602A. При фиксировании задымления одним из датчиков реле замыкает нагрузку из вентиляторов. Я перенастроил АЦП для более быстрого преобразования сигналов, поступающих с датчиков. Суть же проблемы, с которой я сталкиваюсь, в том, что на всех аналоговых пинах фиксируется одно и то же значение, как бы я не проворачивал это дело.
Вот фрагмент кода для обработки прерывания от АЦП:
Выручайте, уважаемые специалисты! На дисплей я вывожу пока limit1 и limit2, получается вот такой ужас :(
По датчикам, у меня подключен только один MQ-2 к А0, но подключая датчик звука к А1, я наблюдаю ту же картину(
Прочитайте тему http://arduino.ru/forum/obshchii/pesochnitsa-dlya-vsekh-novichkov и попробуйте задать вопрос правильно.
Извиняюсь. Вот фрагмент из обработчика прерываний и loop:
Не вижу настроек ADC и также не вижу чему равна переменная/константа analog_ref. Потому не могу сказать взводится ли бит ADLAR. Если нет, то считывание значения ADC написано неверно.
Зачем так "извращённо" издеваться над АЦП? Опрашивай их потихоньку в основном лупе и будет всё работать.
PS: АЦП обрабатывают через ISR таким способом только тогда, когда нужно отслеживать или анализировать состояние нескольких входов АЦП за единицу времени. Например,раз в 1 сек. 5 входов или 100 раз в секунду и т.д. Так-что в именно этом коде - это лишнее.
Я перенастроил АЦП для более быстрого преобразования сигналов, поступающих с датчиков.
Вы пытаетесь сэкономить несколько десятков мкс на опросе датчиков и тут же тратите в несколько сотен раз больше времени для вывода на дисплей.
почему? у меня ведь выводятся беспрерывно показания, без задержек, или все-таки есть какие-то задержки, просто я не замечал?.. Serial.print и lcd.print аккуратно координируются вроде, без отставаний, я так проверял...
Получается, желательно отказаться от изменения параметров обработчика прерываний? Я понял, спасибо. Да я только просто разбираться начал, вычитал все здесь: https://codius.ru/articles/
То есть нужно в обработчике прерываний просто
оставить, а в loop уже поочередный опрос датчиков сделать?
Вы, по-прежнему, не показали своих настроек ADC, потому разговор идёт "языком по голому заду".
Суть проблемы в том, что мне надо сменить вход мультиплексора для нового преобразования, потом снова в обработчик прерываний, потом меняем опять вход мультиплексора, опять преобразуем и в обработчик прерываний и т.д., а потом заново, с A0 начинаем
В строке №3 ошибка. Среда Ардуино сама конфигурирует ADMUX, Вы хотите переконфигурировать его под себя, но зачем-то сохраняете старую конфигурацию. Замените на присваивание.
Далее, не вижу где Вы запускаете считывание ADC. Из Вас код по строчке клещами тянуть?
Понял, исправил. Ну как, вот в последней строке
это разве не запуск преобразования?
Вот для одного датчика у меня прекрасно все работает, для нескольких начинается *crazy dance* микроконтроллера
Соглашусь с #4. Родной analogRead около 100 микросекунд. Вывод символа на экран тоже этих масштабов. Весь цикл опроса датчиков и вывод на экран займёт не больше миллисекунды. Время реакции датчика на задымление в сотни раз больше. Зачем устраивать головную боль? Если учиться, то надо взять мануал на процессор и написать программу как там рекомендуют. Если сделать устройство, то надо рассмотреть параметры всех составляющих и выбрать наиболее простой путь реализации. В данном случае, гнаться за скоростью обработки - показать свою не состоятельность как инженера.
Понял, исправил. Ну как, вот в последней строке
это разве не запуск преобразования?
Однократный. Как Вы запускаете его после прерывания?
В общем, если Вы ещё не поняли, выкладывайте код полностью (разумеется, сократив его до минимального, на котором видна проблема) или разбирайтесь сами
Я понял, тогда переделаю, уберу обработчик прерываний и сделаю через analogRead в loop. Спасибо.
Я не знаю. У меня ведь ADC работает в режиме free running mode. А касательно обработчика, я думал, он самостоятельно при таком режиме ADC завершает работу. Да и потом, нужно ли завершать его работу при непрерывной обработке входящих сигналов?.. Считывается себе и считывается, работает обработчик и работает, это ведь телу программы (loop) не мешает....
А. Я понял, вы имеете ввиду, что я в Setup установил флаг запуска ADC. Ну хорошо, я тогда уже сам попробую разобраться, не могу полностью код выложить, извините. По антиплагиату потом не пройдет.
Суть проблемы в том, что мне надо сменить вход мультиплексора для нового преобразования, потом снова в обработчик прерываний, потом меняем опять вход мультиплексора, опять преобразуем и в обработчик прерываний и т.д., а потом заново, с A0 начинаем
ЕслиУж так нужно "выпендиццо" тогда делаешь ADC Free Running mode. В ISR по окончанию преобразования запоминаешь результат, меняешь канал АЦП и поехал. В таком режиме АЦП будет работать на максимуме своих возможностей и аппаратно, оОочень мало занимая процессорного времени. Но, сцуко, атомарность будет засадой )))
Извините, а не могли бы вы показать в коде, как это сделать? Просто вроде стоит free running mode, но АЦП втупую не хочет прикасаться к другим пинам, в итоге на выходе переменная rezultat присваивается и первому, и второму, и третьему пину одна и та же :(
Вот в качестве примера опрос джойстика по трём каналам в прерывании ADC.
Сверху: берём результат преобразования.
Дальше, разбрасываем по трём разным переменным. У меня в этом примере использован AutoTriggering от таймера, опрос 60 раз в секунду, соответственно, 20 раз в секунду на канал. Работает уже не один год. (это только махонький кусочек кода...)
in r0,adcl
in r1,adch
lds r16,{Adc_input_channel}
cpi r16,00
breq adcc_int_joy_x
cpi r16,01
breq adcc_int_joy_y
cpi r16,02
breq adcc_int_joy_b
Да, мне очень нужно выпендриться..)) от этого зависит оценка по курсовой.... Так бы я через analogRead спокойненько все сделал и не мучил бы ни себя, ни вас..
В таком случае сделай всё на прерываниях и на асме. В main будет только одна строчка, типа если (flag) то реле On иначе Off. Гарантирую, шо препод(ша) акуеет!!!
Да, забыл, заголовок на чистом С сделай, кодевижн или джумпстарт позволяют конфиг проца сделать оОочень лаконичный!!!
Ахахаха, нет, я изначально отказался на восьмой меге делать, потому что терпеть не могу на асме все, что можно и нельзя, инициализировать, адресовать и т.д. и т.п )) Еле лабы закрыл по нему в прошлом семестре.
Спасибо большое всем за ответы и помощь, буду пробовать по-разному, уже логика и здравый смысл отключились!) Буду перебирать варианты, руководствуясь принципом "А вдруг заработает" :D
Но при этом от других требуется
В общем, разбирайтесь сами.
потому что терпеть не могу на асме
Буду перебирать варианты, руководствуясь принципом "А вдруг заработает" :D
Этт ты зря... На асме можно творить чудеса.
Принцип не плох, время только много занимает.
Ну, можно и фри-раннинг, только ADMUX нужно вовремя обновлять, а не когда попало, как у ТС. А так получается, что читается всё время с одного и того же канала, т.к. DMUX реально не изменяется.
Понимаю. Но сейчас банально нехватка времени сказывается. А так у меня стмка в пути с Китая, я буду на асме ее кодить
Да я уже и так пробовал обновлять, ни в какую просто
Я сейчас просто убрал все лишнее с программы и оставил только инициализацию АЦП, обработку прерываний и вывод данных на дисплей, вот что получается, полная программа, еще какая проблемная..
Предделитель я потом поменяю, мне пока просто надо, чтобы это все заработало
А так у меня стмка в пути с Китая, я буду на асме ее кодить
Дануна. Там шоб светадиодоммаргнуть нуно тышшустрок написАтЪ )))
Вот на "тяжёлых" процах ассемблер - это уже лишнее )))
А, ну просто для себя попробую хотя бы))
Вы не вовремя обновляете ADMUX - слишком рано. Читайте даташит
Ну частота контроллера 16 МГц, а частота АЦП зависит от частоты МК и предделителя, насколько знаю. Получается, нужен таймер перед следующим считыванием для задержки по времени и все?
Я сделал задержку по времени, но ничего не меняется..(
Я сделал задержку по времени, но ничего не меняется..(
А с какого бодуна ему меняться?
https://www.youtube.com/watch?v=ZSXimQHCjKo - Вы не сделали никакой задержки от слова совсем.
Во-первых, для задержки нужно не
if
(millis() - timing > 1000)
, а while (millis() - timing > 1000);. А во-вторых, если Вы так сделаете, то то это будет задержка навечно - программа намертво повиснет, т.к. millis внутри обработчика прерывания не изменяется и всегда возвращает одно и тоже.частота АЦП зависит от частоты МК и предделителя, насколько знаю.
Неправильно знаете. Вы её настраиваете сами и должны знать её точно. Для полного разрешения АЦП частота должна быть от 50 до 200 килогерц.
Эмммм...
Эт щас такой студент пошёл, шо фприрывании милс считает? Шо с нами будет... Ужос...
Та я уже не знаю, где что посчитать, голова не работает. http://www.cyberforum.ru/avr/thread2085603.html здесь пишут, что считать вообще не нужно ничего, каналы можно сразу переключать. Я вроде все правильно делаю, пины переключаю:
Результат в case вывожу в loop(), этот АЦП в упор не хочет видеть другие пины кроме A0. Где еще что поставить,
я уже не знаю. По-моему, это невыполнимая задача какая-то.
Все верно ведь по логике...
1) Настройка АЦП, запуск преобразования
2) Обработка прерываний от АЦП, переключение пина, новый запуск преобразования
3) Завершение преобразования, обработка прерываний
4) Переключение пина, новый запуск и т.д.
Зачем нужны 6, 8, 12-канальные АЦП, если их невозможно нормально настроить?..
Зачем нужны 6, 8, 12-канальные АЦП, если их невозможно нормально настроить?..
Почему невозможно? "Рыба есть, ловить надо уметь"
Ну, не знаю, Вы на каждом заборе читаете, что пишут? Читайте даташит. там пишут всё правильно.
Ну, почему, я же Вам уже всё сказал. Просто назначайте новый пин после того, как прошёл первый тик преобразования (можно парочку тиков пропустить для надёжности). Делов-то.
4) Переключение пина, новый запуск и т.д.
Стоп! Давайте определимся, чего Вы хотите. Уж либо "фри-раннинг", либо "новый запуск". Вы что-то выберите и в одну кучу не валите.
Спасибо за ссылку, завтра ознакомлюсь с даташитом.
Ну фри-раннинг должен подразумевать непрерывную обработку всех каналов, правильно? Результаты этой обработки моментально присваиваются в loop() соответствующим переменным porog1, porog2, porog3 и т.д., правильно? Т.е. loop() и ISR работают, не мешая друг другу.
Задержку я пробовал делать через выключение/включение АЦП перед переключением пинов. Вот так это в коде выглядит:
Также я попробовал поставить Serial.begin после каждого case и обнаружил, что в монитор порта выводится значение PC0, то есть 14, получается, что переключения просто-напросто не происходит, насколько я понял.
С другой стороны, я установил Serial.begin после
Здесь уже монитор порта отображает, что переключение пинов происходит..
Ну, почему, я же Вам уже всё сказал. Просто назначайте новый пин после того, как прошёл первый тик преобразования (можно парочку тиков пропустить для надёжности). Делов-то.
Там, вроде, даже первый результат чтения надо в утиль спускать после смены канала. Или это не про то?
Если переключать канал в прерывании, в режиме автозапуска, то это происходит уже после старта нового захвата, и новый канал станет активен только после следующего прерывания. Учесть это не сложно.
Извините, а как это учесть? Где и что прописать, в loop, setup, ISR или в функции, отвечающей за настройку ADC? Подозреваю, что вы имеете ввиду какую-то проверку на определение нового входа, но как ее реализовать, если не через switch(analogPin)?
Ну фри-раннинг должен подразумевать непрерывную обработку всех каналов, правильно?
У атмеги всего один АЦП и аналоговый коммутатор с помощью которого можно подключать этот один АЦП к разным ножкам по очереди. Фри ранинг означает, что следующее измерение автоматически запускается сразу же после окончания предыдущего. Причем по тому же самому каналу. При этом срабатывает прерывание, но к тому времени как обработчик начинает его обрабатывать АЦП уже во всю оцифровывает следующую выборку.
Фри ранинг используется когда нам надо получать выборки по одному каналу с минимальными паузами. Если нам надо скакать между каналами, то такой режим использовать смысла нет. Тогда для максимально быстрого опроса нужен режим одиночных измерений и обработка и переключение каналов по прерыванию. Но для вашего случая (датчика MQ-2) экономить микросекунды смысла нет. Как тут уже неоднократно упоминали - используйте analogRead без всяких прерываний и будет вам счастье. Ну получите вы сигнал о задымлении на одну десятитысячную секунды позже, что это изменит?
Кстати если вы используете код приведенный в сообщении #9 то у вас в 19 строке ошибка, тильду пропустили. Хотя в данном случае это ни на что особо не влияет.
Там, вроде, даже первый результат чтения надо в утиль спускать после смены канала. Или это не про то?
Нет, это после смены "Voltage Reference"
Извините, а как это учесть? Где и что прописать, в loop, setup, ISR или в функции, отвечающей за настройку ADC? Подозреваю, что вы имеете ввиду какую-то проверку на определение нового входа, но как ее реализовать, если не через switch(analogPin)?
Блин, ну Вы голову-то включите. Ну, запустили Вы преобразование в самом начале. Запоминайте время. Проверяйте в лупе, не прошло ли два , скажем тика ADC (время тика Вы обязаны знать!). Как прошло, перезаписывайте ADMUX. Случилось прерывание, запоминайте время, хватайте результат и убирайтесь из обработчика прерывания. И снова "проверяйте в лупе ..." и так далее.
Ничего не получается. Наверно, буду делать через analogRead(); Я уже попробовал одиночное преобразование по-разному делать, и с задержкой, и с переключением пинов в обработчике прерывания, с проверкой обработки прерывания и последующим переключением пинов, этот АЦП не сдается. А мне сдается, что мультиплексор вообще не умеет работать по неизвестным мне причинам с другими портами кроме PC0, может с ардуинкой что-то не то, может с АЦП. Я написал чистую программу для работы с несколькими каналами, ничерта не работает.
И задержку делал на 2 такта, как указано в даташите и как посоветовал Евгений. Что не так? Режим Single conversion mode, преобразование завершилось, обработчик прерываний включился, далее после присваивания результата переменной res я вновь запускаю АЦП, а в loop меняю пины для переключения. Я делал и с задержкой, не помогает вообще. А еще я заметил, что если вот тут
вместо
указать
убрать к черту свитч и просто пытаться вывести результат на A1 пине, то что получается? Правильно, ничего. Ничего не меняется, АЦП не хочет работать ни с каким пином кроме A0.