Спойлер
Код: Выделить всё
#include <avr/io.h>
#include <avr/interrupt.h>
#include "Button.h"
typButton aButtons[] = {
{.ddr=&DDRB, .port=&PORTB, .pin=&PINB, .bitmask=_BV(PB0)},
{.ddr=&DDRC, .port=&PORTC, .pin=&PINC, .bitmask=_BV(PC1)},
{.ddr=&DDRD, .port=&PORTD, .pin=&PIND, .bitmask=_BV(PD2)}
};
// every 1 ms
volatile uint8_t Strobe1ms;
ISR(TIMER2_COMPA_vect)
{
Strobe1ms = 1;
}
void Setup(void)
{
btnSetup(sizeof(aButtons) / sizeof(aButtons[0]));
// Timer 2
Strobe1ms = 0;
// Timer2, Mode 2 Clear Timer on Compare Match (CTC) mode, OC2A and OC2B disconnected
TCCR2A = _BV(WGM21);
// T = clkIO/64 = 4 us
TCCR2B = _BV(CS22);
// (249 + 1) * 4 us = 1 ms
OCR2A = 249;
// Output Compare A Match Interrupt Enable
TIMSK2 = _BV(OCIE2A);
// interrupts enable
sei();
}
int main(void)
{
Setup();
while(1) {
if(Strobe1ms) {
Strobe1ms = 0;
btnCheckOnTimer(sizeof(aButtons) / sizeof(aButtons[0]));
uint8_t AllButtonsLongPressed = 1;
for(uint8_t i = 0; i < sizeof(aButtons) / sizeof(aButtons[0]); ++i) {
AllButtonsLongPressed &= (btnRepeat == aButtons[i].state) || (btnAmbRepeat == aButtons[i].state);
switch(aButtons[i].state) {
case btnDbl: // двойной клик
break;
case btnOn: // нажали
break;
case btnRepeat: // автоповтор
break;
default:
break;
}
}
if(AllButtonsLongPressed) {
; // все кнопки нажаты продолжительное время
}
}
}
}
Спойлер
Код: Выделить всё
#ifndef BUTTON_H
#define BUTTON_H
typedef enum {btnOff = 0, btnAmbOn, btnAmbDbl_1, btnAmbDbl_2, btnDbl, btnOn, btnAmbRepeat, btnRepeat} typBtnState;
// in makefile
#ifndef BTN_BEFORE_ON
#define BTN_BEFORE_ON 200 // 200ms
#endif
#ifndef BTN_BEFORE_DBL
#define BTN_BEFORE_DBL 50 // 50ms
#endif
#ifndef BTN_BEFORE_REPEAT
#define BTN_BEFORE_REPEAT 200 // 200ms
#endif
#ifndef BTN_REPEAT_DELAY
#define BTN_REPEAT_DELAY 150 // 150ms
#endif
typedef struct {
volatile uint8_t * ddr;
volatile uint8_t * port;
volatile uint8_t * pin;
const uint8_t bitmask;
typBtnState state;
uint16_t tick;
} typButton;
extern typButton aButtons[];
void btnSetup(uint8_t qtty);
uint8_t btnCheckOnTimer(uint8_t qtty);
#endif
Спойлер
Код: Выделить всё
#include <avr/io.h>
#include "Button.h"
void btnSetup(uint8_t qtty)
{
typButton* pButton = aButtons;
while(qtty--) {
// input
*pButton->ddr &= ~pButton->bitmask;
// pull-up
*pButton->port |= pButton->bitmask;
pButton->state = btnOff;
pButton->tick = 0;
++pButton;
}
}
uint8_t btnCheckOnTimer(uint8_t qtty)
{
uint8_t bNeedCheck = 0;
typButton* pButton = aButtons;
while(qtty--) {
++pButton->tick;
if(*pButton->pin & pButton->bitmask) { // нет нажатия
switch(pButton->state) {
case btnAmbOn: // было нажатие, возможно двойной клик, отпустили раньше
if(BTN_BEFORE_DBL <= pButton->tick) {
pButton->state = btnAmbDbl_1;
pButton->tick = 0;
}
break;
case btnAmbDbl_1: // не нажали повторно для двойного клика
if(BTN_BEFORE_ON <= pButton->tick) {
pButton->state = btnOff;
}
break;
case btnAmbDbl_2: // двойное нажатие
if(BTN_BEFORE_ON <= pButton->tick) { // слишком долгое повторное нажатие, сброс
pButton->state = btnOff;
} else if(BTN_BEFORE_DBL <= pButton->tick) {
pButton->state = btnDbl;
bNeedCheck = 1;
}
break;
default:
pButton->state = btnOff;
break;
}
} else { // зафиксировали нажатие
switch(pButton->state) {
case btnAmbDbl_1: // двойное нажатие
if(BTN_BEFORE_DBL <= pButton->tick) {
pButton->state = btnAmbDbl_2;
pButton->tick = 0;
}
break;
case btnAmbDbl_2: // двойное нажатие, ждем отпускание кнопки
break;
case btnOff: // ничего не было зафиксированно до сих-пор
pButton->state = btnAmbOn;
pButton->tick = 0;
break;
case btnAmbOn: // кнопка возможно нажата
if(BTN_BEFORE_ON <= pButton->tick) {
pButton->state = btnOn; // точно нажата - обработать
pButton->tick = 0;
bNeedCheck = 1;
}
break;
case btnOn:
case btnRepeat:
pButton->state = btnAmbRepeat; // будем ждать автоповтор
// плавно попадаем в btnAmbRepeat
case btnAmbRepeat:
if(BTN_BEFORE_REPEAT <= pButton->tick) {
pButton->state = btnRepeat; // автоповтор
pButton->tick = 0;
bNeedCheck = 1;
}
break;
default:
pButton->state = btnOff; // ерунда какая-то
break;
}
}
++pButton;
}
return bNeedCheck;
}
- Вложения
-
- Buttons.rar
- Проект
- (6.78 КБ) 128 скачиваний


