Пятое упражнение по Arduino: Shift-Out, click button, digital{Read,Write}Fast

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

Мой пятый урок по изучению Arduino. Совершенствую навыки. Программа гоняет 8 светодиодов через сдвиговый регистр (демультиплексор) по 8 разным программам, две кнопки переключения программ. Самостоятельная (очередная) реализация способво записи и чтения цифровых пинов. Начал реализовывать обобщённый класс реагирующий на операции с кнопками. Комментарии приветствуются.

#include <Arduino.h>

#define portWrite(set,mask,port) do {\
		byte state = port;\
		state &= ~mask;\
		state |= set;\
		port = state;\
	} while(0)
#define _digitalWriteFast(P, V) \
	do {\
		if((P) < 8)\
			portWrite((V) << (P),_BV(P), PORTD);\
		else if((P) < 14)\
			portWrite((V) << ((P)-8),_BV((P)-8), PORTB);\
		else\
			portWrite((V) << ((P)-14),_BV((P)-14), PORTC);\
	} while(0)
#define portRead(bit,pin,ret) do {\
		ret = pin;\
		ret >>= bit;\
		ret &= 1;\
	} while(0)

#define _digitalReadFast(P, ret) do {\
	if((P) < 8)\
		portRead((P), PIND, ret);\
	else if((P) < 14)\
		portRead((P)-8, PINB, ret);\
	else\
		portRead((P)-14, PINC, ret);\
	} while(0)

static inline byte digitalReadFast(byte pin) {
	byte ret;
	_digitalReadFast(pin, ret);
	return ret;
}

static inline void digitalWriteFast(byte pin, byte value) {
	_digitalWriteFast(pin, value);
}


#define datapin  2
#define clockpin 3
#define latchpin 4

#define next_button 13
#define prev_button 12

// We'll also declare a global variable for the data we're
// sending to the shift register:

void setup() {
	pinMode(datapin, OUTPUT);
	pinMode(clockpin, OUTPUT);
	pinMode(latchpin, OUTPUT);
	pinMode(next_button, INPUT);
	pinMode(prev_button, INPUT);
}

static byte shift_out_register = 0;

void shift_out(byte latch, byte clock, byte data, byte value) {
	shift_out_register = value;
	digitalWriteFast(latch, 0);
	for (byte i = 0; i < 8; ++i) {
		digitalWriteFast(clock, 0);
		digitalWriteFast(data, value & 1);
		value >>= 1;
		digitalWriteFast(clock, 1);
	}
	digitalWriteFast(latch, 1);
}

void xset(byte latch, byte clock, byte data, byte num, byte value) {
	bitWrite(shift_out_register, num, value);
	shift_out(latch, clock, data, shift_out_register);
}

void binary_count() {
	static unsigned long next_turn = 0;
	static byte data = 0;
	unsigned long time = millis();
	if (time > next_turn) {
		shift_out(latchpin, clockpin, datapin, data);
		data++;
		next_turn = time + 1000;
	}
}

void ping_pong(bool bounce = false) {
	static unsigned long next_turn = 0;
	static byte index = 0;
	unsigned long time = millis();
	if (time > next_turn) {
		index &= 31;
		byte num = index >> 1;
		if (num > 7)
			num = (15 - num);
		if (index & 1) {
			shift_out(latchpin, clockpin, datapin, 0);
			next_turn = time - 1;
		} else {
			xset(latchpin, clockpin, datapin, num, 1);
			if (bounce)
				xset(latchpin, clockpin, datapin, 7 - num, 1);
			next_turn = time + 100;
		}
		++index;
	}
}

void random_led() {
	static unsigned long next_turn = 0;
	static byte index = 0;
	unsigned long time = millis();
	if (time > next_turn) {
		index &= 1;
		byte num = random(8);
		if (index & 1) {
			shift_out(latchpin, clockpin, datapin, 0);
			next_turn = time - 1;
		} else {
			xset(latchpin, clockpin, datapin, num, 1);
			next_turn = time + 100;
		}
		++index;
	}
}

void one_after_another(bool original = false) {
	static unsigned long next_turn = 0;
	static byte index = 0;
	unsigned long time = millis();
	if (time > next_turn) {
		index &= 15;
		byte num = index;
		byte show;
		if (num > 7) {
			if (original) {
				num = 15 - num;
				show = _BV(num+1) - 1;
			} else {
				num &= 7;
				show = ~(_BV(num+1) - 1);
			}
		} else {
			show = _BV(num+1) - 1;
		}
		shift_out(latchpin, clockpin, datapin, show);
		next_turn = time + 100;
		++index;
	}
}

void one_on_at_a_time() {
	static unsigned long next_turn = 0;
	static byte index = 0;
	unsigned long time = millis();
	if (time > next_turn) {
		index &= 7;
		shift_out(latchpin, clockpin, datapin, _BV(index));
		next_turn = time + 100;
		++index;
	}
}

void marquee_nd() {
	static unsigned long next_turn = 0;
	static byte index = 0;
	unsigned long time = millis();
	if (time > next_turn) {
		index &= 3;
		shift_out(latchpin, clockpin, datapin, _BV(index) | _BV(index+4));
		next_turn = time + 200;
		++index;
	}
}

class Button {
	byte pin, prev_state;
	bool _clicked;
	void process_button() {
		byte val = digitalReadFast(pin);
		_clicked = false;
		if(val == 0 && prev_state == 1) {
			_clicked = true;
		}
		prev_state = val;
	}
public:
	Button(byte _pin) :
			pin(_pin) {
		prev_state = 1;
		_clicked = false;
	}

	bool is_clicked() {
		process_button();
		return _clicked;
	}
};

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

void loop() {
	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);
	}
	current_alg &= 7;
	switch (current_alg) {
	case 0:
		binary_count();
		break;
	case 1:
		ping_pong(true);
		break;
	case 2:
		ping_pong(false);
		break;
	case 3:
		random_led();
		break;
	case 4:
		one_after_another(false);
		break;
	case 5:
		one_after_another(true);
		break;
	case 6:
		one_on_at_a_time();
		break;
	case 7:
		marquee_nd();
		break;
	}
}

int main(void) {
	init();
	setup();
//endless loop
	for (;;) {
		loop();
	}
	return 0;
}

 

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

Забыл добавить, что результат очень похож на программу для управления гирляндой :)