Универсальный класс кнопки

ites
Offline
Зарегистрирован: 26.12.2013

Несмотря на то, что я в очередной раз изобретаю велосипед, и подобные классы уже наверняка есть, в большинстве местных тем кнопки обрабатываются вручную. Предлагаю на обсуждение класс, который проверяет клики, даблклики и удержания кнопок. Подразумевается, что в свободном состоянии на входе 1, в нажатом состоянии 0, что в общем довольно стандартно с учётом встроенных подтягивающих резисторов.

class Button {
	byte pin, prev_state;
	bool _clicked, _pressed, _held, _dblclicked;
	unsigned long pressed_time, uct, clct;
	static const unsigned int jtime = 10;
	static const unsigned int htime = 100;
	static const unsigned int dbltime = 300;
public:
	void process_button() {
		byte val = digitalReadFast(pin);
		_clicked = false;
		_dblclicked = false;
		if (val == 0 && prev_state == 1) {
			_pressed = true;
			if (pressed_time == 0)
				pressed_time = millis();
			if (millis() > pressed_time + jtime) {
				uct = 0;
				prev_state = val;
				_clicked = true;
				if (clct != 0 && millis() < clct + dbltime) {
					_dblclicked = true;
				}
				clct = millis();
			}
		} else if (val == 1 && prev_state == 0) {
			_pressed = false;
			if (uct == 0)
				uct = millis();
			if (millis() > uct + jtime) {
				pressed_time = 0;
				prev_state = val;
				_held = false;
				uct = millis();
			}
		}
		if (val == 0 && prev_state == 0 && millis() > clct + htime) {
			_held = true;
		} else {
			_held = false;
		}
	}
	Button(byte _pin) :
			pin(_pin) {
		prev_state = 1;
		_dblclicked = _held = _pressed = _clicked = false;
		clct = uct = pressed_time = 0;
	}

	bool is_clicked() {
		return _clicked;
	}
	unsigned long held_time() {
		if(_held)
			return millis() - clct;
		return 0;
	}
	bool is_dblclicked() {
		return _held;
	}
};

Пример использования:

Button b_next(next_button);
Button b_prev(prev_button);
byte current_alg = 2;

void loop() {
	b_next.process_button();
	b_prev.process_button();
	if (b_next.is_clicked()) {
		++current_alg;
		shift_out(latchpin, clockpin, datapin, 0);
	}
	if (b_prev.is_clicked()) {
		--current_alg;
		shift_out(latchpin, clockpin, datapin, 0);
	}
	if (b_prev.is_dblclicked()) {
		current_alg = random(8);
		shift_out(latchpin, clockpin, datapin, 0);
	}
	if (b_next.is_dblclicked()) {
		current_alg = random(8);
		shift_out(latchpin, clockpin, datapin, 0);
	}
	current_alg &= 7;
// ....... последующий код.....
}

 

ites
Offline
Зарегистрирован: 26.12.2013

Последняя версия. Исправлена ошибка, убрано лишнее. Думаю, что я на этом тему для себя закончил.

class Button {
	byte pin, prev_state;
	bool _clicked, _held, _dblclicked;
	unsigned long pressed_time, uct, clct;
	static const unsigned int jtime = 10;
	static const unsigned int htime = 100;
	static const unsigned int dbltime = 300;
public:
	void process_button() {
		byte val = digitalReadFast(pin);
		_clicked = false;
		_dblclicked = false;
		if (val == 0 && prev_state == 1) {
			uct = 0;
			unsigned long now = millis();
			if (pressed_time == 0)
				pressed_time = now;
			if (now > pressed_time + jtime) {
				prev_state = val;
				_clicked = true;
				if (clct != 0 && now < clct + dbltime) {
					_dblclicked = true;
				}
				clct = pressed_time;
			}
		} else if (val == 1 && prev_state == 0) {
			pressed_time = 0;
			if (uct == 0)
				uct = millis();
			if (millis() > uct + jtime) {
				prev_state = val;
				_held = false;
				uct = millis();
			}
		}
		if (val == 0 && prev_state == 0 && millis() > clct + htime) {
			_held = true;
		} else {
			_held = false;
		}
	}
	Button(byte _pin) :
			pin(_pin) {
		prev_state = 1;
		_dblclicked = _held = _clicked = false;
		clct = uct = pressed_time = 0;
	}

	bool is_clicked() {
		return _clicked;
	}
	unsigned long held_time() {
		if (_held)
			return millis() - clct;
		return 0;
	}
	bool is_dblclicked() {
		return _dblclicked;
	}
};

 

vvadim
Offline
Зарегистрирован: 23.05.2012

A как чайнику воспользоваться данной конструкцией. Например кнопка включает разные режимы светодиода.

ites
Offline
Зарегистрирован: 26.12.2013

vvadim пишет:

A как чайнику воспользоваться данной конструкцией. Например кнопка включает разные режимы светодиода.

Скопировать этот класс себе, заменить digitalReadFast на digitalRead, создать экземпляр класса инициализировав его номером пина, к которому подключена кнопка и опрашивать в loop метод экземпляра is_clicked. Пример использования с разными программами со сдвиговым регистром есть в другой моей теме: http://arduino.ru/forum/programmirovanie/pyatoe-uprazhnenie-po-arduino-shift-out-click-button-digitalreadwritefast