Опрос кнопок микроконтроллером

Дисплеи, датчики и прочие функциональные узлы, управляемые МК.
Аватара пользователя
Барсик
Друг Кота
Сообщения: 3459
Зарегистрирован: Ср сен 27, 2006 16:18:57

Re: Помогите опросить кнопку

Сообщение Барсик »

Alexeyslav писал(а):каждое 10-е прерывание - тупо запоминаем состояние портов с кнопками и всё.
Понятно. Аналог задержки, но без задержки... :) т.е. получаем нечто, что было 10 миллисекунд назад, и надеемся, что сейчас оно такое самое и есть. Аесли нет? В чём смысл отложить опрос состояния кнопок на 10 мс?
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25151
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Помогите опросить кнопку

Сообщение КРАМ »

Барсик писал(а):В чём смысл отложить опрос состояния кнопок на 10 мс?

Не отложить, а ЗАЩЕЛКИВАТЬ состояние кнопки раз в 10 мс. Тут дело не в 10 мс, а во времени дребезга кнопки. При защелкивании состояния кнопки реже, чем длится дребезг, дребезг исчезнет.
Alexeyslav
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич
Контактная информация:

Re: Помогите опросить кнопку

Сообщение Alexeyslav »

зачем откладывать? бери и пользуйся. Вот прямо как прерывание произошло, состояние защелкнули - так сразу можешь брать и пользоваться. Смысл в чем, в том что состояние кнопок фиксируется один раз за цикл, и даже если фиксация попадёт на момент дребезга - максимум что может быть то один раз зафиксируем неверное состояние кнопки в момент перехода а это чревато только тем что нажатие мы увидим в худшем случае на следующий цикл опроса. Но сам дребезг программа не увидит.

из этого кстати следует естественное ограничение данного алгоритма - кнопка может быть в нажатом(отпущенном) состоянии для правильной работы не менее 2-х циклов опроса. Если не соблюсти это условие максимум что случится - пропустим событие нажатия кнопки. Человек, к примеру, так быстро нажимать кнопки не сможет. А для концевых выключателей или датчиков частоты вращения вала нужны другие методы подавления дребезга, зачастую даже механические.
Аватара пользователя
Барсик
Друг Кота
Сообщения: 3459
Зарегистрирован: Ср сен 27, 2006 16:18:57

Re: Помогите опросить кнопку

Сообщение Барсик »

КРАМ писал(а):...а ЗАЩЕЛКИВАТЬ...
Дошло... Спасибо.
nurekil
Родился
Сообщения: 4
Зарегистрирован: Чт ноя 12, 2015 20:26:00

проблема при подключение кнонки к atmega8...

Сообщение nurekil »

По задумке по нажатию кнопки должен загораться светодиод и гореть 3 сек.
Подключил кнопку, сделал подтяжку пина к земле. Сигнал на пин поступает, но не обрабатывается.
Подскажите что не так. Или это просто протеус логает
СпойлерИзображение



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

#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>

int main(void){
   DDRB |= (1<<PB7);
   DDRC &= ~(1<<PC3);
   while(1){
      if((PINC & (1<<PC3)) == 1){       //If switch is pressed
         PORTB |= (1<<PB7);       //Turns ON LED
         _delay_ms(3000);           //3 second delay
         PORTB &= ~(1<<PB7);   //Turns OFF LED
      }
      }
}
Вложения
кнопка.rar
:
Proteus
CVAVR 5.0
(39 КБ) 345 скачиваний
Последний раз редактировалось nurekil Пт ноя 13, 2015 00:33:34, всего редактировалось 2 раза.
Аватара пользователя
Mishany
Электрический кот
Сообщения: 1031
Зарегистрирован: Чт июн 20, 2013 00:00:58
Откуда: москва, м.Сходненская

Re: проблема при подключение кнонки к atmega8...

Сообщение Mishany »

