Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Тема закрыта

Re: Обработка нажатия кнопки в AVR...

Пн июн 24, 2013 01:21:14

Alexeyslav писал(а):По факту достаточно ОДНОГО защелкивания. Ведь в процессе дребезга на момент защелкивания может быть считано только одно из двух 1 или 0. Но поскольку конкретно этот момент считывания обрамляют разные уровни 1 и 0 либо 0 и 1 то каким бы ни было считывание в момент дребезга оно лишь приведет к отставанию считывания реального состояния кнопки максимум на время одного опроса.
Я думаю что не достаточно ОДНОГО защелкивания....
Напимер если прибор работает в условиях помех, то запросто возможна ситуация, когда единичное чтение даст положительный результат.... как результат - выполнится какое то действие....

Я только через счетчик защелки опрашиваю кнопки, так 100% надежно.....
Давно уже состряпал себе такую либу, опрос 4-х кнопок (короткое, длинное нажатие)
Спойлер
Код:
//#######################################################################################################################
//#
//#    ФУНКЦИИ РАБОТЫ С КЛАВОЙ
//#
//# в начале проинитить библиотеку вызовом BtnInit();
//# организовать вызов из прерывания с частотой 100Гц - функцию BtnExe();
//# чтение значения состояния флагов кнопок производится с помощью функции BtnGet();
//# например так: 
//# char BtnMask = BtnGet();
//# if (BtnMask & BTN_SHRT_UP)      {....ветка короткого нажатия кнопки UP}
//# if (BtnMask & BTN_SHRT_DN)      {....ветка короткого нажатия кнопки DN}
//# if (BtnMask & BTN_LONG_RIGHT)   {....ветка длинного нажатия кнопки RIGHT}
//# и т.д.
//#
//#######################################################################################################################

//настройка параметров работы функций
#define BTN_LOCK_TIME         30                /*время обработки дребезга в милисекундах (10-100)*/
#define BTN_LONG_TIME        1000            /*время фиксации длинного нажатия в милисекундах (1000 - 2500)*/

//настройки портов
#define BTN_PORT        PORTC                    /*порт чтения кнопок*/
#define BTN_DDR            DDRC
#define BTN_PIN         PINC                    
    #define BTN_LINE_UP     (1<<0)                /*пины чтения кнопок*/
    #define BTN_LINE_DN     (1<<1)
    #define BTN_LINE_LEFT    (1<<2)
    #define BTN_LINE_RIGHT    (1<<3)
    
//глобальные переменные
volatile uint8_t BtnFlags;                        //байт флагов нажатия кнопки
    #define BTN_SHRT_UP        (1<<0)                /*бит короткого нажатия кнопки up*/ 
    #define BTN_SHRT_DN        (1<<1)                /*бит короткого нажатия кнопки dn*/ 
    #define BTN_SHRT_LEFT    (1<<2)                /*бит короткого нажатия кнопки left*/ 
    #define BTN_SHRT_RIGHT    (1<<3)                /*бит короткого нажатия кнопки right*/ 
    #define BTN_LONG_UP        (1<<4)                /*бит длинного нажатия кнопки up*/ 
    #define BTN_LONG_DN        (1<<5)                /*бит длинного нажатия кнопки dn*/ 
    #define BTN_LONG_LEFT    (1<<6)                /*бит длинного нажатия кнопки left*/ 
    #define BTN_LONG_RIGHT    (1<<7)                /*бит длинного нажатия кнопки right*/ 


//#######################################################################################################################
//функция настройки библиотеки работы с кнопками
void BtnInit (void)
{
    
    BTN_DDR 
&= ~(BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_LEFT| BTN_LINE_RIGHT);    //на ввод
    BTN_PORT |= (BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_LEFT| BTN_LINE_RIGHT);    //подтяжка вкл
}

//----------
//функция чтения данных о нажатии кнопок
char BtnGet (void)
{
    cli ();
    char temp = BtnFlags;
    BtnFlags = 0;
    sei ();
    return temp;
}

