Atmega8. Обработчик для валкодера на C

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Сб май 12, 2007 09:04:03

Сообщение sansan88 »

В общем я делаю блок управления для УМЗЧ. Регулировка громкости будеи происходить при помощи валкодера (или как он там правильно называется, когда крутишь в одну сторону, контакты замыкаются в одном порядке, если в другую, то наоборот).

Вот собственно обработчик:

Код: Выделить всё


while (1)
      {
      if (PIND.7==0) {
        if (enc_dec==1) {
                enc_count--;
                enc_dec=0;
                enc_inc=0;
                printf("%c\r",enc_count);
                }
        else {
                enc_inc=1;
        };
      };   
      if (PIND.6==0) {
        if (enc_inc==1) {
                enc_count++;
                enc_dec=0;
                enc_inc=0; 
                printf("%c\r",enc_count); 
                }
        else {
                enc_dec=1;    
        };
      };
      };
Это пока главный цикл программы.
Тут для примера сделал вывод состояния переменной-счетчика enc_count.

Изначально переменные enc_dec, enc_inc установлены в 0.

Выводы PD6 и PD7 програмно подтянуты к + питания.

Проблема такая, при повороте движка на одно деление происходит многократное выполнение кода и соответственно число в счетчике уменьшается (увеличивается) не на 1, как требуется, а на много больше.
Как решить эту проблему, мож кто сталкивался, подскажите пожалуйста.
Вложения
Clipboard01.gif
Схема подключения валкодера
(2.11 КБ) 913 скачиваний
Опыт не пропьешь!
Реклама
Э...
Аватара пользователя
Сообщения: 2792
Зарегистрирован: Ср апр 04, 2007 08:39:14
Откуда: Москва

Сообщение tych »

Можно оставить схему как у вас и две ножки МК подсоединить диодами к INT0 настроеному как вход с подтяжкой и прервание по спаду. А в прерывании инализировать направление.
Думайте сами, решайте сами ... а вот он-лайн перевод на корявый русский http://translate.ru
Контактная информация:
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18786
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Тебе необходимо добавить в свой код цикл ожидания момента, когда состояние твоих входных портов изменится - и только после этого продолжать основной цикл. В этом случае при одном и том же состоянии счетчик увеличится только на 1.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Сб май 12, 2007 09:04:03

Сообщение sansan88 »

Попробую, но хотелось бы не использовать прерывание.
Опыт не пропьешь!
Реклама
Эиком - электронные компоненты и радиодетали
Э...
Аватара пользователя
Сообщения: 2792
Зарегистрирован: Ср апр 04, 2007 08:39:14
Откуда: Москва

Сообщение tych »

Если не использовать прерывание то твоя прога может вечно крутится в опросе ( поллинге ) валкодера и ничего больше делать не сможет.
Думайте сами, решайте сами ... а вот он-лайн перевод на корявый русский http://translate.ru
Контактная информация:
Реклама
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Сб май 12, 2007 09:04:03

Сообщение sansan88 »

ARV писал(а):Тебе необходимо добавить в свой код цикл ожидания момента, когда состояние твоих входных портов изменится - и только после этого продолжать основной цикл. В этом случае при одном и том же состоянии счетчик увеличится только на 1.
У меня еще будет процедура вывода информации на ЖКИ от Nokia 3310, только вот не знаю куда ее засунуть, в главный цикл или в таймер. Задержки - это первое что мне пришло в голову, но тогда если состояние долго не изменится (например я не до конца провернул ручку и произошло замыкание только первого контакта) то программа подвиснет до его изменения и ничего кроме прерываний обрабатывать не будет. Кстати, на прерывание еще повешу IR приемник для декодирования сигналов с пульта.
Опыт не пропьешь!
Реклама
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Сб май 12, 2007 09:04:03

Сообщение sansan88 »

tych писал(а):Если не использовать прерывание то твоя прога может вечно крутится в опросе ( поллинге ) валкодера и ничего больше делать не сможет.
Тот код который я привел - есть главный цикл функции main. так что после обработчика валкодера в него можно впринципе вставить еще чего-то. ЛАдно, попробую сделать с прерыванием, похоже это единственный приемлемый вариант.
Опыт не пропьешь!
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18786
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Вообще-то, tych прав: делай в основном цикле вывод всего, чего надо, управление всем чем надо, а остальное (всю входящую информацию) делай по прерываниям - валкодер, IR-приемник, таймер...
а при ожидании можно извратиться и тоже че-то делать, но это муторно, имхо...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Сб май 12, 2007 09:04:03

Сообщение sansan88 »

Значит так и сделаю. с задержками чет нет желания заморачиваться. Ладно, разработки данного давайса приостановлены до понедельника, отдыхаю. Потом отпишусь че получилось.
Опыт не пропьешь!
Э...
Аватара пользователя
Сообщения: 2792
Зарегистрирован: Ср апр 04, 2007 08:39:14
Откуда: Москва

Сообщение tych »

Можно сделать прерывание по переполнению таймера_0 в 2 раза чаще чем максимальное число тиков валкодера разумно допустить.

И в этом прервании 1 раз опрашивать что там на ногах его и сравнить что было в прошлый раз. Далее делать в этом прерывании все остальное.
Думайте сами, решайте сами ... а вот он-лайн перевод на корявый русский http://translate.ru
Контактная информация:
Грызет канифоль
Аватара пользователя
Сообщения: 293
Зарегистрирован: Пн дек 24, 2007 07:09:09

Сообщение VenomXP »