if(PINC & (1<<PC3) == 1){ //If switch is pressed
не хватает скобок if((PINC&(1<<PC3))==1){
nurekil
Родился
Сообщения: 4
Зарегистрирован: Чт ноя 12, 2015 20:26:00

Re: проблема при подключение кнонки к atmega8...

Сообщение nurekil »

Mishany писал(а):if(PINC & (1<<PC3) == 1){ //If switch is pressed
не хватает скобок if((PINC&(1<<PC3))==1){


Спсибо, исправил. Но, к сожалению, не работает.
Аватара пользователя
B@R5uk
Собутыльник Кота
Сообщения: 2896
Зарегистрирован: Сб ноя 13, 2010 12:53:25
Откуда: приходит весна?

Re: проблема при подключение кнонки к atmega8...

Сообщение B@R5uk »

Токоограничивающий резистор надо последовательно со светодиодом поставить.
nurekil
Родился
Сообщения: 4
Зарегистрирован: Чт ноя 12, 2015 20:26:00

Re: проблема при подключение кнонки к atmega8...

Сообщение nurekil »

B@R5uk писал(а):Токоограничивающий резистор надо последовательно со светодиодом поставить.


Поставил. Сперва 110ом, а потом 150. Не загорается... :dont_know:
Аватара пользователя
СКАЗОЧНИК
Идёт направо - песнь заводит, Налево - сказку говорит.
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Re: проблема при подключение кнонки к atmega8...

Сообщение СКАЗОЧНИК »

nurekil писал(а):Сперва 110ом, а потом 150. Не загорается..

В Протеусе моежешь не ставить. ))) Это в реальной жизни надо. А если так, то и приучаться к хорошему надо везде.
Может и херню скажу, но обычно кнопки ставят от порта на землю, а подтяжку делают к плюсу.... Как внутреннюю, так и внешнюю.
(это вроде традиции еще от старых МК пошло, если захотите - прочитаете). Здесь же в вашей схеме может так и задумано. :dont_know:
Косяк у вас в программе где-то... 8)

Я плохо помню Си. А если в программе без всяких опросов кнопок сконфигурировать порт В7 на выход - будет светодиод гореть?
Станислав
Аватара пользователя
B@R5uk
Собутыльник Кота
Сообщения: 2896
Зарегистрирован: Сб ноя 13, 2010 12:53:25
Откуда: приходит весна?

Re: проблема при подключение кнонки к atmega8...

Сообщение B@R5uk »

nurekil писал(а):Не загорается... :dont_know:
Отпаяйте базовый резистор от МК и подключите на плюс питания. Если не загорится и в этом случае, то проблема с транзистором или светодиодом.

И если можно, то спрячте первую картинку под спойлер, а то не лезет форум по ширине в экран.
Аватара пользователя
СКАЗОЧНИК
Идёт направо - песнь заводит, Налево - сказку говорит.
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Re: проблема при подключение кнонки к atmega8...

Сообщение СКАЗОЧНИК »

B@R5uk писал(а):Отпаяйте базовый резистор от МК и подключите на плюс питания.


В Протеусе??? :shock: :))) :))) :))) Все бы глумиться...
Станислав
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Re: проблема при подключение кнонки к atmega8...

Сообщение Z_h_e »

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

  if((PINC & (1<<PC3)) == 1)
замените на

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

  if(PINC & (1<<PC3))


Ну или вместо 1 напишите 0b00001000, но это лишнее.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
nurekil
Родился
Сообщения: 4
Зарегистрирован: Чт ноя 12, 2015 20:26:00

Re: Помогите опросить кнопку

Сообщение nurekil »

Всем спасибо за ответы. Помог совет в конце 2 страницы этой темы. Заработало 8)
12val12
Потрогал лапой паяльник
Сообщения: 315
Зарегистрирован: Пт янв 29, 2010 19:42:27

Re: Помогите опросить кнопку

Сообщение 12val12 »

В большинстве телевизоров кнопки стоят на линии АЦП . всего два провода и до 6 кнопок .

