// MATRIX 4-12CH
//BOARD PROMINI ATMEGA328P
//PATTERN MATRIX FOR 4 - 16 CHANNEL
//REVERSE LOGIC FOR RELAY HIGH / LOW TRIGER
// RELAY1 : D4
// RELAY2 : D5
// RELAY3 : D6
// RELAY4 : D7
// RELAY5 : D8
// RELAY6 : D9
// RELAY7 : D10
// RELAY8 : D11
// RELAY9 : D12
// RELAY10 : D13
// RELAY11 : A0
// RELAY12 : A1
// SWITCH : A2 (TRIGER LOW)
// BUTTON : A3 (TRIGER LOW)
#include <Arduino.h>
#include <avr/pgmspace.h>
#include "pattern16.h"
#include "pattern12.h"
#include "pattern8.h"
#include "pattern6.h"
#include "pattern4.h"
uint8_t selectSWICTH[2]={8,4};//[12,8,6,4]
uint8_t NUMRELAY = selectSWICTH[0];
uint8_t NUMSEBELUMNYA = NUMRELAY;
uint8_t relay[] = {13, 2, 3, 4, 5, 6, 12, 11, 10, 9, 8, 7};
uint8_t switch_PIN = 0;
uint8_t change_PIN = 19;
uint8_t state = 1;
bool Rlogic = false;
bool autos = false;
bool active = true;
bool singleClick = false;
bool tombolDitekan = false;
unsigned long waktuTombolDitekan = 0;
unsigned long waktuDebounce = 50;
unsigned long waktuKlikTerakhir = 0;
unsigned long waktuAntaraKlik = 250;
unsigned long previousMillis = 0;
unsigned long interval = 200;
int currentFrame = 0;
void writeToPins(const uint8_t *data, uint8_t relaynumber) {
for (int i = 0; i < relaynumber; i++) {
if(!Rlogic)digitalWrite(relay[i], data[i]); else digitalWrite(relay[i], (data[i] == 1) ? 0 : 1);
}
}
bool animate4ch(bool init, const uint8_t (*frames)[4], int numFrames) {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
uint8_t rowData[4];
memcpy_P(rowData, frames[currentFrame], 4);
writeToPins(rowData, 4);
currentFrame++;
if (currentFrame >= numFrames) {
init = false;
}
}
return init;
}
bool animate6ch(bool init, const uint8_t (*frames)[6], int numFrames) {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
uint8_t rowData[6];
memcpy_P(rowData, frames[currentFrame], 6);
writeToPins(rowData, 6);
currentFrame++;
if (currentFrame >= numFrames) {
init = false;
}
}
return init;
}
bool animate8ch(bool init, const uint8_t (*frames)[8], int numFrames) {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
uint8_t rowData[8];
memcpy_P(rowData, frames[currentFrame], 8);
writeToPins(rowData, 8);
currentFrame++;
if (currentFrame >= numFrames) {
init = false;
}
}
return init;
}
bool animate12ch(bool init, const uint8_t (*frames)[12], int numFrames) {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
uint8_t rowData[12];
memcpy_P(rowData, frames[currentFrame], 12);
writeToPins(rowData, 12);
currentFrame++;
if (currentFrame >= numFrames) {
init = false;
}
}
return init;
}
void clear() {
for (int i = 0; i < 12; i++) {
if(!Rlogic)digitalWrite(relay[i], LOW); else digitalWrite(relay[i], HIGH);
}
}
void change() {
int tombolBaca = digitalRead(change_PIN);
if (tombolBaca == LOW) {
if (!tombolDitekan) {
waktuTombolDitekan = millis();
tombolDitekan = true;
} else if (millis() - waktuTombolDitekan > 500) {
active = !active;
if (active)Serial.println("change matrix off");
while (digitalRead(change_PIN) == LOW) {
}
}
} else {
if (tombolDitekan) {
if (millis() - waktuTombolDitekan > waktuDebounce && millis() - waktuTombolDitekan <= 500) {
if (millis() - waktuKlikTerakhir < waktuAntaraKlik) {
currentFrame = 0;
autos = !autos;
if(active)Serial.println("change matrix ON"),active = false;
singleClick = false;
Serial.println("change matrix auto");
}
else {
singleClick = true;
waktuKlikTerakhir = millis();
}
}
tombolDitekan = false;
}
if (singleClick && (millis() - waktuKlikTerakhir > waktuAntaraKlik)) {
autos = false;
if(active)Serial.println("change matrix ON"),active = false; else state++;
if (state > 12) {
state = 1;
currentFrame = 0;
}
Serial.println("change matrix ke " + String(state));
singleClick = false;
}
}
}
void run() {
static bool init = true;
if (!init) {
if (autos)state++;
currentFrame = 0;
init = true;
}
if (NUMRELAY == 4) {
switch (state) {
case 1: init = animate4ch(init, animated4ch_1, sizeof(animated4ch_1) / sizeof(animated4ch_1[0])); break;
case 2: init = animate4ch(init, animated4ch_2, sizeof(animated4ch_2) / sizeof(animated4ch_2[0])); break;
case 3: init = animate4ch(init, animated4ch_3, sizeof(animated4ch_3) / sizeof(animated4ch_3[0])); break;
case 4: init = animate4ch(init, animated4ch_4, sizeof(animated4ch_4) / sizeof(animated4ch_4[0])); break;
case 5: init = animate4ch(init, animated4ch_5, sizeof(animated4ch_5) / sizeof(animated4ch_5[0])); break;
case 6: init = animate4ch(init, animated4ch_6, sizeof(animated4ch_6) / sizeof(animated4ch_6[0])); break;
case 7: init = animate4ch(init, animated4ch_7, sizeof(animated4ch_7) / sizeof(animated4ch_7[0])); break;
case 8: init = animate4ch(init, animated4ch_8, sizeof(animated4ch_8) / sizeof(animated4ch_8[0])); break;
case 9: init = animate4ch(init, animated4ch_9, sizeof(animated4ch_9) / sizeof(animated4ch_9[0])); break;
case 10: init = animate4ch(init, animated4ch_10, sizeof(animated4ch_10) / sizeof(animated4ch_10[0])); break;
case 11: init = animate4ch(init, animated4ch_11, sizeof(animated4ch_11) / sizeof(animated4ch_11[0])); break;
case 12: init = animate4ch(init, animated4ch_12, sizeof(animated4ch_12) / sizeof(animated4ch_12[0])); break;
default: state = 1;
}
}
if (NUMRELAY == 6) {
switch (state) {
case 1: init = animate6ch(init, animated6ch_1, sizeof(animated6ch_1) / sizeof(animated6ch_1[0])); break;
case 2: init = animate6ch(init, animated6ch_2, sizeof(animated6ch_2) / sizeof(animated6ch_2[0])); break;
case 3: init = animate6ch(init, animated6ch_3, sizeof(animated6ch_3) / sizeof(animated6ch_3[0])); break;
case 4: init = animate6ch(init, animated6ch_4, sizeof(animated6ch_4) / sizeof(animated6ch_4[0])); break;
case 5: init = animate6ch(init, animated6ch_5, sizeof(animated6ch_5) / sizeof(animated6ch_5[0])); break;
case 6: init = animate6ch(init, animated6ch_6, sizeof(animated6ch_6) / sizeof(animated6ch_6[0])); break;
case 7: init = animate6ch(init, animated6ch_7, sizeof(animated6ch_7) / sizeof(animated6ch_7[0])); break;
case 8: init = animate6ch(init, animated6ch_8, sizeof(animated6ch_8) / sizeof(animated6ch_8[0])); break;
case 9: init = animate6ch(init, animated6ch_9, sizeof(animated6ch_9) / sizeof(animated6ch_9[0])); break;
case 10: init = animate6ch(init, animated6ch_10, sizeof(animated6ch_10) / sizeof(animated6ch_10[0])); break;
case 11: init = animate6ch(init, animated6ch_11, sizeof(animated6ch_11) / sizeof(animated6ch_11[0])); break;
case 12: init = animate6ch(init, animated6ch_12, sizeof(animated6ch_12) / sizeof(animated6ch_12[0])); break;
default: state = 1;
}
}
if (NUMRELAY == 8) {
switch (state) {
case 1: init = animate8ch(init, animated8ch_1, sizeof(animated8ch_1) / sizeof(animated8ch_1[0])); break;
case 2: init = animate8ch(init, animated8ch_2, sizeof(animated8ch_2) / sizeof(animated8ch_2[0])); break;
case 3: init = animate8ch(init, animated8ch_3, sizeof(animated8ch_3) / sizeof(animated8ch_3[0])); break;
case 4: init = animate8ch(init, animated8ch_4, sizeof(animated8ch_4) / sizeof(animated8ch_4[0])); break;
case 5: init = animate8ch(init, animated8ch_5, sizeof(animated8ch_5) / sizeof(animated8ch_5[0])); break;
case 6: init = animate8ch(init, animated8ch_6, sizeof(animated8ch_6) / sizeof(animated8ch_6[0])); break;
case 7: init = animate8ch(init, animated8ch_7, sizeof(animated8ch_7) / sizeof(animated8ch_7[0])); break;
case 8: init = animate8ch(init, animated8ch_8, sizeof(animated8ch_8) / sizeof(animated8ch_8[0])); break;
case 9: init = animate8ch(init, animated8ch_9, sizeof(animated8ch_9) / sizeof(animated8ch_9[0])); break;
case 10: init = animate8ch(init, animated8ch_10, sizeof(animated8ch_10) / sizeof(animated8ch_10[0])); break;
case 11: init = animate8ch(init, animated8ch_11, sizeof(animated8ch_11) / sizeof(animated8ch_11[0])); break;
case 12: init = animate8ch(init, animated8ch_12, sizeof(animated8ch_12) / sizeof(animated8ch_12[0])); break;
default: state = 1;
}
}
if (NUMRELAY == 12) {
switch (state) {
case 1: init = animate12ch(init, animated12ch_1, sizeof(animated12ch_1) / sizeof(animated12ch_1[0])); break;
case 2: init = animate12ch(init, animated12ch_2, sizeof(animated12ch_2) / sizeof(animated12ch_2[0])); break;
case 3: init = animate12ch(init, animated12ch_3, sizeof(animated12ch_3) / sizeof(animated12ch_3[0])); break;
case 4: init = animate12ch(init, animated12ch_4, sizeof(animated12ch_4) / sizeof(animated12ch_4[0])); break;
case 5: init = animate12ch(init, animated12ch_5, sizeof(animated12ch_5) / sizeof(animated12ch_5[0])); break;
case 6: init = animate12ch(init, animated12ch_6, sizeof(animated12ch_6) / sizeof(animated12ch_6[0])); break;
case 7: init = animate12ch(init, animated12ch_7, sizeof(animated12ch_7) / sizeof(animated12ch_7[0])); break;
case 8: init = animate12ch(init, animated12ch_8, sizeof(animated12ch_8) / sizeof(animated12ch_8[0])); break;
case 9: init = animate12ch(init, animated12ch_9, sizeof(animated12ch_9) / sizeof(animated12ch_9[0])); break;
case 10: init = animate12ch(init, animated12ch_10, sizeof(animated12ch_10) / sizeof(animated12ch_10[0])); break;
case 11: init = animate12ch(init, animated12ch_11, sizeof(animated12ch_11) / sizeof(animated12ch_11[0])); break;
case 12: init = animate12ch(init, animated12ch_12, sizeof(animated12ch_12) / sizeof(animated12ch_12[0])); break;
default: state = 1;
}
}
}
void setup() {
Serial.begin(115200);
for (int i = 0; i < NUMRELAY; i++) {
pinMode(relay[i], OUTPUT);
}
pinMode(switch_PIN, INPUT_PULLUP);
pinMode(change_PIN, INPUT_PULLUP);
}
void loop() {
if (digitalRead(switch_PIN) == LOW)NUMRELAY = selectSWICTH[1] , interval = 130; else NUMRELAY = selectSWICTH[0], interval = 80;
if (NUMRELAY != NUMSEBELUMNYA)NUMSEBELUMNYA = NUMRELAY, currentFrame = 0, clear();
change();
if (!active)run(); else clear();
}