//----------
//ФУНКЦИЯ ОБРАБОТКИ НАЖАТИЙ КЛАВИШ (вызывать в прерывании с частотой 100 Гц)
//короткое нажатие устанавливает бит BTN_SHRT_X глобальной переменной BtnFlags
//длинное нажатие устанавливает бит BTN_LONG_X глобальной переменной BtnFlags
void BtnExe (void)
{
    
    static unsigned char BtnLockBit
;            //ащелка (защита от дребезга)
    static unsigned char BtnLockCoun;            //счетчик защелки (защита от дребезга)
    static unsigned char BtnLongCoun;            //счетчик длинного нажатия
    static unsigned char BtnLastState;            //последнее состояние кнопок перед отпусканием

    char mask = 0;
    if (! (BTN_PIN & BTN_LINE_UP))        mask = BTN_SHRT_UP;
    if (! (BTN_PIN & BTN_LINE_DN))        mask = BTN_SHRT_DN;
    if (! (BTN_PIN & BTN_LINE_LEFT))    mask = BTN_SHRT_LEFT;
    if (! (BTN_PIN & BTN_LINE_RIGHT))    mask = BTN_SHRT_RIGHT;
    
    if 
(mask){                                    //опрос состояния кнопки
        if (BtnLockCoun < (BTN_LOCK_TIME/10)){    //клавиша нажата
            BtnLockCoun++;
            return;                                //защелка еще не дощитала - возврат
        }
        BtnLastState = mask;
        BtnLockBit =1;                            //нажатие зафиксировано                
        if (BtnLongCoun >= (BTN_LONG_TIME/10))                                
            return
;                                //возврат, т.к. счетчик длинн нажат досчитал до максимума еще раньше        
        if (++BtnLongCoun >= (BTN_LONG_TIME/10))
            BtnFlags |= (BtnLastState<<4);        //счетчик досчитал до максимума - устанавливаем биты длинного нажатия 
    }            
    else
{                                        //клавиша отжата            
        if (BtnLockCoun){
            BtnLockCoun --;
            return;                                //защелка еще не обнулилась - возврат
        }
        if (! BtnLockBit)                        //СТАТИЧЕСКИЙ ВОЗВРАТ
            return;                                
        BtnLockBit 
=0;                            //отжатие зафиксировано
        if (BtnLongCoun < (BTN_LONG_TIME/10))
            BtnFlags |= BtnLastState;            //установка бита короткого нажатия
        BtnLongCoun = 0;                        //сброс счетчика длительности нажатия
    }
}
    

//#######################################################################################################################
 

Re: Обработка нажатия кнопки в AVR...

Пн июн 24, 2013 10:45:48

Вероятность такого события довольно низка. А если у вас в условиях применения схемы так сильно прут помехи, боюсь там проблем будет выше крыши не только с кнопками. В крайнем случае, импульсные помехи сглаживает обычная RC-цепочка(но она не избавляет от дребезга реальной кнопки).

Re: Обработка нажатия кнопки в AVR...

Вт июл 02, 2013 22:02:15

Alexeyslav писал(а):Вероятность такого события довольно низка. А если у вас в условиях применения схемы так сильно прут помехи, боюсь там проблем будет выше крыши не только с кнопками. В крайнем случае, импульсные помехи сглаживает обычная RC-цепочка(но она не избавляет от дребезга реальной кнопки).
Да, например плата компактная и помехи ей не страшны..... но если кнопки расположены не на плате, и подключены шлейфом.... Вот вам и подвох.....
Поклацайте выключателем рядом с таким прибором..... (а сам прибор работает отменно, никаких проблем выше крыши.....)
Можно конечно поставить RC на каждую кнопку..... Ну а можно и программно решить.... тут уж на вкус и цвет....

Re: Обработка нажатия кнопки в AVR...

Вт июл 02, 2013 22:46:20