а тут я накалякал на 3кнопки

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

  
   void OPROS_KN ()         
           {   unsigned char  VIBORKA1    ;
           
                 VIBORKA1= read_adc(0);           
                  if ( VIBORKA1 >240  )         return;        //ничего не нажато  подтяжка тянет       
                 delay_ms(15);
                 
                 if (read_adc(0) >VIBORKA1+1  )         return;   // если повторный уровень олтчается больше чем на +-1  то вых           
                 if ( VIBORKA1 >read_adc(0)+1  )         return;   // если повторный уровень олтчается больше чем на +-1  то вых       
           
               if (VIBORKA1<8)          ///  нажат выбор реж
                   {
                    if  (Mode_SLCT <2) Mode_SLCT++;
                        else   Mode_SLCT=0;
                   }       
            if  (Mode_SLCT ==0)
                  {
                    LCD_PutChar (0, 0 ,80);             //P
                    LCD_PutChar (9, 0 ,79);        //O     
                    LCD_PutChar (18, 0 ,82);        //R         
                                   nlcd_Line(porog,10,porog, 160, black )  ; 
                              if ( VIBORKA1>75 & VIBORKA1<85)    porog=porog-2  ;   // ацп канал 0  выход =80 нажат минус
                              if (  VIBORKA1>98 & VIBORKA1<108)    porog=porog+2  ;   // ацп канал 0  выход =103  нажат плюс       
                               nlcd_Line(porog,10,porog, 160, yellow )  ;         
                             print_int( 36,0,  porog);   
                         }
                         
             if  (Mode_SLCT ==1)
                   {  LCD_PutChar (0, 0 ,77);             //M
                    LCD_PutChar (9, 0 ,88);              //X   
                    LCD_PutChar (18, 0 ,61);          //=     
                              if (   VIBORKA1>75 & VIBORKA1<85)      multiplerX++ ;  // ацп канал 0  выход =80 нажат минус
                              if (  VIBORKA1>98 & VIBORKA1<108)     multiplerX-- ;   // ацп канал 0  выход =103  нажат плюс   
                              if (multiplerX==0 )      multiplerX= 1 ;           
                             print_int( 36,0, multiplerX);     
                    }     
               if  (Mode_SLCT ==2)
                   {  LCD_PutChar (0, 0 ,77);             //M
                    LCD_PutChar (9, 0 ,89);              //X   
                    LCD_PutChar (18, 0 ,61);          //=     
                              if (   VIBORKA1>75 & VIBORKA1<85)     { multiplerY=1; DEL_ON  ;  }  // ацп канал 0  выход =80 нажат минус
                              if (  VIBORKA1>98 & VIBORKA1<108)     { multiplerY=0 ;DEL_OFF;  }  // ацп канал 0  выход =103  нажат плюс   
                     
                             print_int( 36,0, multiplerY);     
                    }       
                   
                   
            }
Вложения
кнопки.PNG
кнопки в ТВ
(55.87 КБ) 611 скачиваний
ух ты.... показывает
Аватара пользователя
prinv
Вымогатель припоя
Сообщения: 677
Зарегистрирован: Чт янв 20, 2011 09:07:08
Откуда: Пермь
Контактная информация:

Программный антидребезг

Сообщение prinv »

Котаны, поделитесь удачными примерами программного антидребезга.
Делаю сейчас вот так

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

      // Чтение клавиатуры
      do
         {
            _delay_ms(50);      // Задержка от дребезга контактов      
            Key1   =   PIND & ~PINSQW; // На PINSQW приходит меандр 1 Гц от DS1307, исключаем меандр из опроса клавиш.
            _delay_ms(50);
            Key2   =   PIND & ~PINSQW;
         }
      while (Key1 != Key2);

Но иногда не срабатывает, а иногда наоборот, дребезг всё-таки пролетает.
Помогут ли кондёры 0.1uF параллельно тактовым кнопкам?
Триггеры Шмидта будут в следующей конструкции.
Никакая контра не уйдёт от нас
Аватара пользователя
Oxford
Опытный кот
Сообщения: 819
Зарегистрирован: Вт окт 23, 2012 13:17:25
Откуда: Прокопьевск
Контактная информация:

Re: Программный антидребезг

Сообщение Oxford »

https://www.youtube.com/watch?v=VD8OaPyAEtI
Тут хороший алгоритм разжеван. Сможете настроить фильтр.
Инженер R@D

Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
Аватара пользователя
prinv
Вымогатель припоя
Сообщения: 677
Зарегистрирован: Чт янв 20, 2011 09:07:08
Откуда: Пермь
Контактная информация:

Re: Программный антидребезг

Сообщение prinv »

Большое спасибо!
Алгоритм понятен, попробую реализовать - посмотрим что получится.
Никакая контра не уйдёт от нас
Demiurg
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44
Контактная информация:

Re: Программный антидребезг

Сообщение Demiurg »

Спойлер

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

// kbd_drv.h

//==================
#ifndef KBD_DRV_H

#define KBD_DRV_H

#include "kbd_drv.h"

#include "main_def_func.h"
//==================

//==================
#ifdef __PROJECT_MODE_WORK__
#define DEBOUNCE_DELAY 30
#define HOLD_1_DELAY 1500
#define HOLD_2_DELAY 2500

#define REPEAT_1_DELAY 150
#define REPEAT_2_DELAY 50
#endif

#ifdef __PROJECT_MODE_DEBUG__
#define DEBOUNCE_DELAY 3
#define HOLD_1_DELAY 5
#define HOLD_2_DELAY 7

#define REPEAT_1_DELAY 5
#define REPEAT_2_DELAY 3
#endif
//==================

//==================
#define KEY_ENTER          1
#define KEY_ENTER_BIT      1<<KEY_ENTER
//----------
#define KEY_MINUS          2
#define KEY_MINUS_BIT      1<<KEY_MINUS
//----------
#define KEY_PLUS           0
#define KEY_PLUS_BIT       1<<KEY_PLUS
//==================

