analogRead через прерывания?
- Войдите на сайт для отправки комментариев
Передо мной стоит задача чтения значения с порта, например A4. Сейчас это реализовано так:
int val = analogRead(A4); Serial.println(val);
И все хорошо, и мы получаем нужное нам значение. Но в программе где идет это считывание это немного медленно, затем я изучил это: https://habr.com/post/141442/ — тоже хорошо, но там не раскрыт мой главный вопрос на сегодня.
Изучая регистры DDRD, PORTD, PIND мы можем установить тип input/output и установить состояние low/high на нужном нам пине, а так же можем считать эти состояния при установленном типе input, где если на пине будет 5V это будет HIGH. Но задача не считывать значения Digital пинов, а считать значение Analog пинов, как это делает функция analogRead.
Сейчас я указываю через регистр DDRС состояние input вот так: DDRC &= ~(1<<PC4)
Затем я пытаюсь считать с регистра PINС данные так: int8_t pin = (PINC & (1<<PC4))
И получаю либо 0 либо 1 в зависимости от напряжения на аналоговом пине, выше 2.5 или ниже. А как получить, например, тоже значение как получает analogRead 0-1023 ?
Поискав в сети, ничего не нашел и прошу помощи куда копать. Конкретно моя задача состоит в том, чтоб внедрить в CNC шилд датчик температуры, изначально в исходниках нет ни единого упоминания об этом по этому я принялся написать этот код. Сейчас думаю что это должно как-то решаться прерыванием, считываем биты в буфер, затем переводим в нужные значения.. но вот тут я и встал колом, как это сделать :-) А может и вообще не так надо делать, а как-то иначе...
А что такое и для чего необходимо по-Вашему мнению прерывание?
так как я сегодня добрый, привожу код analogRead из файла
с:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\wiring_analog.c
Этож без прерывания.
Первая ссылка по запросу аvr adc interrupt дает полную программу ацп на прерываниях
http://www.avr-tutorials.com/adc/utilizing-avr-adc-interrupt-feature
А если добавить к запросу слово arduino....
я ответил на четко сформулированный вопрос, не более и не мение
И получаю либо 0 либо 1 в зависимости от напряжения на аналоговом пине, выше 2.5 или ниже. А как получить, например, тоже значение как получает analogRead 0-1023 ?
название ветки тоже читал и подозревал, что хочет автор.
но выложив полный расклад, я бы "нарушил уставы форума"...
Вы не первый. Там у автора хорошая травка была:
Нельзя ли поточнее пнять для чего Вам это надо? Через прерывания? Чтобы отсчёты делать со строго определённой частотой? Или по какому-то событию? Для чего?
Если Вы просто хотите ускорить analogRead, то по Вашей ссылке первый же пример кода это делает. Самый первый. Показывать правда будет "цену на овёс", но зато быстро. А ускорить analogRead без потери точности не получится. Она аппаратно такая.
В программе обрабатываюся Gcode данные отправляемые по serial порту и очень важно чтоб не было задержек в месте чтения analogRead. Мне понравился способ использующий константы тем, что они достаточно быстро меняют состояние пинов, раз константы быстрее digitalWrite, я предположил что если они быстрее и analogRead.
Можете подсказать, использование кода с хабр хорошее решение или плохое?
Можете подсказать, использование кода с хабр хорошее решение или плохое?
Не бывает абсолютно хороших решений (абсолютно плохие - бывают). Любое решение чем-то хорошо, чем-то плохо.
Вам ведь постом выше уже написали, что если для Вас главное - это скорость, то решение хорошее, а если главное - точность, то решение плохое.
В программе обрабатываюся Gcode данные отправляемые по serial порту
пусть меня поправят более знающие - но вот эта фраза сразу показывает, что большая скорость вам не нужна. Если в программе что-то принимается по Сериал, она по определению не быстрая и обычный analogRead тут вполне подойдет
Можете подсказать, использование кода с хабр хорошее решение или плохое?
Хорошее или плохое для чего? Чтобы работало быстро и "что-то такое показывало" - используйте. Если же Вам не всё равно, что показывает, то там очень большая потеря точности. Ещё раз говорю, без потери точности Вы analogRead сколько-нибудь существенно не ускорите.
В программе обрабатываюся Gcode данные отправляемые по serial порту
пусть меня поправят более знающие - но вот эта фраза сразу показывает, что большая скорость вам не нужна. Если в программе что-то принимается по Сериал, она по определению не быстрая и обычный analogRead тут вполне подойдет
Так кажется на первый взгляд, дело в том что команды могут приходить по сериал в момент их уже выполнения, там асинхронный подход, типа много задачность, всегда слешаем сериал порт даже в момент шевеления двигателями и всегда слушаем пины на входящие сигналы, вдруг кнопка нажата.
Вернемся к датчику, напряжение высокого сигнала там 2.5 т.е полагаю оно и должно быть опорным, а все что выше это 1023. Нужно считать данные с порта в диапозоне этих значений 0-2.5. И мне действительно нужна точность и скорость два в одном. Для точности можно использовать тот же буфер и после искать среднее значение за последние, скажем 10 итеракций чтения порта. Пример выше по ссылке дает уже достаточные представления о работе analogRead на прерываниях, как к этому добавить еще опорку 2.5 использовать analogReference() ?
Не знаю, что он Вам даёт, но 1) там нет никаких прерываний и 2) выше Вам привели просто текст функции analogRead - он не быстрее и не медленне - это сам analogRead и есть.
Не знаю, что он Вам даёт, но 1) там нет никаких прерываний и 2) выше Вам привели просто текст функции analogRead - он не быстрее и не медленне - это сам analogRead и есть.
analogReference(EXTERNAL), на вывод AREF подать внешнее опорное напряжение 2.5 вольт
Евгений опередил )))
Так кажется на первый взгляд, дело в том что команды могут приходить по сериал в момент их уже выполнения, там асинхронный подход, типа много задачность, всегда слешаем сериал порт даже в момент шевеления двигателями и всегда слушаем пины на входящие сигналы, вдруг кнопка нажата.
Прием стоки из 10 символов на скорости 9600 занимает 12.500мс, а выполнение analogRead() - 0.112мс, т.е. в 100 с лишним раз меньше.
...И мне действительно нужна точность и скорость два в одном...
Точности arduino для моей задачи полностью хватит. Просто я подумал что при данных модификаций точность падает ниже чем было до.
А работает все на скорости 115200.
Точности arduino для моей задачи полностью хватит. Просто я подумал что при данных модификаций точность падает ниже чем было до.
Правильно подумал. Так как написано по Вашей ссылке точность падает с 2 LBS до 5.
Решил все же использовать функцию analogRead в своем приложении, но при компиляции есть ошибка.
Затем я заменил A4 на просто 4, что работает в обычном проекте (стандартном main(); loop();) компиляция прошла, но на выходе чтения я получаю 0, хотя там есть значения.
Решил все же использовать функцию analogRead в своем приложении, но при компиляции есть ошибка.
попробуйте в начало файла .c добавить
#include <Arduino.h>
попробуйте в начало файла .c добавить
#include <Arduino.h>
А нет, ошибка присутствует. При использовании числа 4, вместо A4. На выходе функции по прежнему 0. Думаю где-то константы прописывают Input/Output на этот пин, буду читать код...
Попытайтесь использовать номер 18.
Попытайтесь использовать номер 18.
Не работает.
Вот пробую такой скетч:
Значения на выходе в районе 450, ну как и должно быть.
Вставляю тот же самый код в нужное место из исходников https://github.com/grbl/grbl то не работает, на выходе 0.
Место, в которое вставляю там, практически сразупосле вывода служебной информации типа версии прошивки и прочего, когда программа готова принимать данные с Serial порта. Прошманал все места, не могу найти причину, почему не считывает данные с порта. Порт в состоянии input, т.е DDRC Показывает нули.
adrusha,
ничего, акромя глума и бесполезных попыток что-то угадать здесь не будет пока Вы не поймёте простую вещь: код надо показывать целиком, а не куски и огрызки. Под целиком я имею в виду именно целиком, со всеми там лупами и сетапами.
Сделайте маленький код, в котором видна проблема (в большом ковыряться охотников мало). Уберите нахрен работу с регистрами, которой Вы не понимаете. Сделайте со штатным analogRead - и выложите его целиком. И еще, что и как подключено к ардуине? Что-то ж она у Вас измеряет. Схему и фото в студию
Только так Вам что-то разумное скажут.
У меня есть вот такая плата GRBL контроллера на ардуино:


прошивку (программу) я взял с сайта https://github.com/grbl/grbl и закгрузил на плату, все прекрасно работает и Gcode команды выполняются. Но есть необходимость подключения термистора ntc на 100k. Я нашел свободные ноги: A4, A5 и хочу использовать их для получения данных температуры, накидал схему такую:
И загрузил следующий скетч для настройки и проверки работы термистора на нужном порту:
Скетч исправно работает и данные получает, я доработал код и перевожу данные 0-1023 в температуру цельсия. После чего я доработал код таким образом чтоб на незанятом выходе D11 был шим сигнал в зависимости от температуры 0-255. После чего в исходники grbl в файл spindle_control.c вставил нужные параметры и проверил PWM сигнал оцилографом на выходе, там было то, что ожидалось. После чего я приступил к правке кода чтоб добавить туда код который прикрепил выше, с датчиком температуры, но данные с A4 не получает, приходит 0, хоть analogRead хоть чем. Но когда я подаю 5В на ногу, и смотрю в PINC то там 1 в случае высокого сигнала на ноге и 0 в случае низкого. Т.е пин работает как входящий, но почему-то не читает данные с него в виде 0-1023.
Уберите нахрен работу с регистрами, которой Вы не понимаете.
Не могу, вся программа GRBL заточена под это и работает на них. Раньше я писал простые программы, но когда начал изучать код пришлось освоить понимание этих регистров и их масок и как они применяются &=~ и |=
Вопрос решен. Добавил это после int main(void)
Выяснил это так, я не нашел функции setup в исходниках grbl которая как позже стало известна вызывается из int main() в которой помимо прочего были и выше указанные константы, которые за что-то от вечают, возможно за какие-нибудь тайминги. В grbl они нигде не прописаны, а прописав их сразу функция analogRead стала получать свои значения. Позже изучу за что они все же отвечают. Вопрос считаю закрытым, догадался сам, всем спасибо за участие.
Ну да. В ардуиновском main кроме setup ещё init вызывается. Из него можно взять правильную инициацию ацп. Догадался это круто. А можно было просто даташит почитать. Там всё расписано.
Я не силен в таком языке програмирования, для меня было новым все что поднималось в этой теме. Но в жизни пригодится все, буду знать. Я же ранее не имел представления как работает это все, думал что все мол просто, функция запрашивает данные с порта, тот ему отвечает, а нет, там еще инициализация ацп нужна, которой не было в grbl просто потому что не нужна. Но сейчас встали другие вопросы, связанные с PWM буду их решать, там частота слишком высокая, не стандартная... Но результат появился, правда скетч на 99% вышел )))
Ещё раз. grbl написан не для среды ардуино. Все ваши попытки использовать функции ардуино будут наталкиваться на отсутствие правильной инициализации железа под функции ардуины. С АЦП вы уже наступили на эти грабли. Что бы добавить функции в grbl программу нужно использовать возможности програмирования микроконтролеров AVR. Это немного шире чем ардуино. Нужно изучить существенно больше.
Ещё раз. grbl написан не для среды ардуино. Все ваши попытки использовать функции ардуино будут наталкиваться на отсутствие правильной инициализации железа под функции ардуины. С АЦП вы уже наступили на эти грабли. Что бы добавить функции в grbl программу нужно использовать возможности програмирования микроконтролеров AVR. Это немного шире чем ардуино. Нужно изучить существенно больше.
Странно, но на самом сайте написано что для Arduino.
На проблемы АЦП я наступил только потому, что они в базовой прошивке grbl просто не нужны, нет необходимости считывать данные с аналог портов. Но программа написана и работает прекрасно. А еще говорят grbl не работает по UNO для 4 осей, но ничего, это мы тоже исправили, теперь 4 оси + датчик температуры и выходы нагрева. Обычная дешевая плата превратилась в плату 3D принтера.