Вероятность того что помеха от соседнего выключателя попадет ровно на момент опроса кнопки стремится к нулю. Чтобы эту вероятность повысить до приемлемого уровня, кнопку надо нажимать примерно с частотой опроса или чаще, ну либо коллекторный двигатель с неисправными щетками поднести к схеме.
В случае прерываний на кнопках, эти импульсы 100% будут фиксироваться....

Но нет ничего идеального... вот мой бесперебойник с ума сходит если поднести к нему включенную радиостанцию, всего 0.5Вт.

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

Да, работает у меня одно устройство с кнопкой(геркон) которая просто опрашивается с частотой 100Гц - уже десяток лет, ложных срабатываний не обнаружено. Условия, правда, бытовые а не промышленные.

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

Re: Обработка нажатия кнопки в AVR...

Пт ноя 08, 2013 15:27:40

Всем привет, пытаюсь сделать себе небольшое устройство но с кнопкой так и не разберусь. Суть такая устройство управляет яркостью диодов в двух режимах и запоминает эти уровни яркости, но смог сделать запись данных только при выходе из цикла, но как сделать запись по нажатию кнопки так и не смог разобраться
Спойлер
Код:
/***
Управляем светодиодом с помощью энкодера ***/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/eeprom.h>

EEMEM uint8_t ee_zn, ee_zc;//* переменная размером в 2 байта в EEPROM
unsigned char  my_y,my_b;
volatile char pwm_counter, button ;

// Обработчик прерывания int0
ISR(SIG_INTERRUPT0)
{
_delay_us(50);
if((PIND & (1 << PD2))==0)
{
_delay_us(50);
if((PIND & (1 << PD0))==0)
{
if(button == 0) //
{
my_y--; if(my_y < 1) my_y = 1;

}

if(button == 1) //

my_b--; if(my_b < 1) my_b = 1;

}
}
 
 else
{
if(button == 0) //
{
my_y++; if(my_y > 65) my_y = 65;

}

if(button == 1) //

my_b++; if(my_b > 65) my_b = 65;


}
}
}
GIFR = (1<<INTF0);
return;

}


ISR (TIMER0_OVF_vect)
{
{
if (button == 0)
{
if (pwm_counter++ > 65)
{
PORTB = 0x00;
pwm_counter = 0;
}
if (pwm_counter > my_y)
PORTB |= (1 << PB0);
}
}
{
if (button == 1)
{
if (pwm_counter++ > 65)
{
PORTB = 0x00;
pwm_counter = 0;
}
if (pwm_counter > my_b)
PORTB |= (1 << PB0);
}
}
}



// Главная функция
 
int main (void)
{
DDRB |= (1 << PB0)|(1 << PB1); // выходы
PORTB = 0x00;
DDRD |= (1 << PD3)|(0 << PD2)|(0 << PD1)|(0 << PD0); // входы
PORTD |= (1 << PD2)|(1 << PD1)|(1 << PD0)|(0 << PD3); // подключаем подтягивающие резисторы
TIMSK |= (1 << TOIE0); // разрешение прерывания по таймеру0
TCCR0 |= (1 << CS00);
 
MCUCR |= (0 << ISC00)|(1 << ISC01); // прерывание по заднему фронту INT0(по спаду импульса)
 
GIFR |= (1 << INTF0);     // очищаем флаг внешнего прерывания
GICR |= (1 << INT0);      // разрешаем внешние прерывания INT0
sei(); //глобально разрешаем прерывания

while(1)
{
while(3)
{
if
((PIND & (1 << PD3))==0) break;
button = 0;
my_y = eeprom_read_byte(&ee_zn);//чтение первой переменной
_delay_ms(1000);
eeprom_write_byte(&ee_zn, my_y);//запись первой переменной

}

button = 1;
my_b = eeprom_read_byte(&ee_zc);//чтение второй переменной   
_delay_ms(1000);
eeprom_write_byte(&ee_zc, my_b);//запись второй переменной

}
}


