Ви не увійшли.
Сторінки 1
Ребята сделал генератор для дома ( нужен для экспериментов) - на Ардуино НАНО Скетч компилируется нормально , залил в Арду , все хорошо - только энкодер не работает Кнопка срабатывает а энкодер нет .
Проверил сам энкодер - работает.Мне думается что в скетче не прописана сама работа этой штуки.Но в программировании я не спец,только начинаю.
Может кто подсказать в чем проблема ? Причем иногда что то меняется ( показания)Думаю что проблема в строчке :Rotary r = Rotary(2,3); // sets the pins the rotary encoder uses. Must be interrupt pins.
sketch_test2.zipGenerato.zip- Нашел еще код для того же генератора - но так же не работает энкодер (через раз)
Неактивний
Для початку відтворіть демку з енкодером. Разом з резисторами в конденсаторами
Что именно надо сделать? Физически собрать схему - так я пробовал , энкодер работает ( осциллограф показывает импульсы со смещением). А вот по поводу демки - я уже сказал что только начинаю осваивать Ардуино.
Неактивний
Як правило разом з лібою для енкодера є демо-програма. Очікується що вона працює.
Положим что энкодер - нормально. Что по поводу самого скетча? В двух вариантах программного кода - по разному прописано работа энкодера , и в обоих случаях нет четкого срабатывания . Вопрос именно - в чем причина ?
Неактивний
конденсатори напаяли, як в букварі намальовано?
Вы вообще то скетч смотрели ?
А вы сделали что вас спрашивали?
Як правило разом з лібою для енкодера є демо-програма. Очікується що вона працює.
В папке с библиотекой есть пример Interrupt.ino. Вы его загружали?
Думаю что проблема в строчке :Rotary r = Rotary(2,3); // sets the pins the rotary encoder uses. Must be interrupt pins.
У вас енкодер підключений до пінів D2 та D3? Зовнішні підтяжки на них є? Якщо немає, макрос ENABLE_PULLUPS був визначений на момент компіляції бібліотеки? У вас бібліотека в архіві в трьох екземплярах. Який із двох Rotary.h інклудився при компіляції Rotary.cpp, той що Rotary/Rotary.h чи Rotary-1.0.0/src/Rotary.h ?
Якщо ENABLE_PULLUPS не був визначений при компіляції бібліотеки, то піни без зовнішніх або внутрішніх підтяжок ловлять шуми космоса.
Якщо компілюєте в IDE, увімкніть "Show verbose output: compile" і показуйте вивод. Окрім вас ніхто не може знати, що там у вас як компілюється. Крім того, arduino IDE кешує артефакти компіляції.
Створіть окремий скетч, в якому просто читайте енкодер і пишіть в послідовний порт, що повертає Rotary::process(). Для початку без усяких переривань.
Доречі, у вас операції зі змінними, які апдейтяться в обробнику переривань, неатомарні. Це помилка. Навіть якщо енкодер працюватиме правильно, результат буде непередбачуваним. Якщо, як самі кажете, тільки починаєте, то не звʼязуйтесь із перериваннями. В Rotary є приклад циклічного опитування (polling). Впевніться в стабільній роботі цього приклада, потім інтегруйте його у свій скетч.
Неактивний
якщо немає четкого срабатывания - скоріше за все брязкіт контактів. Звичайно його душать rc фільтром. Тому і спитав. А щодо коду - ви ж його з прикладу скопіювали, правда? приклад робочий.
Доречі, перевірте сам енкодер. Мені зустрічались екземпляри, у яких загальний вивод (GND) не посередині як на цьому фото, а збоку. Тобто послідовно йдуть: GND, OutA, OutB. Якщо продзвонювати кожний пін окремо, то при обертанні виглядає наче все ок. Але в схемі, де їх стани читаються одночасно, звісно що зчитується фігня. Колись витратив мабуть із годину, поки не виявив таку невідповідність розпіновки.
Неактивний
Але помилки при роботі з глобальними змінними раджу все-таки виправити. Переривання може виникнути (і виникне) посередині читання глобальної змінної, і змінить її значення. Прочитане значення буде некоректним. Це призведе до неправильної роботи, а за законом Мерфі це станеться в самий критичний момент Крім того, компілятор взагалі може заоптимізувати звернення до них, вважаючи, що їх значення ніколи не змінюються. Тому потрібні atomic-блоки та volatile.
Краще винести всю ту логіку із ISR в основний цикл, а в ISR тільки репортувати події від енкодера у змінну з атомарним доступом (на AVR8 це 8-бітні типи). А у вашому випадку краще взагалі обійтись без переривань.
Неактивний
ISR(PCINT2_vect) {
unsigned char result = r.process();
Так робити стрьомно. ISR повинно виконуватись максимально швидко, а тут викликається якийсь метод з ліби енкодера, хз що він робитиме. Якщо всередині Serial.print, буде ой.
Як правило, регулярні дії (process(), tick(), ..) викликають в loop - там воно точно спрацює як треба.
Якщо в ISR ви щось робите з глобальною змінною, яка більша ніж uint8_t - на цей час треба забороняти переривання. Приблизно так:
ISR()
..
cli();
do_some_sheet
sei();
loop()
..
cli();
do_some_sheet
sei();
Неактивний
тут викликається якийсь метод з ліби енкодера, хз що він робитиме.
Rotary::process() лише читає стани пінів та перемикає стан внутрішнього конечного автомата. Викликати той Rotary::process() в ISR - норм. Хоча в програмі топікстартера взагалі немає особливого сенсу використовувати переривання.
Якщо всередині Serial.print, буде ой.
Якщо не змішувати з викликами до Serial поза контекстом цього ISR, то буде працювати. HardwareSerial::write() не робить нічого такого, чого не можна робити в ISR.
Приблизно так:
ISR() .. cli(); do_some_sheet sei();
Не робіть так. ISR() викликається з уже вимкненими перериваннями. sei() їх увімкне і дозволить переривати цей обробник.
Остання редакція dimich (2025-02-09 23:40:54)
Неактивний
Заміть 1000 слів - дивіться як зроблено в Arduino
НЯП всередині ISR присідання з атомарністю не потрібні, бо переривання забороняється автоматично.
#if defined(TIM0_OVF_vect)
ISR(TIM0_OVF_vect)
#else
ISR(TIMER0_OVF_vect)
#endif
{
// copy these to local variables so they can be stored in registers
// (volatile variables must be read from memory on every access)
unsigned long m = timer0_millis;
unsigned char f = timer0_fract;
m += MILLIS_INC;
f += FRACT_INC;
if (f >= FRACT_MAX) {
f -= FRACT_MAX;
m += 1;
}
timer0_fract = f;
timer0_millis = m;
timer0_overflow_count++;
}
А ззовні - читайте коментар до коду
unsigned long millis()
{
unsigned long m;
uint8_t oldSREG = SREG;
// disable interrupts while we read millis_timer_millis or we might get an
// inconsistent value (e.g. in the middle of a write to millis_timer_millis)
cli();
m = millis_timer_millis;
SREG = oldSREG;
return m;
}
Неактивний
Сторінки 1