#ifndef ShiftIn_h
#define ShiftIn_h
#include "Arduino.h"
template<byte chipCount, typename ShiftType>
class _ShiftIn {
private:
byte ploadPin;
byte clockEnablePin;
byte dataPin;
byte clockPin;
const uint16_t dataWidth;
uint8_t pulseWidth;
ShiftType lastState;
ShiftType currentState;
public:
_ShiftIn() : dataWidth(chipCount * 8), pulseWidth(5), lastState(0), currentState(0) {}
// setup all pins
void begin(int pload, int clockEN, int data, int clock) {
pinMode(ploadPin = pload, OUTPUT);
pinMode(clockEnablePin = clockEN, OUTPUT);
pinMode(dataPin = data, INPUT);
pinMode(clockPin = clock, OUTPUT);
}
inline uint8_t getPulseWidth() { return pulseWidth; }
inline void setPulseWidth(uint8_t value) { pulseWidth = value; }
inline uint16_t getDataWidth() { return dataWidth; }
// whether some value has changed
inline boolean hasChanged() { return lastState != currentState; }
// whether the value with index 'id' has changed
inline boolean hasChanged(int id) { return state(id) != last(id); }
// returns the state from the last frame
inline ShiftType getLast() { return lastState; }
// returns the current state
inline ShiftType getCurrent() { return currentState; }
// whether button 'id' is pressed or not
inline boolean state(int id) { return bitRead(currentState, id); }
// whether button 'id' was pressed in the last frame
inline boolean last(int id) { return bitRead(lastState, id); }
// whether button 'id' is now pressed, but wasn't pressed in the last frame
inline boolean pressed(int id) { return !last(id) && state(id); }
// whether button 'id' is now released, but was pressed in the last frame
inline boolean released(int id) { return last(id) && !state(id); }
// read in data from shift register and return the new value
ShiftType read() {
lastState = currentState;
ShiftType result = 0;
digitalWrite(clockEnablePin, HIGH);
digitalWrite(ploadPin, LOW);
delayMicroseconds(pulseWidth);
digitalWrite(ploadPin, HIGH);
digitalWrite(clockEnablePin, LOW);
for(uint16_t i = 0; i < dataWidth; i++) {
ShiftType value = digitalRead(dataPin);
result |= (value << ((dataWidth-1) - i));
digitalWrite(clockPin, HIGH);
delayMicroseconds(pulseWidth);
digitalWrite(clockPin, LOW);
}
currentState = result;
return result;
}
// same as read, but it returns whether something has changed or not
boolean update() {
return read() != lastState;
}
};
// fallback with 64 bit state (up to 8 shift registers)
template<byte chipCount>
class ShiftIn : public _ShiftIn<chipCount, uint64_t> {};
// single shift register (8 bit state)
template<>
class ShiftIn<1> : public _ShiftIn<1, uint8_t> {};
// two shift registers (16 bit state)
template<>
class ShiftIn<2> : public _ShiftIn<2, uint16_t> {};
// three shift registers (32 bit state)
template<>
class ShiftIn<3> : public _ShiftIn<3, uint32_t> {};
// four shift registers (32 bit state)
template<>
class ShiftIn<4> : public _ShiftIn<4, uint32_t> {};
#endif
//LED
int SER_Pin = 12; //pin 14 on the 75HC595
int RCLK_Pin = 11; //pin 12 on the 75HC595
int SRCLK_Pin = 13; //pin 11 on the 75HC595
//LED
#define number_of_74hc595s 2 //How many of the shift registers - change this
//do not touch LED
#define numOfRegisterPins number_of_74hc595s * 8
//LED
boolean registers[numOfRegisterPins];
// Declare an array of a given length and initialize its values:
//int ledPins[9] = {1,2,3,4,5,6,9,10,11}; //all led pins to 74hc595
int ledPins[12] = {0,1,2,3,4,5,6,7,8,9,10,11}; //all led pins to 74hc595
//int ledPins[9] = {1,2,3,4,5,6,9,10,11}; //all led pins to 74hc595
int ledPinsWin[8] = {1,4,9,10,11,6,3,2}; //led pattern if game is won
int ledPinsLoose[5] = {1,3,5,9,11}; //led pattern if game is won
int lanaDelRay = 100; //main delay after the led is on and waiting for buttonpress
int lanaDelWin = 20; //delay for win pattern
int lanaDelLoose = 200; //delay for win pattern
byte randomLed; //random led for game
unsigned long previousMillis = 0;
const long ledOnInterval = 2000; // Time the LED is ON in milliseconds
const long ledOffInterval = 20000; // Time the LED is OFF in milliseconds
boolean ledState = LOW;
static int gameLevel = 0; // Keep track of the game level
static boolean gameActive = false; // Flag to indicate if the game is active
static unsigned long gameStartTime; // Timestamp to track the start time of each level
// Init ShiftIn instance with one chip. //BUTTONS
// The number in brackets defines the number of daisy-chained 74HC165 chips
// So if you are using two chips, you would write: ShiftIn<2> shift;
ShiftIn<2> shift;
void setup() {
Serial.begin(9600);
//led part
pinMode(SER_Pin, OUTPUT);
pinMode(RCLK_Pin, OUTPUT);
pinMode(SRCLK_Pin, OUTPUT);
//reset all register pins
//clearRegisters();
//writeRegisters();
//button part
//int dataIn = 2;// Q7 pin 7
//int load = 3;// PL pin 1
//int clockIn = 4;// CP pin 2
//int clockEnablePin = 5;// CE pin 15
// declare pins: pLoadPin, clockEnablePin, dataPin, clockPin
shift.begin(3, 5, 2, 4);
}
void loop() {
if (shift.update()) // read in all values. returns true if any button has changed
displayValues();
delay(100);
}
//BUTTONS
void displayValues() {
for (int i = 0; i < shift.getDataWidth(); i++) {
if (shift.pressed(i)) {
Serial.print("Button ");
Serial.print(i);
Serial.println(" is pressed");
// Set the corresponding LED pin HIGH
setRegisterPin(ledPins[i], HIGH);
writeRegisters();
} else if (shift.released(i)) {
Serial.print("Button ");
Serial.print(i);
Serial.println(" is released");
// Set the corresponding LED pin LOW
setRegisterPin(ledPins[i], LOW);
writeRegisters();
}
// You can add additional conditions for released, state, or any other information you want to display.
}
}
//set all register pins to LOW //LED
void clearRegisters(){
for(int i = numOfRegisterPins - 1; i >= 0; i--){
registers[i] = LOW;
}
}
//Set and display registers //LED
//Only call AFTER all values are set how you would like (slow otherwise)
void writeRegisters(){
digitalWrite(RCLK_Pin, LOW);
for(int i = numOfRegisterPins - 1; i >= 0; i--){
digitalWrite(SRCLK_Pin, LOW);
int val = registers[i];
digitalWrite(SER_Pin, val);
digitalWrite(SRCLK_Pin, HIGH);
}
digitalWrite(RCLK_Pin, HIGH);
}
//set an individual pin HIGH or LOW //LED
void setRegisterPin(int index, int value){
registers[index] = value;
}
//led blinking pattern, if game is won //LED
void delwin(){
//led pattern for winner
for (byte z = 0; z < 4; z = z + 1){
for (byte h = 0; h < 8; h = h + 1){
Serial.print("h"); Serial.println(h);
int g = ledPinsWin[h];
Serial.print("g"); Serial.println(g);
setRegisterPin(g, HIGH);
writeRegisters(); //MUST BE CALLED TO DISPLAY CHANGES //Only call once after the values are set how you need.
delay (lanaDelWin);
setRegisterPin(g, LOW);
writeRegisters(); //MUST BE CALLED TO DISPLAY CHANGES //Only call once after the values are set how you need.
delay (lanaDelWin);
}
}
}
//led blinking pattern at start //LED
void delray(){
//led pattern for game start
for (byte h =0;h < 9; h=h+3){
Serial.print("h"); Serial.println(h);
byte ga = ledPins[0+h];
setRegisterPin(ga, HIGH);
Serial.print("ga"); Serial.println(ga);
byte gb = ledPins[1+h];
setRegisterPin(gb, HIGH);
Serial.print("gb"); Serial.println(gb);
byte gc = ledPins[2+h];
setRegisterPin(gc, HIGH);
Serial.print("gc"); Serial.println(gc);
writeRegisters(); //MUST BE CALLED TO DISPLAY CHANGES //Only call once after the values are set how you need.
delay (lanaDelRay);
setRegisterPin(ga, LOW);
setRegisterPin(gb, LOW);
setRegisterPin(gc, LOW);
writeRegisters(); //MUST BE CALLED TO DISPLAY CHANGES //Only call once after the values are set how you need.
delay (lanaDelRay);
}
}
//led blinkin pattern, if game is lost //LED
void delwrong() {
// Led pattern for game loose
for (byte z = 0; z < 4; z = z + 1) {
for (byte i = 0; i < sizeof(ledPinsLoose) / sizeof(ledPinsLoose[0]); i++) {
setRegisterPin(ledPinsLoose[i], HIGH);
}
writeRegisters(); // Must be called to display changes
delay(lanaDelLoose);
for (byte i = 0; i < sizeof(ledPinsLoose) / sizeof(ledPinsLoose[0]); i++) {
setRegisterPin(ledPinsLoose[i], LOW);
}
writeRegisters(); // Must be called to display changes
delay(lanaDelLoose);
}
}