как сделать чтобы переменные записывались по нажатию кнопки энкодера

Re: Обработка нажатия кнопки в AVR...

Вт дек 17, 2013 01:08:10

Naman_S писал(а):как сделать запись по нажатию кнопки так и не смог разобраться
Уже разобрался?

Re: Обработка нажатия кнопки в AVR...

Пн фев 03, 2014 21:53:03

shads нет, если поможешь буду благодарен

Re: Обработка нажатия кнопки в AVR...

Пн фев 03, 2014 23:25:36

Naman_S писал(а):shads нет, если поможешь буду благодарен

Ну тады подробнее алгоритм распишите... Меньше времени уйдет, если со своего кода набросать... чем в вашем разбиратся... (а время то - деньги...)

Re: Обработка нажатия кнопки в AVR...

Пн фев 03, 2014 23:31:00

viewtopic.php?f=57&t=93727 вот темку создавал заходи туда

Re: Обработка нажатия кнопки в AVR...

Вт фев 04, 2014 01:15:51

Так собственно проблема в чем, отловить момент нажатия кнопки, или записать в EEPROM?
Момент отловить - постоянно сравнивать состояние кнопки с предыдущим, моменты нажатия и отпускания отлавливаются на раз-два, а процедура записи в EEPROM приведена прямо в даташите на контроллер, в виде куска кода. Да, перед записью стоит убедится что записываешь другое значение а не то что там уже есть - чтобы зря ресурс ячеек не расходовать, особенно во время отладки.

Re: Обработка нажатия кнопки в AVR...

Вт фев 04, 2014 01:18:45

Alexeyslav писал(а):Так собственно проблема в чем, отловить момент нажатия кнопки, или записать в EEPROM?
Момент отловить - постоянно сравнивать состояние кнопки с предыдущим, моменты нажатия и отпускания отлавливаются на раз-два, а процедура записи в EEPROM приведена прямо в даташите на контроллер, в виде куска кода. Да, перед записью стоит убедится что записываешь другое значение а не то что там уже есть - чтобы зря ресурс ячеек не расходовать, особенно во время отладки.

с еепром проблем нет, а вот чтобы производить запись по нажатию кнопки с этим уже проблемы

Re: Обработка нажатия кнопки в AVR...

Пн апр 21, 2014 20:08:33

Код:
if (button==0)
{
      _delay_ms (bounce);
      while (button==0) {};
      if(++mode>=5)mode=0;
}

Re: Обработка нажатия кнопки в AVR...

Ср апр 23, 2014 23:00:09

Здравствуйте. Не могу реализовать алгоритм включения нагрузки по нажатию кнопки дважды.
То есть выполнить такой-то код, если кнопка была нажата 2 раза.

Вот моя безуспешная попытка:
Код:
#include <mega8.h>
#include <delay.h>

void main(void)
{
PORTB=0x00;         // PORTB - выход
DDRB=0x01;                 
PORTC=0x01;         // PORTC - вход
DDRC=0x00;

while (1)

{     
unsigned char a=0; // переменной а присвоить 0
    if(PINC.0==0) // если кнопка нажата
    {
    a++;            // инкриминируем а
        if(a==2)    // если а равно 2 (кнопка нажата 2 раза)
        {
        PORTB.0=1;   // выводим 1
        a=0;         // обнуляем а
        }
        }
}
}     

Re: Обработка нажатия кнопки в AVR...

Ср апр 23, 2014 23:44:53

попробуй так
Код:
if(PINC.0==0) // если кнопка нажата
{
      delay_ms (10);
      while (PINC.0==0) {};
    a++;            // инкриминируем а
        if(a==2)    // если а равно 2 (кнопка нажата 2 раза)
        {
        PORTB.0=1;   // выводим 1
        a=0;         // обнуляем а
        }
        }

Re: Обработка нажатия кнопки в AVR...

Чт апр 24, 2014 00:32:45