//==================
#define KEYS_MASK          (KEY_ENTER_BIT | KEY_MINUS_BIT | KEY_PLUS_BIT)
//==================

//==================
typedef enum kbd_codes
{
   KEY_ENTER_COD = 1,
   KEY_MINUS_COD,
   KEY_PLUS_COD,
} kbd_codes;
//==================

//==================
#define HOLD   1<<7
#define REPEAT 1<<6

#define KEY_ENTER_HOLD_COD (KEY_ENTER_COD | HOLD)
#define KEY_MINUS_HOLD_COD (KEY_MINUS_COD | HOLD)
#define KEY_PLUS_HOLD_COD  (KEY_PLUS_COD  | HOLD)

#define KEY_ENTER_REPEAT_COD (KEY_ENTER_COD | REPEAT)
#define KEY_MINUS_REPEAT_COD (KEY_MINUS_COD | REPEAT)
#define KEY_PLUS_REPEAT_COD  (KEY_PLUS_COD  | REPEAT)
//==================

//==================
//#define KEY1_PRESSED() ((KEYS1_PIN & (1<<BIT_KEY1) == 0)
//#define KEY1_UNPRESSED() ((KEYS1_PIN & (1<<BIT_KEY1) == 1)

#define Set_Is_Key_Enter_Pressed() !(check_bit (spi_receive_buf [0], KEY_ENTER)) // Low level.
//#define Set_Is_Key_Enter_Pressed() check_bit (KEY_ENTER_PIN, KEY_ENTER) // High level.


#define Set_Is_Key_Minus_Pressed() !(check_bit (spi_receive_buf [0], KEY_MINUS)) // Low level.
//#define Set_Is_Key_Minus_Pressed() check_bit (KEY_MINUS_PIN, KEY_MINUS) // High level.

#define Set_Is_Key_Plus_Pressed()  !(check_bit (spi_receive_buf [0], KEY_PLUS)) // Low level.
//#define Set_Is_Key_Plus_Pressed()  check_bit (KEY_PLUS_PIN, KEY_PLUS) // High level.

// Ïðè ðàáîòå ñ áóôåðîì âõîäîâ (ðàñøèðåíèå ââîäà-âûâîäà):
// #define Set_Is_Key_Stop_Pressed()   check_bit (inputs_buf [0], KEY_STOP)
//==================

//==================
typedef enum _kbd_drv
{
   KBD_DRV_INIT = 0,
   KBD_DRV_NOCHANGE,
   KBD_DRV_CHANGE,
   KBD_DRV_HOLD_REPEAT,
} kbd_drv_t;
//==================

//==================
typedef enum kbd_drv_mode
{
   KBD_DRV_NO_MODE,
   KBD_DRV_NOUNPRESS,
   KBD_DRV_HOLD,
   KBD_DRV_REPEAT_1,
   KBD_DRV_REPEAT_2,
} kbd_drv_mode_t;
//==================

//==================
u08 scan_keys (void);

void kbd_drv (void);

void kbd_drv_init (void);
void kbd_drv_nochange (void);
void kbd_drv_change (void);
void kbd_drv_hold_repeat (void);

u08 recoding_keys (void);

u08 GetKeyCode (void);
//==================

#endif



Спойлер

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

//==================
#include "kbd_drv.h"
//==================

//==================
static kbd_drv_t _kbd_drv;
static kbd_drv_mode_t kbd_drv_mode;

static u08 keys_prev;
static u08 keys_curr;
static u08 keys_buf;

static soft_timer ST_KBD_1;
static soft_timer ST_KBD_2;
//==================

//==================
u08 scan_keys (void)
{
   u08 a = 0;

   if (Set_Is_Key_Enter_Pressed ())   a |= KEY_ENTER_BIT;
   if (Set_Is_Key_Plus_Pressed ())    a |= KEY_PLUS_BIT;
   if (Set_Is_Key_Minus_Pressed ())   a |= KEY_MINUS_BIT;

   return a;
}
//==================

//==================
void kbd_drv (void)
{
   keys_curr = scan_keys ();

   switch (_kbd_drv)
   {
      case KBD_DRV_INIT:        kbd_drv_init ();        break;
      case KBD_DRV_NOCHANGE:    kbd_drv_nochange ();    break;
      case KBD_DRV_CHANGE:      kbd_drv_change ();      break;
      case KBD_DRV_HOLD_REPEAT: kbd_drv_hold_repeat (); break;
   }
}
//==================

