bool BIT_STATES[8] = {false, false, false, false, false, false, false, false};
byte REGISTER_STATES = 0;
#define DATA 8 // DS (SERIAL DATA INPUT)
#define CLOCK 9 // SHCP (SHIFT REGISTER CLOCK PIN)
#define LATCH 10 // STCP (STORAGE REGISTER CLOCK PIN)
unsigned long DELAYS[8] = {0, 0, 0, 0, 0, 0, 0, 0};
unsigned long LAST_MILLIS[8] = {0, 0, 0, 0, 0, 0, 0, 0};
void setup() {
Serial.begin(9600);
pinMode(DATA, OUTPUT);
pinMode(CLOCK, OUTPUT);
pinMode(LATCH, OUTPUT);
UPDATE_SHIFT_REGISTER();
Serial.println(F("74HC595 PLC TERMINAL.\n"));
Serial.println(F("TYPE 'A' || 'a' TO TURN ON ALL BITS."));
Serial.println(F("TYPE 'BAB || bab;<DELAY:ms>' TO BLINK ALL BITS WITH A SPECIFIED DELAY."));
Serial.println(F("TYPE 'BLINK || blink;<BIT:0-7>;<DELAY:ms>' TO BLINK CONTROL."));
Serial.println(F("TYPE 'X' || 'x' TO TURN OFF ALL BITS."));
Serial.println(F("TYPE 'HIGH || high;<BIT:0-7>' TO TURN ON THE BITS INDIVIDUALLY."));
Serial.println(F("TYPE 'LOW || low;<BIT:0-7>' TO TURN OFF THE BITS INDIVIDUALLY.\n"));
}
void loop() {
if (Serial.available() > 0) {
String CMD = Serial.readStringUntil('\n');
CMD.trim();
PROCESS_COMMAND(CMD);
}
for (byte I = 0; I < 8; I++) {
if (BIT_STATES[I] == true && (millis() - LAST_MILLIS[I] >= DELAYS[I])) {
TOGGLE_BIT(I);
LAST_MILLIS[I] = millis();
}
}
}
void UPDATE_SHIFT_REGISTER() {
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, MSBFIRST, REGISTER_STATES);
digitalWrite(LATCH, HIGH);
}
void SET_BIT_HIGH(byte BIT) {
bitSet(REGISTER_STATES, BIT);
UPDATE_SHIFT_REGISTER();
}
void SET_BIT_LOW(byte BIT) {
bitClear(REGISTER_STATES, BIT);
UPDATE_SHIFT_REGISTER();
}
void TOGGLE_BIT(byte BIT) {
REGISTER_STATES ^= (1 << BIT);
UPDATE_SHIFT_REGISTER();
}
void TURN_OFF_ALL_BITS() {
REGISTER_STATES = 0;
UPDATE_SHIFT_REGISTER();
for (byte I = 0; I < 8; I++) {
BIT_STATES[I] = false;
}
}
void TURN_ON_ALL_BITS() {
REGISTER_STATES = 0xFF;
UPDATE_SHIFT_REGISTER();
for (byte I = 0; I < 8; I++) {
BIT_STATES[I] = false;
}
}
void PRINT_BIT_STATE(byte BIT, const char* STATE) {
Serial.print(F("BIT "));
Serial.print(BIT);
Serial.print(F(" SET TO: "));
Serial.println(STATE);
}
void PROCESS_COMMAND(String CMD) {
if (CMD.startsWith("HIGH") || CMD.startsWith("high")) {
byte BIT = CMD.substring(5).toInt();
if (BIT >= 0 && BIT <= 7) {
SET_BIT_HIGH(BIT);
BIT_STATES[BIT] = false;
DELAYS[BIT] = 0;
LAST_MILLIS[BIT] = 0;
PRINT_BIT_STATE(BIT, "HIGH");
Serial.println(F(" "));
}
else {
Serial.println(F("INVALID BIT NUMBER. USE A VALUE BETWEEN 0 AND 7.\n"));
}
}
else if (CMD.startsWith("LOW") || CMD.startsWith("low")) {
byte BIT = CMD.substring(4).toInt();
if (BIT >= 0 && BIT <= 7) {
SET_BIT_LOW(BIT);
BIT_STATES[BIT] = false;
PRINT_BIT_STATE(BIT, "LOW");
Serial.println(F(" "));
}
else {
Serial.println(F("INVALID BIT NUMBER. USE A VALUE BETWEEN 0 AND 7.\n"));
}
}
else if (CMD.startsWith("BLINK") || CMD.startsWith("blink")) {
byte SPACE_INDEX = CMD.indexOf(';', 6);
if (SPACE_INDEX == -1) {
Serial.println(F("INVALID BLINK COMMAND FORMAT. USE 'BLINK || blink;<BIT:0-7>;<DELAY:ms>'.\n"));
return;
}
byte BIT = CMD.substring(6, SPACE_INDEX).toInt();
unsigned long DELAY_TIME = CMD.substring(SPACE_INDEX + 1).toInt();
if (BIT >= 0 && BIT <= 7) {
BIT_STATES[BIT] = true;
LAST_MILLIS[BIT] = millis();
DELAYS[BIT] = DELAY_TIME;
Serial.print(F("BIT "));
Serial.print(BIT);
Serial.print(F(" SET TO BLINK WITH DELAY: "));
Serial.print(DELAY_TIME);
Serial.println(F(" ms.\n"));
}
else {
Serial.println(F("INVALID BIT NUMBER. USE A VALUE BETWEEN 0 AND 7.\n"));
}
}
else if (CMD.equals("X") || CMD.equals("x")) {
TURN_OFF_ALL_BITS();
Serial.println(F("ALL BITS SET TO: LOW\n"));
}
else if (CMD.equals("A") || CMD.equals("a")) {
TURN_ON_ALL_BITS();
Serial.println(F("ALL BITS SET TO: HIGH\n"));
}
else if (CMD.startsWith("BAB") || CMD.startsWith("bab")) {
unsigned long DELAY_TIME = CMD.substring(4).toInt();
for (byte I = 0; I < 8; I++) {
BIT_STATES[I] = true;
LAST_MILLIS[I] = millis();
DELAYS[I] = DELAY_TIME;
}
Serial.print(F("ALL BITS SET TO BLINK WITH DELAY: "));
Serial.print(DELAY_TIME);
Serial.println(F(" ms.\n"));
}
else {
Serial.println(F("INVALID COMMAND. TYPE 'HIGH || high;<BIT:0-7>', 'LOW || low;<BIT:0-7>', 'BLINK || blink;<BIT:0-7>;<DELAY:ms>', 'X || x', 'A || a', OR 'BAB || bab;<DELAY:ms>'.\n"));
}
}