Конечный автомат. Автоматное программирование.
Цикл статей Татарчевского.Есть нюанс. Так как кнопка одна, вам нужно тщательно продумать интерфейс, чтобы не было проблем. Нужно четко отличать, в каком состоянии какое нажатие. Иначе вы будете ожидать одной реакции на нажатия, а будет совершенно другая, так как не продуман интерфейс.
К примеру, исходное состояние девайса. Он должен ждать только короткое нажатие или только длинное. Или два коротких, к примеру. Два длинных.
В принципе, в одном состоянии можно ожидать короткое либо длинное нажатие. Но, повторяю, тщательно продумывайте. И без использования конечных автоматов не обойтись, если параллельно нужно выполнять какие-либо еще действия.
Программа будет примерно такая:
Опрос кнопки:
CODE
//========================================================================
#include "kbd_drv.h"
//========================================================================
//========================================================================
u08 _kbd_drv;
static u08 keys_buf;
//========================================================================
//========================================================================
void kbd_drv (void)
{
switch (_kbd_drv)
{
case KBD_DRV_NONE: // Состояние ожидания нажатия кнопки.
if (!(KNOPKA_PIN & (1<<KNOPKA))) // Если кнопка нажата,
{
set_timer (ST_KBD_1, DEBOUNCE_DELAY); // то установка таймера на подавление дребезга.
_kbd_drv = KBD_DRV_DOWN;
}
break;
case KBD_DRV_DOWN: // Подавление дребезга нажатия кнопки.
if (KNOPKA_PIN & (1<<KNOPKA))
{
_kbd_drv = KBD_DRV_NONE;
}
else
{
if (wait (ST_KBD_1)) // Если время подавления дребезга вышло,
{
Set_Event (EV_ID_KEY_PRESSED, SET_CLR_EVENT);
keys_buf = KEY_COD;
set_timer (ST_KBD_1, HOLD_DELAY); // то установка таймера на проверку удержания кнопки.
_kbd_drv = KBD_DRV_HOLD;
}
}
break;
case KBD_DRV_HOLD:
if (KNOPKA_PIN & (1<<KNOPKA))
{
_kbd_drv = KBD_DRV_WAIT_UP; // Установка состояния ожидания отжатия кнопки.
}
else
{
if (wait (ST_KBD_1)) // Если время удержания кнопки вышло,
{
Set_Event (EV_ID_KEY_PRESSED, SET_CLR_EVENT);
keys_buf = KEY_COD_HOLD;
set_timer (ST_KBD_1, HOLD_DELAY);
}
}
break;
case KBD_DRV_WAIT_UP: // Состояние ожидания отжатия кнопки.
if (KNOPKA_PIN & (1<<KNOPKA)) // Если кнопка отжата,
{
set_timer (ST_KBD_1, DEBOUNCE_DELAY); // то установка таймера на подавление дребезга.
_kbd_drv = KBD_DRV_UP;
}
break;
case KBD_DRV_UP: // Подавление дребезга отжатия кнопки.
if (!(KNOPKA_PIN & (1<<KNOPKA))) // Если кнопка нажата,
{
_kbd_drv = KBD_DRV_WAIT_UP;
}
else
{
if (wait (ST_KBD_1)) // Если время подавления дребезга вышло,
{
Set_Event (EV_ID_KEY_UNPRESSED, SET_CLR_EVENT);
_kbd_drv = KBD_DRV_NONE; // Установка состояния ожидания нажатия кнопки.
}
}
break;
default:
break;
}
}
//========================================================================
//========================================================================
u08 GetKeyCod (void)
{
return keys_buf;
}
//========================================================================
Выбор режима в зависимости от нажатий кнопки:
CODE
//========================================================================
#include "proc_fsm.h"
//========================================================================
//========================================================================
void proc_fsm (void)
{
static u08 _proc_fsm;
switch (_proc_fsm)
{
case PROC_FSM_INIT:
// Инициализация ввода-вывода
_proc_fsm = PROC_FSM_WAIT_KEYS_PRESSED;
break;
case PROC_FSM_WAIT_KEYS_PRESSED:
if (Get_Event (EV_ID_KEY_PRESSED)) // Если событие нажатия кнопки,
{
_proc_fsm = PROC_FSM_WAIT_SELECT_MODE; // то установка состояния выбора нажатия.
}
break;
case PROC_FSM_WAIT_SELECT_MODE:
if (Get_Event (EV_ID_KEY_UNPRESSED)) // Если событие отжатия кнопки, то это в любом случае было короткое нажатие.
{
set_led_1_blink_on (); // Включаем мигание светодиодом.
_proc_fsm = PROC_FSM_MODE_1;
return;
}
if (Get_Event (EV_ID_KEY_PRESSED)) // Если повторное событие нажатия кнопки, то это длинное нажатие кнопки.
{
led_1_on (); // Включаем светодиод.
_proc_fsm = PROC_FSM_MODE_2;
return;
}
break;
case PROC_FSM_MODE_1:
if (Get_Event (EV_ID_KEY_PRESSED)) // Если событие нажатия кнопки,
{
set_led_1_blink_off (); // то выключаем мигание светодиодом.
_proc_fsm = PROC_FSM_WAIT_KEYS_PRESSED;
return;
}
led_1_blink (); // Мигание светодиодом.
break;
case PROC_FSM_MODE_2:
if (Get_Event (EV_ID_KEY_UNPRESSED)) // Если событие отжатия кнопки,
{
led_1_off (); // то выключаем светодиод.
_proc_fsm = PROC_FSM_WAIT_KEYS_PRESSED;
}
break;
default:
break;
}
}
//========================================================================
//========================================================================
static u08 _led_blink;
#pragma inline
void set_led_1_blink_on (void)
{
led_1_on ();
set_timer (ST_LED_1_BLINK, LED_1_TIME);
_led_blink = 1;
}
#pragma inline
void set_led_1_blink_off (void)
{
led_1_off ();
_led_blink = 0;
}
#pragma inline
void led_1_blink (void)
{
switch (_led_blink)
{
case 0:
break;
case 1:
if (wait (ST_LED_1_BLINK))
{
led_1_switch ();
set_timer (ST_LED_1_BLINK, LED_1_TIME);
}
break;
default:
break;
}
}
//------------------------------------------------------------------------
#pragma inline
void led_1_on (void)
{
set_bit (LED_1_DDR, LED_1);
}
#pragma inline
void led_1_off (void)
{
clr_bit (LED_1_DDR, LED_1);
}
#pragma inline
void led_1_switch (void)
{
switch_bit (LED_1_DDR, LED_1);
}
//========================================================================