//==================
#ifdef __PROJECT_MODE_WORK__
#pragma inline = forced
#endif
void kbd_drv_init (void)
{
   #ifdef __PROJECT_MODE_DEBUG__
   spi_receive_buf [0] = 0xFF;
   #endif

   kbd_drv_mode = KBD_DRV_NOUNPRESS;
   keys_prev = 0xFF;
   _kbd_drv = KBD_DRV_NOCHANGE;
}
//----------
#ifdef __PROJECT_MODE_WORK__
#pragma inline = forced
#endif
void kbd_drv_nochange (void)
{
   if (keys_prev != keys_curr) // Если предыдущее состояние кнопок не равно предыдущему.
   {
      keys_prev = keys_curr;

      reset_soft_timer (ST_KBD_2);
      set_soft_timer (ST_KBD_1, DEBOUNCE_DELAY, 0); // Таймер подавления дребезга.
      _kbd_drv = KBD_DRV_CHANGE;
   }
}
//----------
#ifdef __PROJECT_MODE_WORK__
#pragma inline = forced
#endif
void kbd_drv_change (void)
{
   if (keys_prev == keys_curr)
   {
      if (handle_soft_timer (ST_KBD_1)) // Таймер подавления дребезга.
      {
         if (keys_curr)
         {
            Set_Event (EV_ID_KEY_PRESSED, USER_EVENT);
            keys_buf = recoding_keys ();

            set_soft_timer (ST_KBD_1, HOLD_1_DELAY, 0); // Установка таймера удержания.
            kbd_drv_mode = KBD_DRV_HOLD;

            _kbd_drv = KBD_DRV_HOLD_REPEAT;
         }
         else
         {
            if (kbd_drv_mode == KBD_DRV_NOUNPRESS)
               kbd_drv_mode = KBD_DRV_NO_MODE;
            else
               Set_Event (EV_ID_KEY_UNPRESSED, USER_EVENT);

            _kbd_drv = KBD_DRV_NOCHANGE;
         }
      }
   }
   else
      _kbd_drv = KBD_DRV_NOCHANGE;
}
//----------
#ifdef __PROJECT_MODE_WORK__
#pragma inline = forced
#endif
void kbd_drv_hold_repeat (void)
{
   if (keys_prev == keys_curr)
   {
      switch (kbd_drv_mode)
      {
         case KBD_DRV_HOLD:
            if (handle_soft_timer (ST_KBD_1))
            {
               Set_Event (EV_ID_KEY_PRESSED, USER_EVENT);
               keys_buf = (recoding_keys () | HOLD);

               set_soft_timer (ST_KBD_1, REPEAT_1_DELAY, REPEAT_1_DELAY);
               set_soft_timer (ST_KBD_2, HOLD_2_DELAY, 0);

               kbd_drv_mode = KBD_DRV_REPEAT_1;
            }
            break;

         case KBD_DRV_REPEAT_1:
            if (handle_soft_timer (ST_KBD_2))
            {
               set_soft_timer (ST_KBD_1, 0, REPEAT_2_DELAY);

               kbd_drv_mode = KBD_DRV_REPEAT_2;
               return;
            }

         case KBD_DRV_REPEAT_2:
            if (handle_soft_timer (ST_KBD_1))
            {
               Set_Event (EV_ID_KEY_PRESSED, USER_EVENT);
               keys_buf = (recoding_keys () | REPEAT);
            }
            break;
      }
   }
   else
      _kbd_drv = KBD_DRV_NOCHANGE;
}
//==================

//==================
u08 recoding_keys (void)
{
   switch (keys_curr)
   {
      case KEY_ENTER_BIT: return KEY_ENTER_COD;
      case KEY_PLUS_BIT:  return KEY_PLUS_COD;
      case KEY_MINUS_BIT: return KEY_MINUS_COD;
   }

   return 0;
}
//==================

//==================
u08 GetKeyCode (void)
{
   return keys_buf;
}
//==================
Аватара пользователя
prinv
Вымогатель припоя
Сообщения: 677
Зарегистрирован: Чт янв 20, 2011 09:07:08
Откуда: Пермь
Контактная информация:

Re: Программный антидребезг

Сообщение prinv »

У меня вот так получилось
Спойлер

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

      // Чтение клавиатуры
      Key = 0;
      OldKey = 0;
      KeyCount = 0;
      do
         {
            Key = (~PIND) & (PINMODE|PINSET0|PINPLUS|PINMINUS);
            if (Key == OldKey)
            {
               KeyCount++;
            }
            else
            {
               KeyCount = 0;
               OldKey = Key;
            }
            _delay_ms(20);
         }
      while (KeyCount<5);
Никакая контра не уйдёт от нас
Ответить

Вернуться в «Периферия»