Автор пропал куда-то. Очень интересно увидет код этой штуки. Имеется такая штука, только она из мышки, современной (умерла бедная совсем). Он такой маленький имеет 3 вывода. Фото позже будет. Я уверен что в нем нет оптопары, по простой причине что она просто туда не поместиться.
Даташит - библия моя...
Изображение
Контактная информация:
Грызет канифоль
Аватара пользователя
Сообщения: 293
Зарегистрирован: Пн дек 24, 2007 07:09:09

Сообщение VenomXP »

Привожу пример кода обработки валкодера:

Код: Выделить всё

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
if ((PIND.7 == PIND.6)) vol++;

if ((PIND.7 != PIND.6)) vol--;
}
Принцип простой. Любой из выводов валкодера цепляем на внешнее прерывание, допустим PD7(все зависит от контроллера), а другой вывод на любую ножку контроллера сконфигурированную как вход, допустим PD6. Дальше из кода все понятно.
Мне бы хотелось выяснить как допустим можно сделать так: если быстро крутить его то значение инкремента увеличивалось на 10 единиц, а если медленно то на 1?
Последний раз редактировалось VenomXP Пт июн 05, 2009 11:21:01, всего редактировалось 1 раз.
Даташит - библия моя...
Изображение
Контактная информация:
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18786
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

VenomXP писал(а):Мне бы хотелось выяснить как допустим можно сделать так: если быстро крутить его то значение инкремента увеличивалось на 10 единиц, а если медленно то на 1?
я делал такой вариант и даже где-то выкладывал код... но меня раскритиковали - сказали, что неудобно... и я забросил это :(
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Грызет канифоль
Аватара пользователя
Сообщения: 293
Зарегистрирован: Пн дек 24, 2007 07:09:09

Сообщение VenomXP »

Я думаю принцип следующий. Запускаем таймер пусть он считает вообще не останавливаясь до максимума. Вводим переменную которая бы считала чколько времени прошло: count++; Далее когда приходит внешнее прерывание делаем так:

Код: Выделить всё

interrupt [EXT_INT0] void ext_int0_isr(void)
{
if (count > 50) //если прошло больше 50 мс с последнего обнуления
{
   if ((PIND.7 == PIND.6)) vol++;
   if ((PIND.7 != PIND.6)) vol--;

   count = 0; //обнуляем счетчик 
}
else
{
   if ((PIND.7 == PIND.6)) vol = vol +10;
   if ((PIND.7 != PIND.6)) vol = vol - 10;

   count = 0;
}
}
Ну или примерно так.
Даташит - библия моя...
Изображение
Контактная информация:
Мявтор!
Аватара пользователя
Сообщения: 2057
Зарегистрирован: Чт ноя 30, 2006 12:27:46
Откуда: Челябинск

Сообщение dt_andrew »

вот мой код
работает четко уже не в одном проекте

предварительные определения
//*****************************************************************************
#define ENCODER_PIN_A PD3
#define ENCODER_PIN_B PD1
#define ENCODER_PIN_PORT PIND
#define ENCODER_LEFT KBD_LEFT // код клавиши лево
#define ENCODER_RIGHT KBD_RIGHT // код клавиши право
#define ENC_TIMER_CNT 5

volatile char encoder_status;
const char enc_mask_plus = 0b00011110;
const char enc_mask_minus = 0b00101101;
//*****************************************************************************

осовная программа

таймер 2 настроен на 500мкс
переменной enc_timer_cnt можно регулировать чувствительность
//*****************************************************************************
ISR(SIG_OVERFLOW2)
{
TCNT2 = TIMER2_CNT; OCR2 = TIMER2_OCR;
enc_timer_cnt++;
if (enc_timer_cnt == ENC_TIMER_CNT)
{
if (enc.flip == -1) encoder_scan();
enc_timer_cnt = 0;
}
}
//*****************************************************************************
обработчик валкодера
и процедура инициализации

//*****************************************************************************
void encoder_scan(void)
{
unsigned char enc_A, enc_B, bit_0, bit_1;
if (enc.flip == -1)
{
if (bit_is_clear(ENCODER_PIN_PORT, ENCODER_PIN_A)) enc_A = 0; else enc_A = 1;
if (bit_is_clear(ENCODER_PIN_PORT, ENCODER_PIN_B)) enc_B = 0; else enc_B = 1;
if (bit_is_clear(encoder_status, 0)) bit_0 = 0; else bit_0 = 1;
if (bit_is_clear(encoder_status, 1)) bit_1 = 0; else bit_1 = 1;
if ((enc_A != bit_0) || (enc_B != bit_1))
{
encoder_status = encoder_status << 2;
if (enc_A == 0) encoder_status &= ~(_BV(0)); else encoder_status |= _BV(0);
if (enc_B == 0) encoder_status &= ~(_BV(1)); else encoder_status |= _BV(1);
if (encoder_status == enc_mask_minus)
{
enc.code = ENCODER_LEFT;
enc.flip = 1;
}
if (encoder_status == enc_mask_plus)
{
enc.code = ENCODER_RIGHT;
enc.flip = 1;
}
}
}
}
//*****************************************************************************
void encoder_init(void)
{
enc.code = ENCODER_NOKEY;
enc.flip = -1;
}
//*****************************************************************************

код не оптимальный и можно сделать красивее
но у меня работает хорошо и этим все сказано - переделывать лень и нет времени

в основном цикле

if (enc.flip == 1)
{
kbd_key = enc.code;
beep();
enc.flip = -1;
return 1;
// в зависимости от кода клавиши полученной от валкодера
// принимаем решение что делать
}
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»