Ну я в начале поставил еще одну (как ты не заметил выше). Я думаю это потому, что он как и в бибилиотеке Rotary использовал пины 2 и 3, а у меня используется только один - 2.
Я бы попробовал еще опрос энкодера через таймер (как деда говорил), но его код очень сложный для меня еще. А как проще сделать я не знаю.
Работает хорошо, но почему то есть "пропуски", не в смысле крутишь и пропустил, а в смысле - 1,2,3,7,8,9 (конечно же меняются самые правые "биты" "дисплея".
И не понятно почему. Ведь на осциллограмме нет дребезга (да и в коде "антидребезг есть"). Как это так?
Мне кажется, что все-же виновником является энкодер (а так как памяти у DSO5102P мягко говоря - маловато, то я просто не могу на осциллограмме это увидеть). Я провел другой эксперимент.
Я опять подключил два канала, стал вращать энкодер медленно с относительно постоянной скоростью (по "тактильному тику") и в момент когда произошло опять "смена значения" (назовем это так), я остановил осциллограмму (это происходит один раз за оборот 360гр). Ниже привожу скрины с осциллографа:
То есть я увидел, что значение "прыгнуло", еще по инерции довернул энкодер (еще один "щелчок") и остановил осциллограмму.
Ну и, честно говоря, мне непонятно - как так то? По осциллограмме вообще не должно быть срабатываний, а в коде есть.
Использовал этот код (комментарии не стал удалять), задержка была 2мс.
Запаял новый (другой уже и тоже новый) энкодер - проблема ушла. Прекрасно работает и с задержкой и без нее (думаю, что это потому что у DSO5102P на мнооого меньше памяти чем у того же DSO5102B (2Mb) и он просто пропускал дребезг). Работает схема только на этом коде (код от komandir'а работает только одно значение (либо только инкремент, либо только декремент):
Не правильно ты дядя Фёдор бутерброд ешь. Его надо колбасой на язык... перевести осциллограф в однократный режим, поставить разрешение микросекунд 200 на клетку, запуск от фронта любого канала, память процентов 25 и крутануть ручку, разок в одну сторону сохраниться и разок в другую. Можно будет увидеть дребезг. Возможно надо развертку по времени ещё уменьшить. Так, что бы на весь кадр только один импульс был. Не надо много импульсов. Не видно ничего.
Не правильно ты дядя Фёдор бутерброд ешь. Его надо колбасой на язык... перевести осциллограф в однократный режим, поставить разрешение микросекунд 200 на клетку, запуск от фронта любого канала, память процентов 25 и крутануть ручку, разок в одну сторону сохраниться и разок в другую. Можно будет увидеть дребезг. Возможно надо развертку по времени ещё уменьшить. Так, что бы на весь кадр только один импульс был. Не надо много импульсов. Не видно ничего.
Это хорошая идея на "отвлечься", энкодер я выпаял, но не выкинул. Отложил в сторону (хотя хотелось по нему молотком! Но молотка дома нет сейчас, да и я сейчас "под шафэ" )) В гараж точно не поеду. Да и хожу "морской походкой" ))
И да, я сейчас именно (видимо трезветь начал) понимаю, что скобки мои были "далеко не на своих местах". Ну чтож, если не помру в ближайшее время от "зеленого змия", то точно завяжу с ним. Ну и с парочкой соседей в общении. Большое спасибо, что хоть на последней отдушине души не бросили в омут.
Я на самом деле удивлен - Почему в решении этого вопроса мне откликнулся помогать только komandir?
Так радоваться надо: диалог - разговор двоих - наиболее эффективный вариант. Когда советчиков много, всегда проявляется эффект лебедя, рака и щуки. Поэтому при эффективном взаимодействии двоих третьему лучше не вмешиваться (сколько бы этих "третьих" ни было).
Хочу поднять тему вот по какому "случаю". Я поменял энкодер и пару-тройку недель все было в шоколаде, но спустя время и поменянный энкодер стал выдавать "то +/то-". Знаю, этого популяризатора ардуино тут не любят, но именно его код заработал отлично. Со старым энкодером:
/*
* Данный код выполнен из примера "Гайвера". Это подключаемый .h файл, который обеспечил стабильную работу энкодера.
*/
#define ENC_A PIN_PD2 // | Первый пин энкодера
#define ENC_B PIN_PC5 // | Второй пин энкодера
volatile boolean state0, lastState, turnFlag;
extern uint32_t number;
// Код по гайверу:
void int0() {
state0 = digitalRead(ENC_A);
if (state0 != lastState) {
turnFlag = !turnFlag;
if (turnFlag) {
number += (digitalRead(ENC_B) != lastState) ? -1000 : 1000;
}
lastState = state0;
}
}
/*
* В мэйн части (основном скетче) написано следующее:
*/
void setup() {
attachInterrupt(0, int0, CHANGE); // | Привязываем функцию int0() к прерыванию INT0 по любому изменению уровня (CHANGE)
sei(); // | Разрешаем глобальные прерывания
pinMode(ENC_A, INPUT_PULLUP);
pinMode(ENC_B, INPUT_PULLUP);
}
Код отлично работает. На "правильность" кода - усмотрение читающих, в моем случае (одно прерывание) он подошел идеально!...
А расскажи зачем там нужен CHANGE ?
Может просто стоит вникнуть в то как работает энкрдер и понять , что за один щелчок он совершает полный цикл переключений ?
Тогда очевидно станет ясно, что RISING/FALLING тупо сократят половину кода прерывания и весь код для FALLING будет выглядеть так:
digitalRead(EncB)?val++:val--;
Поясню как это работает:
Вход в прерывание только по смене состояния пина EncA по заднему фронту сигнала.
Т.е. мы уже знаем, что на пине EncA лог0, мы же в прерывание из за этого и попали.
Теперь нам осталось прочитать состояние пина EncB.
Если там лог1 то инкрементируем счётчик, если лог0 то декрементируем(или наоборот , по желанию).
Борьба с дребезгом отдельная песня.
Можно тот же миллис использовать, чтоб результат опроса учитывать скажем не чаще чем 1 раз в 20мс.
Я предпочитаю делать это аппаратно посредством mc14490
Чего непонятного то ?
Тут идёт проверка на то что было вращение.
Увеличь время на устранение дребезга(в твоём случае на щелчок убитого энкодера и нормально всё будет).
Я делаю так:
EncTick в коде сбрасывается в 0 после использования.
Хм, интересный подход - надо будет попробовать.
По поводу времени на антидребезг - я начал с 2мс (как советовал Командир) и постепенно добрался до 50мс. При этом ситуация не улучшилась... (((( (Может нужно было и дальше увеличивать? Но я побоялся).
ЗЫ: От тактовой это как-то зависит? У меня всего 1МГц от внутреннего генератора...
Как то ты считаешь непонятно.
1млнмкс/8мгц=0.125мкс время одного такта
0.125*256=32мкс время переполнения таймера(без делителя)
С предделителем 256
32*256=8192мкс
1млнмкс/8192мкс=122.07
Ничего прецизионного не нужно, +/- меня вполне устроит.
А как использовать один таймер для двух задач? Где-то читал про использование таймера на переполнение и совпадение одновременно (счетчик не сбрасывается), но не могу вспомнить и найти - где я это видел...
void setup() {
TIMSK |= (1<<TOIE2); // включаем timer2
TCCR2 |= (1<<WGM21) | (WGM20) // Активируем режим FastPWM, в этом режиме при совпадении счетчика он не обнуляется и считает до переполнения
TCCR2 |= (1<<CS22) | (1<<CS21); // предделитель 1/256
OCR2 = 128;
sei();
}
void loop() {
}
ISR(TIMER2_OVF_vect) {
// Выполняю какие-то действия каждые ~8,2 миллисекунды
}
ISR (TIMER2_COMP_vect){
// Выполняю какие-то действия примерно каждые ~4,1 миллисекунды
}
это не включение таймера - это разрешение прерываний по переполнению
включается/выключаются таймер выставлением значения предделителя !
Точно! Исправляемся:
void setup() {
TIMSK |= (1<<TOIE2) | (1<<OCIE2); // Разрешаем прерывания timer2 по переполнению (TOIE2)и совпадению (OCIE2)
TCCR2 |= (1<<WGM21) | (1<<WGM20) // Активируем режим FastPWM, в этом режиме при совпадении счетчика он не обнуляется и считает до переполнения
TCCR2 |= (1<<CS22) | (1<<CS21); // предделитель 1/256
OCR2 = 128; // Устанавливаем значение для совпадения
sei();
}
void loop() {
}
ISR(TIMER2_OVF_vect) {
// Выполняю какие-то действия каждые 8,2 миллисекунды
}
ISR (TIMER2_COMP_vect){
// Выполняю какие-то действия примерно каждые 4,1 миллисекунды
// А вот так можно делать?::
if (OCR2 == 128) {
// Что-то делаем
OCR2 = 180;
}
if (OCR2 == 180) {
// Что-то делаем
OCR2 = 128;
}
}
Komandir пишет:
И режим работы таймера скорее всего должен быть NORMAL !!!
Не могу ничего сказать, так как не совсем понимаю вот это:
Бит 6,3 — WGM21:0: Режим генерации сигнала
Эти биты управляют последовательностью подсчета счетчика, источником максимального (TOP) значения счетчика и какой тип генерации сигнала будет использоваться. Режимы работы, поддерживаемые блоком Таймер/Счетчик: Нормальный режим Clear Timer on Compare Match (CTC) и два типа режимов широтно-импульсной модуляции (PWM). Видеть Табл. 18-2 и «Режимы работы» на стр. 111.
Что то вы совсем поплыли ...
Да... "Зеленый змий" стал преобладать. Да и хрен с ним.
Прошу прощения за отнятое время.
1 Интервалы обратно пропорционально зависят от скорости вращения энкодера !!!
Логично, ведь при увеличении вращения увеличивается количество импульсов/за время.
2 Где обновление prevTime ?
Оно на самом деле есть, я вчера вычищал комментарии и "промазал" (удалил эту строчку).
3 Дребезг по паспорту энкодера - около 2 мс !!!
На радиокоте проскакивали сообщения о времени от 30 до 120 мс.
4 На осциллограмме дребезга не видно СОВСЕМ.
И я о том же сначала сказал. Однако ж были "перескакивания". Но змий и "мудрство" творят "чудеса" ))
5 Внешняя подтяжка выходов энкодера есть ?
Внешней нет, есть внутренняя (на осциллограмме хорошо видно, что импульсы генерируются подтяжкой к GND).
А он точно работает у Вас? У меня только так скомпилировалось:
И не заработало ))
А он точно работает у Вас? У меня только так скомпилировалось:
И не заработало ))
и не заработает
в коде от Komandir скобка лишняя в конце.
в коде от Komandir скобка лишняя в конце.
Ну я в начале поставил еще одну (как ты не заметил выше). Я думаю это потому, что он как и в бибилиотеке Rotary использовал пины 2 и 3, а у меня используется только один - 2.
Я бы попробовал еще опрос энкодера через таймер (как деда говорил), но его код очень сложный для меня еще. А как проще сделать я не знаю.
На самом деле вот этот код:
Работает хорошо, но почему то есть "пропуски", не в смысле крутишь и пропустил, а в смысле - 1,2,3,7,8,9 (конечно же меняются самые правые "биты" "дисплея".
И не понятно почему. Ведь на осциллограмме нет дребезга (да и в коде "антидребезг есть"). Как это так?
У меня нет atmega8 и код для нее я рисовал на основе кода 328 (который работает), подправьте синтаксис ...
У меня для прерываний используется только PD2 !!!
Надо включить подтяжки на оба вывода PD2 и PC5 - digatslWrite(..., HIGH) !!!
подправьте синтаксис ...
Не понял о каком синтаксисе речь.
У меня для прерываний используется только PD2 !!!
У меня тоже. Второй вывод энкодера на PC5.
Надо включить подтяжки на оба вывода PD2 и PC5 - digatslWrite(..., HIGH) !!!
Так изначально и сделано (и это хорошо видно на осциллограмме).
Попробуйте выбросить миллис и всё что с ним связано и вставить delayMicroceconds(100) самой первой строчкой прерывания и после проверять кто LOW.
Мне кажется, что все-же виновником является энкодер (а так как памяти у DSO5102P мягко говоря - маловато, то я просто не могу на осциллограмме это увидеть). Я провел другой эксперимент.
Я опять подключил два канала, стал вращать энкодер медленно с относительно постоянной скоростью (по "тактильному тику") и в момент когда произошло опять "смена значения" (назовем это так), я остановил осциллограмму (это происходит один раз за оборот 360гр). Ниже привожу скрины с осциллографа:
То есть я увидел, что значение "прыгнуло", еще по инерции довернул энкодер (еще один "щелчок") и остановил осциллограмму.
Ну и, честно говоря, мне непонятно - как так то? По осциллограмме вообще не должно быть срабатываний, а в коде есть.
Использовал этот код (комментарии не стал удалять), задержка была 2мс.
Запаял новый (другой уже и тоже новый) энкодер - проблема ушла. Прекрасно работает и с задержкой и без нее (думаю, что это потому что у DSO5102P на мнооого меньше памяти чем у того же DSO5102B (2Mb) и он просто пропускал дребезг). Работает схема только на этом коде (код от komandir'а работает только одно значение (либо только инкремент, либо только декремент):
(Конечно же это только часть кода, что относится к энкодеру)
Не правильно ты дядя Фёдор бутерброд ешь. Его надо колбасой на язык... перевести осциллограф в однократный режим, поставить разрешение микросекунд 200 на клетку, запуск от фронта любого канала, память процентов 25 и крутануть ручку, разок в одну сторону сохраниться и разок в другую. Можно будет увидеть дребезг. Возможно надо развертку по времени ещё уменьшить. Так, что бы на весь кадр только один импульс был. Не надо много импульсов. Не видно ничего.
Не правильно ты дядя Фёдор бутерброд ешь. Его надо колбасой на язык... перевести осциллограф в однократный режим, поставить разрешение микросекунд 200 на клетку, запуск от фронта любого канала, память процентов 25 и крутануть ручку, разок в одну сторону сохраниться и разок в другую. Можно будет увидеть дребезг. Возможно надо развертку по времени ещё уменьшить. Так, что бы на весь кадр только один импульс был. Не надо много импульсов. Не видно ничего.
Это хорошая идея на "отвлечься", энкодер я выпаял, но не выкинул. Отложил в сторону (хотя хотелось по нему молотком! Но молотка дома нет сейчас, да и я сейчас "под шафэ" )) В гараж точно не поеду. Да и хожу "морской походкой" ))
Надо было не добавлять скобку, а убрать одну в конце !
digitalRead(PIN_PC5) ? number += 1000 : number -= 1000;
Ты серьезно считаешь, что это что-либо изменило бы? Я могу проверить. Подожди...
Ты серьезно считаешь, что это что-либо изменило бы? Я могу проверить. Подожди...
Да! А я, тупая голова, думал в это нет смысла (расставил скобки как захотел), но все же РАБОТАЕТ! Значит я не совсем ущербен. ОГРОМНОЕ СПАСИБО!!!
Код:
РАБОТАЕТ!!! ))
И да, я сейчас именно (видимо трезветь начал) понимаю, что скобки мои были "далеко не на своих местах". Ну чтож, если не помру в ближайшее время от "зеленого змия", то точно завяжу с ним. Ну и с парочкой соседей в общении. Большое спасибо, что хоть на последней отдушине души не бросили в омут.
Ты серьезно считаешь, что это что-либо изменило бы? Я могу проверить. Подожди...
Да! А я, тупая голова, думал в это нет смысла (расставил скобки как захотел), но все же РАБОТАЕТ! Значит я не совсем ущербен. ОГРОМНОЕ СПАСИБО!!!
Код:
РАБОТАЕТ!!! ))
пиз@дец, я те че в #104 сказал
завязывай бухать.
завязывай бухать.
Вот кстати вопрос - что значит «бухать» и что значит «запой»? Это так - куда я качусь..
Бухой - не бухой, но азы то знать надо! А не методом тыка всё.
Я на самом деле удивлен - Почему в решении этого вопроса мне откликнулся помогать только komandir?
Так радоваться надо: диалог - разговор двоих - наиболее эффективный вариант. Когда советчиков много, всегда проявляется эффект лебедя, рака и щуки. Поэтому при эффективном взаимодействии двоих третьему лучше не вмешиваться (сколько бы этих "третьих" ни было).
Хочу поднять тему вот по какому "случаю". Я поменял энкодер и пару-тройку недель все было в шоколаде, но спустя время и поменянный энкодер стал выдавать "то +/то-". Знаю, этого популяризатора ардуино тут не любят, но именно его код заработал отлично. Со старым энкодером:
Код отлично работает. На "правильность" кода - усмотрение читающих, в моем случае (одно прерывание) он подошел идеально!...
Ну и чтоб никого не обидеть ссылка на статью: Быстрая обработка энкодера digitalRead()
Не рекламы ради, а пользы для...
А sei() для надёжности?
Осталось "по наследству" )))
А расскажи зачем там нужен CHANGE ?
Может просто стоит вникнуть в то как работает энкрдер и понять , что за один щелчок он совершает полный цикл переключений ?
Тогда очевидно станет ясно, что RISING/FALLING тупо сократят половину кода прерывания и весь код для FALLING будет выглядеть так:
digitalRead(EncB)?val++:val--;
Поясню как это работает:
Вход в прерывание только по смене состояния пина EncA по заднему фронту сигнала.
Т.е. мы уже знаем, что на пине EncA лог0, мы же в прерывание из за этого и попали.
Теперь нам осталось прочитать состояние пина EncB.
Если там лог1 то инкрементируем счётчик, если лог0 то декрементируем(или наоборот , по желанию).
Борьба с дребезгом отдельная песня.
Можно тот же миллис использовать, чтоб результат опроса учитывать скажем не чаще чем 1 раз в 20мс.
Я предпочитаю делать это аппаратно посредством mc14490
Собственно говоря у меня и был подобный код (по прерываю FALLING):
Но он работал не корректно - При медленном вращении наблюдалось 4/5/6/5/6.
Ну это же как раз программный перевод CHANGE к FALLING или RISING.
Ну это же как раз программный перевод CHANGE к FALLING или RISING.
Это понятно.
Не понятно - Почему же с этим кодом корректно стало медленное вращение работать?
Код более антидребезговый получился. Подозреваю что на больших скоростях будет пропускать щелчки.
Чего непонятного то ?
Тут идёт проверка на то что было вращение.
Увеличь время на устранение дребезга(в твоём случае на щелчок убитого энкодера и нормально всё будет).
Я делаю так:
if(!EncTick)digitalRead(EncA)?EncTick=1:EncTick=-1;
EncTick в коде сбрасывается в 0 после использования.
Подозреваю что на больших скоростях будет пропускать щелчки.
Даже если и будет - я этого на больших скоростях и не замечу (то есть - для меня приемлемо). )))
if(!EncTick)digitalRead(EncA)?EncTick=1:EncTick=-1;
EncTick в коде сбрасывается в 0 после использования.
Хм, интересный подход - надо будет попробовать.
По поводу времени на антидребезг - я начал с 2мс (как советовал Командир) и постепенно добрался до 50мс. При этом ситуация не улучшилась... (((( (Может нужно было и дальше увеличивать? Но я побоялся).
ЗЫ: От тактовой это как-то зависит? У меня всего 1МГц от внутреннего генератора...
Все равно и с новым кодом проблема на медленных оборотах проявлялась. Хоть и не так часто.
В общем принял кардинальное решение:
1. Поднял тактовую до 8МГц (от внутреннего генератора)
2. Подключил библиотеку Rotary и опрашиваю энкодер в loop()
Все стало просто великолепно!
А если до 16-ти поднять, то станет в 2 раза великолепнее. Не просто, а просто - просто!
А если до 16-ти поднять, то станет в 2 раза великолепнее. Не просто, а просто - просто!
Не исключено! )))))
Тактовую поднял по другой причине (пошло бонусом )) )...
Прошу обратить внимание на дату предыдущих сообщений. Сегодня уже 2е... ))
Сегодня уже 2е... ))
ты отставешь от жизни, 7-е !
Посмотри на Календарь - 8е уже!
(Специально ждал, не отвечал )))) )
Прошу более опытных товарищей проверить ход моих вычислений и, если нужно, поправить:
Даташит на Atmega8: https://static.chipdip.ru/lib/547/DOC005547852.pdf
Как то ты считаешь непонятно.
1млнмкс/8мгц=0.125мкс время одного такта
0.125*256=32мкс время переполнения таймера(без делителя)
С предделителем 256
32*256=8192мкс
1млнмкс/8192мкс=122.07
Неровненько
Я округлял (~), значит правильные у меня вычисления?
Если от внутреннего генератора, то там точность +- километр, особенно если меняется температура...
Ничего прецизионного не нужно, +/- меня вполне устроит.
А как использовать один таймер для двух задач? Где-то читал про использование таймера на переполнение и совпадение одновременно (счетчик не сбрасывается), но не могу вспомнить и найти - где я это видел...
Задай точку сравнения и разреши прерывание... Только тикать они будут с одинаковой частотой, но разнесутся по времени.
Во, нашел где видел. Получается так:
Правильно?
Не вижу разрешения прерывания по совпадению OCIE2
TIMSK |= (1<<TOIE2);
// включаем timer2
это не включение таймера - это разрешение прерываний по переполнению
включается/выключаются таймер выставлением значения предделителя !
И режим работы таймера скорее всего должен быть NORMAL !!!
Не вижу разрешения прерывания по совпадению OCIE2
TIMSK |= (1<<TOIE2);
// включаем timer2
это не включение таймера - это разрешение прерываний по переполнению
включается/выключаются таймер выставлением значения предделителя !
Точно! Исправляемся:
И режим работы таймера скорее всего должен быть NORMAL !!!
Не могу ничего сказать, так как не совсем понимаю вот это:
Что такое TOV2 Flag Set и Update of OCR2 ?
Если режим NORMAL, то получается так:
Строки 5 и 6 я бы поменял местами - сначала настраиваем таймер, потом запускаем.
каждые 4.1 не получится - для этого надо менять OCR в прерывании - прописывая по очереди 0 и 128
Строки 5 и 6 я бы поменял местами - сначала настраиваем таймер, потом запускаем.
Понял
каждые 4.1 не получится - для этого надо менять OCR в прерывании - прописывая по очереди 0 и 128
А как же TOP 0xFF, то есть я так понимаю что в отличии от CTC в этом режиме сработало прерывание и счетчик пошел дальше до переполнения. Не прав?