#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <IRremote.h>
#include <EEPROM.h>
// Definisi pin
#define IR_RECEIVE_PIN 11
#define BUTTON_UP 4
#define BUTTON_SELECT 3
#define BUTTON_DOWN 2
#define BUZZER_PIN 12
#define IR_SEND_PIN 13
// Konfigurasi display
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET 4
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Variabel menu
int menuState = 0;
int menuPosition = 0;
const int MENU_SIZE = 3;
String menuItems[] = {"Record IR", "Play IR", "Clear All"};
// Variabel untuk IR
IRrecv irrecv(IR_RECEIVE_PIN);
IRsend irsend;
decode_results results;
// Definisi struktur untuk menyimpan kode IR
struct IRCode {
unsigned long code;
int bits;
};
// Array untuk menyimpan kode IR
const int MAX_CODES = 10;
IRCode storedCodes[MAX_CODES];
int storedCodesCount = 0;
// Variabel untuk debouncing
unsigned long lastDebounceTime[3] = {0, 0, 0};
int lastButtonState[3] = {HIGH, HIGH, HIGH};
int buttonState[3] = {HIGH, HIGH, HIGH};
const unsigned long debounceDelay = 50;
void setup() {
// Inisialisasi Serial untuk debugging
Serial.begin(9600);
// Inisialisasi pin
pinMode(BUTTON_UP, INPUT_PULLUP);
pinMode(BUTTON_SELECT, INPUT_PULLUP);
pinMode(BUTTON_DOWN, INPUT_PULLUP);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(IR_SEND_PIN, OUTPUT);
// Debug print button states
Serial.println("Button states:");
Serial.print("UP: "); Serial.println(digitalRead(BUTTON_UP));
Serial.print("SELECT: "); Serial.println(digitalRead(BUTTON_SELECT));
Serial.print("DOWN: "); Serial.println(digitalRead(BUTTON_DOWN));
// Inisialisasi receiver IR
irrecv.enableIRIn();
// Inisialisasi display OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
// Setup awal display
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
// Tampilkan splash screen
showSplashScreen();
// Load data dari EEPROM
loadFromEEPROM();
}
void loop() {
handleButtons();
updateDisplay();
delay(10); // Delay kecil untuk stabilitas
}
bool isButtonPressed(int pin) {
int index;
if (pin == BUTTON_UP) index = 0;
else if (pin == BUTTON_SELECT) index = 1;
else if (pin == BUTTON_DOWN) index = 2;
else return false;
int reading = digitalRead(pin);
if (reading != lastButtonState[index]) {
lastDebounceTime[index] = millis();
}
if ((millis() - lastDebounceTime[index]) > debounceDelay) {
if (reading != buttonState[index]) {
buttonState[index] = reading;
if (reading == LOW) { // Aktif LOW karena menggunakan pull-up
lastButtonState[index] = reading;
return true;
}
}
}
lastButtonState[index] = reading;
return false;
}
void handleButtons() {
// Button UP
if (isButtonPressed(BUTTON_UP)) {
Serial.println("UP pressed");
beep();
if (menuPosition > 0) {
menuPosition--;
}
}
// Button DOWN
if (isButtonPressed(BUTTON_DOWN)) {
Serial.println("DOWN pressed");
beep();
if (menuPosition < MENU_SIZE - 1) {
menuPosition++;
}
}
// Button SELECT
if (isButtonPressed(BUTTON_SELECT)) {
Serial.println("SELECT pressed");
beep();
selectMenuItem();
}
}
void selectMenuItem() {
switch(menuPosition) {
case 0: // Record IR
recordIR();
break;
case 1: // Play IR
playIR();
break;
case 2: // Clear All
clearAllCodes();
break;
}
}
void recordIR() {
if (storedCodesCount >= MAX_CODES) {
showMessage("Memory Full!");
return;
}
showMessage("Point Remote...");
while (!irrecv.decode(&results)) {
if (isButtonPressed(BUTTON_SELECT)) {
showMessage("Cancelled");
delay(1000);
return;
}
}
// Simpan kode
storedCodes[storedCodesCount].code = results.value;
storedCodes[storedCodesCount].bits = results.bits;
storedCodesCount++;
// Simpan ke EEPROM
saveToEEPROM();
showMessage("Recorded!");
delay(1000);
irrecv.resume();
}
void playIR() {
if (storedCodesCount == 0) {
showMessage("No codes!");
delay(1000);
return;
}
int currentCode = 0;
bool selecting = true;
while (selecting) {
display.clearDisplay();
display.setCursor(0,0);
display.print("Select Code: ");
display.println(currentCode + 1);
display.display();
if (isButtonPressed(BUTTON_UP) && currentCode > 0) {
currentCode--;
}
if (isButtonPressed(BUTTON_DOWN) && currentCode < storedCodesCount - 1) {
currentCode++;
}
if (isButtonPressed(BUTTON_SELECT)) {
irsend.sendNEC(storedCodes[currentCode].code, storedCodes[currentCode].bits);
showMessage("Sent!");
delay(1000);
selecting = false;
}
}
}
void clearAllCodes() {
showMessage("Clear All?");
delay(1000);
while (true) {
display.clearDisplay();
display.setCursor(0,0);
display.println("UP: Yes");
display.println("DOWN: No");
display.display();
if (isButtonPressed(BUTTON_UP)) {
storedCodesCount = 0;
saveToEEPROM();
showMessage("Cleared!");
delay(1000);
return;
}
if (isButtonPressed(BUTTON_DOWN)) {
return;
}
}
}
void showMessage(const char* message) {
display.clearDisplay();
display.setCursor(0,0);
display.println(message);
display.display();
}
void updateDisplay() {
display.clearDisplay();
display.setCursor(0,0);
// Header
display.println("IR Remote");
display.println("---------");
// Menu items
for (int i = 0; i < MENU_SIZE; i++) {
if (i == menuPosition) {
display.print("> ");
} else {
display.print(" ");
}
display.println(menuItems[i]);
}
display.display();
}
void showSplashScreen() {
display.clearDisplay();
display.setCursor(0,0);
display.println("IR Remote");
display.println("Universal");
display.println("---------");
display.print("Codes: ");
display.println(storedCodesCount);
display.display();
delay(2000);
}
void beep() {
tone(BUZZER_PIN, 2000, 50);
}
void saveToEEPROM() {
EEPROM.put(0, storedCodesCount);
for (int i = 0; i < storedCodesCount; i++) {
EEPROM.put(sizeof(int) + (i * sizeof(IRCode)), storedCodes[i]);
}
}
void loadFromEEPROM() {
EEPROM.get(0, storedCodesCount);
if (storedCodesCount > MAX_CODES) storedCodesCount = 0;
for (int i = 0; i < storedCodesCount; i++) {
EEPROM.get(sizeof(int) + (i * sizeof(IRCode)), storedCodes[i]);
}
}