Используем Энкодер
- Войдите на сайт для отправки комментариев
Вот решил закинуть в этот форум тему про энкодер, которая я думаю будет интересна новичкам да и не только.
энкодер — устройство, предназначенное для преобразования угла поворота вращающегося объекта (вала) в электрические сигналы, позволяющие определить угол его поворота. ПРоще говоря вращая ручку энкодера мы периодически замыкаем и размыкаем группу контактов. Таким образом получаем импульс. Ручку энкодера можно вращать бесконечно с любой скоростью, у него нет крайнего положения как у переменного резистора. Это значительный плюс. так как мы можем регулировать чувствительность программно, а не аппаратно. Такой прибор ввода стоит (например) в современных автомагнитолах в качестве регулятора громкости. Кроме регулировки громкости он можетбыть использован как поворотная кнопка для перемещения по меню. Многие энкодеры оснащены доп. контактами которые работают как обычная кнопка без фиксации.
Я такой прибор использовал для регулировки скорости вращения вентилятора авто-печки, т.к. родной переключатель сломался.
Где взять простой поворотный энкодер. Его можно купить в магазине радиодеталей. В моем городе с этим проблема, нужно заказывать. Поэтому я взял энкодер из компьютерной мышки. Вполне точен и надежен.
вот схема его подключения:
средний подключаем на землю, а два боковых по схеме к ножкам МК, и через резисторы подтягиваем на +5.
Ну и код для ардуины для управляения яркостью светодиода D:
int brightness = 120; // яркость LED, начинаем с половины int fadeAmount = 10; // шаг изменения яркости LED unsigned long currentTime; unsigned long loopTime; const int pin_A = 12; // pin 12 const int pin_B = 11; // pin 11 unsigned char encoder_A; unsigned char encoder_B; unsigned char encoder_A_prev=0; void setup() { // declare pin 9 to be an output: pinMode(9, OUTPUT); // устанавливаем pin 9 как выход pinMode(pin_A, INPUT); pinMode(pin_B, INPUT); currentTime = millis(); loopTime = currentTime; } void loop() { currentTime = millis(); if(currentTime >= (loopTime + 5)){ // проверяем каждые 5мс (200 Гц) encoder_A = digitalRead(pin_A); // считываем состояние выхода А энкодера encoder_B = digitalRead(pin_B); // считываем состояние выхода А энкодера if((!encoder_A) && (encoder_A_prev)){ // если состояние изменилось с положительного к нулю if(encoder_B) { // выход В в полож. сост., значит вращение по часовой стрелке // увеличиваем яркость, не более чем до 255 if(brightness + fadeAmount <= 255) brightness += fadeAmount; } else { // выход В в 0 сост., значит вращение против часовой стрелки // уменьшаем яркость, но не ниже 0 if(brightness - fadeAmount >= 0) brightness -= fadeAmount; } } encoder_A_prev = encoder_A; // сохраняем значение А для следующего цикла analogWrite(9, brightness); // устанавливаем яркость на 9 ножку loopTime = currentTime; } }
Источник: http://cxem.net/arduino/arduino8.php
На сайте http://www.compcar.ru/forum - можно найти ветку по использованию энкодеров, там в программной части применяется метод прерываний, что дает еще больше возможностей.
еще можно анемометр сделать, позже выложу его конструктив и скетч
А какое разрешение у энкодера из мыши?, ну то есть он может считывать один поворот или, например, каждые 30 градусов?
Честно я не знаю как это точно проверить, так как документации нет но по наблюдениям. Он имеем 12 положений. в полном обороте. Вроде получается 30 градусов одно положение 360 соответственно 12.
Я проверял светодиодами, на A и B вешал светодиоды и крутил насчитал 12 импульсов за полный оборот. Сейчас достал еще два мышинных энкодера посмотрю что с ними отпишусь.
Угадал с 30. Я правильно понял, что выход B дает информацию о направлении вращения?
Тут суть такая.
Устанавливаем положение когда ни один светодиод не светит. Затем вращаем по часовой стрелке, очень медленно, сначало зажигается светодиод на выводе B затем на половине одного щелчка зажигается светодиод на выводе A, затем щелчек оба светятся еще пол щелчка перестает светится B и затем оба гаснут. Ну и так в обратном направлении получаем цикл наоборот - оба светятся, один гаснет затем другой. Получается что при вращении по часовой первым зажигается B а против зажигается A. как-то так.
Вот здесь есть программа для управления компьютером с помощью энкодера
ПРограмма подразумевает программную переделку модуля ардуино, так как расчитана на carduino - что не есть хорошо на мой взгляд?
А по подробней про переделку можно?
Тут суть такая.
Устанавливаем положение когда ни один светодиод не светит. Затем вращаем по часовой стрелке, очень медленно, сначало зажигается светодиод на выводе B затем на половине одного щелчка зажигается светодиод на выводе A, затем щелчек оба светятся еще пол щелчка перестает светится B и затем оба гаснут. Ну и так в обратном направлении получаем цикл наоборот - оба светятся, один гаснет затем другой. Получается что при вращении по часовой первым зажигается B а против зажигается A. как-то так.
У меня так под linux'ом получилось :), правда не под arduino, а под арм9 9260 :).
На этом и строится анализ, того в какую сторону прокрутка идет? А то я тоже долго иискал, как заполучить направление вращения, всякие данные какие-то ожидал :).
>Его можно купить в магазине радиодеталей. В моем городе с этим проблема, нужно заказывать.
Это вам повезло.
>Поэтому я взял энкодер из компьютерной мышки.
Вы не представляете каких каких гимороев избежали этим решением. В мышках, обычно, используются оптические энкодеры. И они действитеьльно довольно точны. Недорогие же "из радиомагазина" являются механическими.
У механических есть такое принеприятнийшие свойство как "дребезг контактов". Это когда на "пограничном сотоянии" (вот вот прощелкнимся в следующие положение) он начинает выдвать очень много импульсов как-будото ты его "быстро крутишь туда сюда" по одному из каналов.
В результате ты получаешь либо "мусор" и понять куда он крутится вообще не возможно, либо, если ты начинаешь использовать "антидребезг" (игнорировать изменения которых приходят "слишком быстро"), то пропускаешь настоящие щелки при быстром кручении.
Механический энкодер был моей "первой игрушкой с ардуиной" и за несколько недель я так и не смог добится "идеальной работы", только "приемлимой".
Кстати два 10K резисторов в вашей схеме,IMHO, не обязательны. Их можно выкинуть, так как подобные резисторы, как раз для таких случаев, на 20K уже имеются внутри самого микроконтроллера. Нужно только их "подключить".
"Включить" их добавив такой код (после конфигурации портов на INPUT).
Подробней про это почитать можно тут arduino.ru/Tutorial/DigitalPins раздел ""Подтягивающие (нагрузочные) резисторы".
Либо в оригинале www.arduino.cc/en/Tutorial/DigitalPins. Если можете - лучше читать в оригинале. В переводе, к сожалению, они переведены просто как "подтягивающие", при это потеряно что "подтягивающие бывают" двух видов: pullup (подтягивающие к питанию) и pulldown (подтягивающие к земле). Котроллер имеет встроенные только pullup. В данном случае они нам "подходят".
Кстати, лично мне, понять принцип работы энкодера, как определять "куда крутится" сильно помогла статейка
easyelectronics.ru/avr-uchebnyj-kurs-inkrementalnyj-enkoder.html
В переводе, к сожалению, они переведены просто как "подтягивающие", при это потеряно что "подтягивающие бывают" двух видов: pullup (подтягивающие к питанию) и pulldown (подтягивающие к земле).
Спасибо, подредактировал перевод.
>Спасибо, подредактировал перевод.
Оперативно. :) Только тогда нужно еще чуть-чуть поправить. :)
Оригинал: These built-in pullup resistors
Текущие перевод:Микроконтроллер Atmega имеет программируемые встроенные подтягивающие резисторы 20 кОм.
Как видимо довольно важная информация о том какие именно подтягивающие резисторы имеет Atmega - потерялось.
Как видимо довольно важная информация о том
какие именно
подтягивающие резисторы имеет Atmega - потерялось.
И еще раз спасибо.
Ребят, а как сделать так, чтобы при отключении питания контроллер запоминал состояние на котором сейчас находится светодиод?
http://arduino.ru/Reference/Library/EERPOM
Спасибо, но запись в EEPROM имеет ограниченое количество циклов если не ошибаюсь то 100 000. А если я правильно понимаю, то нужно записывать значение после каждого изменения? Уж очень быстро износится память... Крутить много в моем проэкте будут.
Энергонезависимую память без ограничений ресурса записи еще не изобрели.
Поэтому выхода два:
1. Оптимизировать использование имеющиюся EEPROM (менять ячейки куда пишеш, что-бы подольше растянуть удовольствие).
2. Выносить куда-то наружу: SD, внешние flash микрухи, механические ячейки памяти и т.п.
Я вот как подумал, считать значение с памяти, если не равно считаному выждать пять секунд и перезаписать. Выдержка в данном случае будет имет смысл, так как экономить ресурс будет EEPROM. Но и подвох в том, что если будут продолжать крутить валкодер то через 5 секунд снова пройдет запись, и как только прекратят крутить тогда последняя запись, то есть плюс еще одна.
Что-то не как не соображу как это будет выглядеть в коде, помогите пожалуйста.
Есть еще вариант обхода проблемы ресурса eeprom - более сложный, но и перспективный в плане освоения железа: контролируйте напряжение питания и как только оно начнет падать - производите запись в eeprom. На просторах Интернета утверждается, что время записи нескольких байтов в eeprom меньше, чем продолжительность переходного процесса при отключении питания. Можно подстраховаться и поставить на входе питания конденсатор, который дополнительно растянет этот процесс.
Вот как-то так.
еще можно анемометр сделать, позже выложу его конструктив и скетч
Очень интересно было бы посмотреть...
добыл энкодер, сижу дёргаю, балуюсь.. дребезг контактов жуткий.. по часам дуины отследил продолжительность замыкания контактов, получилось 7-25мс в зависимости от скорости вращения. а вообще хотелось попробовать воплотить на нём идею жестов. т.е. быстро вращать это одно, медленно-другое, подёргать взад-вперёд на разных скоростях ещё несколько жестов.. и попутно возник вопрос, а получится ли перенести хотя бы определение скорости и направления в аппаратную часть из кода? Что бы повесить итоговую схему на один аналоговый вход и заодно избавиться от довольно ресурсоёмкой части кода.
как скорость определить в общем то понятно, это RC цепочки, а как быть с направлением? по идее нужно оттягивать среднее напряжение в 2.5В разными направлениями вращения либо к земле, либо к +5. и в зависимости от скорости вращения получать разные отклонения от 2.5В...
добыл энкодер, сижу дёргаю, балуюсь.. дребезг контактов жуткий..
Тоже сталкивался с этой проблемой. Честно говоря это единственный девайс который я так и не "победил". Ну то есть определял вращения, но при быстром прокруте - слишком много ложных сработок было. Либо, если боротся с дребезгом, пропусков и как результат - неправильное определение направления.
Правда это был мой самый первый опыт с ардуиной. Возможно стоит сделать еще один "подход к весу". Уже с "высоты опыта".
а вообще хотелось попробовать воплотить на нём идею жестов. т.е. быстро вращать это одно, медленно-другое, подёргать взад-вперёд на разных скоростях ещё несколько жестов..
Апплодирую. Действительно очень интерестная идея. Прийдется, на выходных, искать свой энкодер в загашнике :)
Можно даже сделать несколько градаций. Задавать "ритм" каким-то писком или миганием. Типа делаешь щелчок на каждый писк - одно, на каждый второй - другое, на каждый третий - третье.
Но это, конечно, уже после "победы дребезга" и реализации вашего варианта.
и попутно возник вопрос, а получится ли перенести хотя бы определение скорости и направления в аппаратную часть из кода?
Смотря что вы понимаете под "аппаратную". Если "повесится на прервывания" - думаю это даже единственно возможный путь. Если "что-бы сам и считал".... тоже интерестная задумка. Что-то смутно-подобное (аппаратный счетчик длины импульсов) видел в книге "Arduino Cookbook" Michael Margolis. Издательство O'REILYY Глава 18.8 "Measuring Pulses More Accurately". Но совсем не уверен. Возможно это "другая опера".
А вообще, опять, вы интерестный вопрос задали. Нужно подумать. Может и получится его выдать за какой-нибудь i2c. Подобно тому как со сдвиговыми работают, хотя они и не i2c :)
Что бы повесить итоговую схему на один аналоговый вход и заодно избавиться от довольно ресурсоёмкой части кода.
Ну analogRead тоже, вроде, не сильно быстрая функция :( Плюс к этому, кроме "родного дребезга" еще добавится еще и шум АЦП. Плюс все прелести "аналога". Зависимость от температуры и т.п.
Хотя, все-таки, что-то в этом есть. Возможно и получится. Скорость определять - проблем не должно быть. Если вы можете "поймать каждый щелчок" и благодаря цепочкам, по напряжению, понять "куда он был сделан", то узнать "скорость" уже не проблема. millis()-prevMillis. Главное что-бы небыло "пропусков" и "ложных".
Блин. Вообщем "зажгли исследовательский зуд" :) Жаль только что прямо сейчас времени на это нет :(
прерывания прям щас врятли осилю, потому буду думать в сторону получения аналогового сигнала. analogRead может и не быстрая, но читать её можно будет не раз в 5-10 мс как контакты, а раз в 20-50мс. точность отслеживания каждого щелчка на аналоге конечно исчезнет из-за интегрирующих цепочек, но из за них же о дебезге можно будет вообще забыть. АЦП шумит, но даже при этом его разрешающей способности достаточно для определения 0,1В.
Хотя под мою задумку возможно проще всего будет растиранить какой нибудь микродвигатель без стабилизатора... он то точно может смещать напряжения в зависимости от скорости и направления вращения..
Не стоит боятся прерываний. "повесится на прерывание" не сложней чем переключить пин на выход.
http://arduino.ru/Reference/AttachInterrupt
У них только один "минус". Ног с прерываниями мало (если у вас не мега - всего две таких ноги), а ситуаций где их очень удобно использовать - много :)
И ух IMHO всяко проще чем с аналогом что-то мудрить. Просто не бойдесь слово "прерывание". Например если вы сделаете attachInterrupt(0,myHandler,FALLING) это значит, всего лишь, что вы сказали контроллеру "вызови мою функцию myHandler, когда цифровой пин 2 перейдет из состояния 1 в 0". И все. Как только на D2 появится логически 0 - вызовется ваша функция. Только не нужно уже самому опрашивать пин, запоминать прошлоего его состояние. Все это уже будет делаться "железом".
В "теории", на прерываниях вообще все очень просто.
Повесили канал A, на пин 2. Сделали attachInterupt(0,pinAHandler,RISING);
Красные стрелки это момент когда вызовется функция pinAHandler, в зависимости от того в какую сторону крутим ручку.
В самом функции pinAHandler прочитали пин на который подсоеденан канал B. Если там 1 - значит щелкнули против часовой, если 0 - значит по часовой (ну или наоборот, смотря как подключили A,B).
Но это "в теории все просто". В реальности пол дня сегодня промучился с энкодером, так и не добился нифига. Какая-то карма у меня на энкодеры.
Когда канал A падает в ноль, по идее на пине B должно быть какое-то четкое значение. Причем одно и тоже если энкодер крутишь в одну сторону. А у меня выходит "от фазы луны". Может 1 там быть, а может и 0 (хорошо что не 3 :) Как будто фронты A и Б каналов - сопадают.
Был-бы осцил что-бы посмотреть "что там происходит" :(
а если считывать состояние каналов одновременно - каким-нить регистром - может и пропадут временные неувязки ?
....между фронтами каналов
считывать одновременно - уж потом анализировать ?
на моей технике так и было воплощено.... работает до сих пор....
а если считывать состояние каналов одновременно - каким-нить регистром - может и пропадут временные неувязки ?
Тоже пробовал. Напрямую PINE читать (у меня мега) - такая же фигня :(
Хуже того. Даже когда вешаюсь на attachIntterput(0,myHandler,RISING); и первой же строчкой в обработчике пытаюсь прочитать второй пин (который как бы и вызвал прерывание) - там тоже может быть "что угодно", а не только 1, как ожидается. И digitalRead-том и напрямую из порта.
С горя взял готовую либу http://www.pjrc.com/teensy/td_libs_Encoder.html
Так зарабтоала. Зараза. (значит не в железе дело). Подшумливает, но "терпимо пашет".
У меня уже комплекс неполноценности из-за этого энкодреа. Элементарная штука, три сосны, намного более сложные вещи укрощали. А тут - никак не могу оседлать :(
у меня щас вот так по первому эксперименту, если ооооченнь медленно вращать, то все щелчки на диодах последовательно видны, а декодированные направления на звуке (нагляднее чем в сериал писать). а при нормальном вращении почему то только одно направление вращения серьёзно косячит (~30% мимо). Нормального пишущего осцилографа у меня нет (отдельные фронты и дребезг погрядеть), но всё же склонен считать, что все проблемы в механике.
Продам энкодер AG100-412400000000 новый или б/у
Что-то как-то... Захотелось самому "побороть" энкодер. Вроде получилось. Правда, только с преруваниями. Критикуйте, обсуждайте, пользуйтесь:
Заодно индикатор SC2004CULB-XH-GS опробовал. 20х4 строки, куплен в Мегаэлектронике всего за 111р.
Что-то как-то... Захотелось самому "побороть" энкодер. Вроде получилось. Правда, только с преруваниями. Критикуйте, обсуждайте, пользуйтесь:
Спасибо. Попробуем как только время будет. Прийдется чуток похмурить мозг какие состояния вы рассматирваете. Ну то есть вообщем-то "понятно какие", просто попытатся понять их "по коду". Что-бы "просто работало" - мне пало. Хочется 100% понимания (а сам энкодер, в данный момент мне вообще не нужен :) Но вы явно пошли по пути "запоминаем предыдущие состояние и сравниваем с текущим". То есть какие-то отголоски "Кода Грея". Подход хорошо (и возможно даже более правильный, меньше зависит от конретного энкодера), но меня мучает почему-же "тупой подход" не работает: ловить фронт сигнала, смотрететь на второй пин и понимать "куда крутим". Чуть позже выложу свой скетч (не сохранил, ну да там всего пара строк, напишем заново).
Блин, ну почему всегда что- то не так. Взяли индикатор 20х4, а у меня 16х2. Ладно, исправил под свой, откомпиллировалось нормально,а загрузка в Arduino завершается ошибкой и рекомендацией обратиться arduino.cc для поиска решения. Ну, не разумею я по ангельски...
Но вы явно пошли по пути "запоминаем предыдущие состояние и сравниваем с текущим". То есть какие-то отголоски "Кода Грея". Подход хорошо (и возможно даже более правильный, меньше зависит от конретного энкодера), но меня мучает почему-же "тупой подход" не работает: ловить фронт сигнала, смотрететь на второй пин и понимать "куда крутим". Чуть позже выложу свой скетч (не сохранил, ну да там всего пара строк, напишем заново).
Я сначала пытался без запоминания предыдущего состояния, но не получилось побороть дребезг - не было стабильности счета. Попробовал библиотеку - работает, но мне показалась она жирновата для одного энкодера. 2 очень похожих прерывания - некрасиво. Сделал с одним обработчиком и с запоминанием состояния - получилось, но не нравился "switch case" - сделал определение, какой вывод сработал, через "xor". Совсем перейти на битовые операчии тоже не получилось, но выложенный вариант более-менее понравиля :) Логика:
Ваш вариант мне будет интересен
Вот, причесал код слегка. Оптимизироал прерывание.
Самое интересное оказалось то, что ">>2" (сдвиг на 2 бита) компиллируется в 2 16-битных однобитных сдвига, а деление на 4 - в 2 8-битных сдвига и код сокращается :)
Вот результаты компилляции:
Ну все-таки не зря мне тут Код Грея примерещился :)
Только табличка "не совсем полная". Опущены варианты где "действие" - 0. Например когда и "пред" и "текущ" - 00 00 или 11 11
А switch можно еще по другому "обойти" (не скажу что "так лучше", просто "еще один вариант"). Сочетание "пред" и "текущь" расмотреть как "индекс массива". А в сам массив положить колонку "действия". 1, -1, или 0.
Тогда запоминать старое значение будем так:
Определим массив действий примерно так
Тогда саму позицию мы будем апдейтить вообще "просто до крика"
То есть сам хендлер у нас будет "вообще тупым"
Это в "теории", в практике... ну должно работать идентично вашему подходу (это вообщем-то "он и есть", только "посчитанные заранее"). Но мог где-то в выписывании логической конструкции и хомутнуть :)
но мне показалась она жирновата для одного энкодера.
Вы сравнивали скомпиленный вариант или "на глаз"? Просто мне показалась что автор библиотеки как раз "повернут на оптимизации" (я так понял что он ставил целью в тиньку втиснутся). Сам обработчик даже ассемблерной вставкой делал.
Хотя конечно "за универсальность" возможно и пришлос ему заплатить (на разных пинах может работать, несколько энкодеров) и т.п. Но там, бегло успел заметить, возможнго еще лишние куски библиотеки можено дефвайнами поотключать. Они специально ее все в .h запихнули для подобных финтов. .c - пустой.
На глаз.
Сейчас посмотрел по результатам компилляции (размер):
Совсем без энкодера (в цикле newpos++): 2958 (+0)
С библиотекой Encoder.h (с прерываниями, 1 энкодер): 3896 (+938)
Мой вариант: 3330 (+372)
Ну все-таки не зря мне тут Код Грея примерещился :)
Только табличка "не совсем полная". Опущены варианты где "действие" - 0. Например когда и "пред" и "текущ" - 00 00 или 11 11
Не зря :) Я намеренно исключил варианты 00 00 и 11 11, потому что они не должны возникнуть в прерывании (в теории) и 00 11 и 11 00, потому что одновременно поменяться уровни тоже не должны. Вернее, такая ситуация возможна, но только при очень быстром вращении, когда следующий импульс прийдет до окончании обработки прерывания. Я поэтому и бился за укорачивание прерывания.
А switch можно еще по другому "обойти" (не скажу что "так лучше", просто "еще один вариант"). Сочетание "пред" и "текущь" расмотреть как "индекс массива". А в сам массив положить колонку "действия". 1, -1, или 0.
Массив - штука опасная. volatile нельзя, много рабочих регистров съест, локально в теле прерывания - растолстеет прерывание.
Это в "теории", в практике... ну должно работать идентично вашему подходу (это вообщем-то "он и есть", только "посчитанные заранее"). Но мог где-то в выписывании логической конструкции и хомутнуть :)
Я смотрел ассемблерный код у конструкций типа "вложенные ифы" - все очень коротко и оптимально. Я бы на асме именно так написал ;)
Сделал с массивом.
размер 3358
в врианте volatile char action[] - 3306
Попыткарасположить массив в PROGMEM не увенчалась успехом :(
Массив - штука опасная. volatile нельзя, много рабочих регистров съест, локально в теле прерывания - растолстеет прерывание.
Погодите, а разве volatile не означает указание не использовать регистры? То есть "с точностью до наоборот" - будем экономить их (потерей скорости на чтения памяти). Да и проблем с volatile массивами никогда не замечал (хотя пользовал)
Во вторых а зачем нам тут volatile? Его же использовать нужно если мы изменяем переменную в конкурентном потоке, а тут мы его только читаем. Заполняем - один раз.
volatile - не оптимизировать.
Собственно, поборол :) Компиллятор располагает массив в памяти программы при использовании модификатора PROGMEM.
Такой вариант:
Размер скетча 3308 (+350)
Код мне понравился :)
>volatile - не оптимизировать.
Ну да. То есть не использовать регистр. Почему же тогда "много рабочих регистров съест"? Не, я вам верю. честно говоря я ассемлер последний раз щупал во времена MS-DOS, поэтому "оценить" могут только длину листинга что вы приводите :(
>enc=(enc>>2) | (PIND & 0b1100)
Какой хитрый, однако человек :) Специально "старые биты" хранит в младших разрядах что-бы "взорвать мозг" :)
P.S. я понял что "& 0xF" съекономить решили. просто инерция мышления что "новое в младших битах"
>volatile - не оптимизировать.
Ну да. То есть не использовать регистр. Почему же тогда "много рабочих регистров съест"? Не, я вам верю. честно говоря я ассемлер последний раз щупал во времена MS-DOS, поэтому "оценить" могут только длину листинга что вы приводите :(
Тоже "инерция мышления". Откуда-то помнится, что память у авр "регистровая". Смотрел, как работает модификатор.... никак. Переменная в озу, копируется в рабочий регистр, когда требуется. Так что про регистры - я неправ. Но ради экономии памяти я не хочу там хранить константы :)
С ассемблером знаком - начинал программить на нем для attiny2313. В ассемблере видно, что откуда берется, ну и длина кода - покзатель скорости. Кроме того, там ремарки есть, где написано, что в этой команде деется. Я добивался получения именно строки "LPM R30,Z Load program memory", что значит, что данные берутся непосредственно из флеша
>enc=(enc>>2) | (PIND & 0b1100)
Какой хитрый, однако человек :) Специально "старые биты" хранит в младших разрядах что-бы "взорвать мозг" :)
:)))
Я добивался получения именно строки "LPM R30,Z Load program memory", что значит, что данные берутся непосредственно из флеша
А чтение флеша не является более медленной операцией чем чтение из памяти? (я не спорю, просто - не знаю).
Является. Вся жизнь состоит из компромисов. А если серьезно, то загрузка данных из оперативки - 2 такта, из флеша - 3 такта. Можно пренебречь :)))
"Меняю 15 байт оперативки на 16 тактов процессора. С доплатой :) "
Можно еще извратится и весь массив упихарить в 4 байта (по два бита на состояние). Сомневаюсь правда что при этом выиграем в скорости так как "вытаскивать action будет сложней" (сдвиг+маска+вычитание). Но тому кто будет сопровождать наш код - добавим пару седых волос точно :)
Нет, неправильно. 15 байт оперативки на 15 байт флеша и 1 такт процессора. В прерывании читается только 1 элемент массива!
Неа...
1. флеш у нас занят в любом случае. Только с PROGMEM не происходит его копирование в оперативу, а без - происходит. Иначе где хратися этот массив когда питание выключено?
2. Флеша все-таки 16-ть байт, а не 15-ть. Размер массива 16-ть. (просто когда юзаем PROGMEM то оператива все-таки расходуется. предположил что 1 byte на ссылку, если больше - то выигрыш еще меньше). Но так как эти "16-байт флеша" у нас находятся по обе стороны уравнения - я их "сократил" :)
3. " В прерывании читается только 1 элемент массива". Ну тут уж так однозначно спорить не получится :) Зависит от того какую точку зрения выбрать. Если смотреть "только на прерывание" - то да. 1 такт. Если же смотреть на более длительные промеждутки времени - то все, таки, выборка всего массива 16-тактов доп. израсходует. Вообще похоже "точно логичного" интервала измерения тут выбрать просто не возможно :) Для "ручного энкодера" - будет ваша мерка более правильной. Если же это будет какой-то энкодер на валу двигателя - нужно будет смотреть сколько тиков в секунду происходит (и сколько в секунду тактов мы расходуем).
Да. Я что-то упустил, что массив есть во флеше в любом случае... Значит вместо 16 байтов оперативки останется 2 (это размер ссылки на флеш). А такты прерывания нужно смотреть "в целом", то есть для всей функции прерывания (без учета входа и выхода прерывания - лень искать).
В целом можно резюмировать, что это "борьба с крошками" и я голосую за первый вариант, потому что оперативку всегда жальче :)