Вам кроме подсчета нажатий надо бороться с дребезгом(прошлый код был попыткой это сделать) и ОТЛАВЛИВАТЬ моменты нажатия и отпускания(это не реализовано у вас в коде, у вас получается если кнопка нажата больше двух опросов - она считается нажатой дважды) - сделать это можно только сравнивая считанное состояние кнопки с состоянием предыдущим в прошлой итерации. Во вторых, при первом нажатии надо запустить таймер на 1-2 секунды, если второго нажатия не будет за это время - обнулить счетчик нажатий и остановить таймер.

Re: Обработка нажатия кнопки в AVR...

Чт апр 24, 2014 08:09:38

Alexeyslav писал(а):Вам кроме подсчета нажатий надо бороться с дребезгом(прошлый код был попыткой это сделать) и ОТЛАВЛИВАТЬ моменты нажатия и отпускания

Подскажите как ОТЛАВЛИВАТЬ моменты нажатия и отпускания?

Re: Обработка нажатия кнопки в AVR...

Чт апр 24, 2014 08:22:42

100500 раз уже говорилось, что нажатие кнопки и опрос пина - это не одно и то же! проблемы всех кодописателей не исчезнут до тех пор, пока этот факт не будет осознан и учтен в программах.

Re: Обработка нажатия кнопки в AVR...

Чт апр 24, 2014 09:20:22

как ОТЛАВЛИВАТЬ моменты нажатия
Внимательно прочтите сообщение которое перед вашим...

Re: Обработка нажатия кнопки в AVR...

Чт апр 24, 2014 22:13:06

Alexeyslav писал(а):Внимательно прочтите сообщение которое перед вашим...

Извините пожалуйста, читал это сообщение ОЧЕНЬ внимательно, но я не силен в программировании (пока) и не знаю как реализовать это на "С".

Я попробовал осуществить задумку через внешние прерывания, работает вроде так как надо, но почему-то в прерывании одно нажатие считается за два, объясните пожалуйста почему так и подправьте код если не сложно.
Спасибо.
Код:
#include <mega8.h>
#include <delay.h>

char s=0;   // переменная s=0

interrupt [EXT_INT0] void ext_int0_isr(void)//внешние прерывания

{
s++;               //инкриминируем s
        if(s==4)    // если s=4(а не 2, как нужно)
        {
        PORTB.0=0;    // 0 на PORTB.0=0
        s=0;          // обнулить s
        }
       
}

void main(void)
{
DDRB=0x01;
PORTB.0=1;
PORTC=0x01;
DDRC=0x00;

PORTD=0x04;
DDRD=0x00;


GICR|=0x40;
MCUCR=0x01;
GIFR=0x40;
UCSRB=0x00;
SFIOR=0x00;
SPCR=0x00;
TWCR=0x00;

// Global enable interrupts
#asm("sei")

while (s==0) // пока s=0
      { 
       
       PORTB.0=1;
       delay_ms(5000);
      }
}

PS
Я чуток изменил задачу, теперь при подаче питания на PORTB.0 будет 1 пока кнопка не будет нажата 2 раза, после чего произойдет задержка в delay_ms(5000) и PORTB.0 опять будет 1 пока кнопка снова не будет нажата 2 раза.
Очень надеюсь на вашу помощь.

Re: Обработка нажатия кнопки в AVR...

Пт апр 25, 2014 10:23:46

Это не зависит от языка. Напишите программу на русском, потом переводите на С. А вообще, начинать надо с рисования блок-схемы карандашом на листе бумаги, потом переводить на С.

Прерывания... куда вас в СТЕПЬ понесло? Во-первых, задачу решить можно без прерываний а во-вторых работает такая вещь как дребезг контактов - у вас при нажатии кнопки возникает сложный переходный процесс в котором возникает целая пачка импульсов иногда до сотни за раз.
И когда пишете программу, попытайтесь её исполнить в роли процессора - сразу увидите ошибку.
Тема закрыта