01.06.2016, 10:15 | #1 (permalink) |
Member
Регистрация: 26.03.2016
Сообщений: 16
Сказал(а) спасибо: 0
Поблагодарили 1 раз в 1 сообщении
Репутация: 60
|
Проблема с опросом энкодера на внешних прерываниях
изменения значения энкодером в большую (до 999) или меньшую сторону. Опрос энкодера реализовать на внешних прерываниях. Вот код: KOD_2.txt Алгоритм стандартный, но при повороте ручки энкодера влево-вправо он либо в обе стороны прибавляет, либо в обе стороны отнимает. В чем может быть дело? |
01.06.2016, 10:15 | |
Helpmaster
Member
Регистрация: 08.03.2016
Сообщений: 0
|
В похожих обсуждениях зачастую можно найти полезные ответы Странность с опросом подключение внешних разъемов Подключение энкодера Помогите с макросом для энкодера О внешних ссылках |
01.06.2016, 16:31 | #2 (permalink) |
Member
Регистрация: 15.08.2013
Адрес: Minsk
Сообщений: 145
Сказал(а) спасибо: 1
Поблагодарили 0 раз(а) в 0 сообщениях
Репутация: 713
|
Скажите, а зачем там вообще таймер?
Вы разрешили прерывание по спаду INT0, объявили обработчик - что еще надо? Флаг прерывания сам сбросится при входе в обработчик. Или же у вас дребезг контактов? Но тогда лучше вообще все по таймеру, а внешнее прерывание запретить. Читать по таймеру, сравнивать с предыдущим. |
03.06.2016, 15:19 | #3 (permalink) |
Member
Регистрация: 26.03.2016
Сообщений: 16
Сказал(а) спасибо: 0
Поблагодарили 1 раз в 1 сообщении
Репутация: 60
|
Недавно боролся с похожей проблемой. Поборол. Суть в следующем.При инициализации:1. Привязываем прерывание к срезу импульса на выходе А энкодера.Обработчик прерываний:1. Запрещает прерывания.2. Взводит глобальный флаг.Основной код программы:1. Если взведен флаг, выполняем последующий код, иначе - пропускаем.2. Задержка 3 мс для завершения возможного переходного процесса.3. Читаем выход А энкодера. Если высокий - прерывание ложное, сбрасываем глобальный флаг, разрешаем прерывания, пропуск последующего кода.4. Читаем выход В энкодера - если высокий, добавляем нужную величину, низкий - убавляем и т.д., вобщем стандартный вариант. Перед завершением обработки сбрасываем глобальный флаг и разрешаем прерывания
Выше предложенный алгоритм заработал, однако программа работает не оптимально: иногда при повороте энкодера возникает осечка, либо прибавляет/отнимает 2, вместо 1. Пробовал перебрать частоту тиков таймера, ничего не помогает. Код:
#include "hd44780.h" #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #define ENC_PORT PORTD #define ENC_PIN PIND #define A_PIN 2 #define B_PIN 1 #define Comapare_Mask (1<<A_PIN)|(1<<B_PIN) volatile uint8_t flag=0; void timer0_on() { TCNT0=0x00; //записываем 0 в счетный регистр TCCR0|=(1<<CS02)|(0<<CS01)|(1<<CS00);//устанавливаем частоту тиков TIMSK|=(0<<OCIE0)|(1<<TOIE0);//устанавливаем прерывания по переполнению } void timer0_off() { TCCR0|=(0<<CS02)|(0<<CS01)|(0<<CS00); } int main(void) { int count=14; lcd_init(); lcd_clear(); lcd_out4(count,2); MCUCR |= (1<<ISC01)|(0<<ISC00);//прерывание по спаду GICR = (1<<INT0); //разрешение прерываний ENC_PORT |= Comapare_Mask;//опрос энкодера sei(); while(1) { if (flag==1) { timer0_on(); if ((ENC_PIN&(1<<A_PIN)) >>A_PIN==1) //считываем вывод А { flag = 0;//если уровень высокий сбрасываем флаг } else { if ((ENC_PIN&(1<<B_PIN)) >>B_PIN==1) { count--; if (count<0) count=9999; } else { count++; if (count>9999) count=0; } flag = 0; } } lcd_out4(count,2); }; } ISR (INT0_vect) { GICR = (0<<INT0); //запрещаем прерывания flag = 1;//взводим глобальный флаг } ISR (TIMER0_OVF_vect) { timer0_off(); GICR = (1<<INT0); } |
03.06.2016, 15:54 | #4 (permalink) |
Member
Регистрация: 09.08.2015
Адрес: Minsk
Сообщений: 245
Сказал(а) спасибо: 12
Поблагодарили 0 раз(а) в 0 сообщениях
Репутация: 3649
|
|
Ads | |
Member
Регистрация: 31.10.2006
Сообщений: 40200
Записей в дневнике: 0
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Репутация: 55070
|
|
|