#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <map>
#include <Arduino.h>
// إعدادات الأجهزة
#define I2C_ADDR 0x27
#define LCD_COLUMNS 16
#define LCD_LINES 2
#define RELAY_PIN 5
#define SPEAKER_PIN 17
#define AUDIO_IN_PIN 18
#define LED_PIN 19
// إعدادات مورس
#define DEFAULT_WPM 20
#define DIT_TIME_MS (1200 / DEFAULT_WPM)
#define DAH_TIME_MS (3 * DIT_TIME_MS)
// إعدادات القائمة
enum MenuState {HOME, SEND_MENU, RECEIVE_MENU};
MenuState currentMenu = HOME;
// هياكل البيانات
std::map<String, char> morseMap = {
{".-", 'A'}, {"-...", 'B'}, {"-.-.", 'C'}, {"-..", 'D'},
{".", 'E'}, {"..-.", 'F'}, {"--.", 'G'}, {"....", 'H'},
{"..", 'I'}, {".---", 'J'}, {"-.-", 'K'}, {".-..", 'L'},
{"--", 'M'}, {"-.", 'N'}, {"---", 'O'}, {".--.", 'P'},
{"--.-", 'Q'}, {".-.", 'R'}, {"...", 'S'}, {"-", 'T'},
{"..-", 'U'}, {"...-", 'V'}, {".--", 'W'}, {"-..-", 'X'},
{"-.--", 'Y'}, {"--..", 'Z'}, {".----", '1'}, {"..---", '2'},
{"...--", '3'}, {"....-", '4'}, {".....", '5'}, {"-....", '6'},
{"--...", '7'}, {"---..", '8'}, {"----.", '9'}, {"-----", '0'}
};
// إعدادات لوحة المفاتيح
const byte ROWS = 4;
const byte COLS = 4;
char hexaKeys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {27, 13, 16, 4};
byte colPins[COLS] = {33, 25, 26, 14};
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
// إعدادات الشاشة
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
// المتغيرات العامة
String currentMessage = "";
String receivedMorse = "";
int wpm = DEFAULT_WPM;
unsigned long lastInputTime = 0;
// تعريفات مسبقة للدوال
void processSignal(int state);
void handleReceiveInput(char key);
void decodeMorse();
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
pinMode(RELAY_PIN, OUTPUT);
pinMode(SPEAKER_PIN, OUTPUT);
pinMode(AUDIO_IN_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
showHomeScreen();
}
void loop() {
handleInput();
updateDisplay();
}
// =============== معالجة الإدخال =============== //
void handleInput() {
char key = customKeypad.getKey();
if (!key) return;
switch(currentMenu) {
case HOME:
handleHomeInput(key);
break;
case SEND_MENU:
handleSendInput(key);
break;
case RECEIVE_MENU:
handleReceiveInput(key);
break;
}
}
void handleHomeInput(char key) {
switch(key) {
case 'A':
currentMenu = SEND_MENU;
startMessageEntry();
break;
case 'B':
currentMenu = RECEIVE_MENU;
startMorseReception();
break;
case '#':
toggleWPM();
break;
}
}
// =============== إدارة الرسائل =============== //
void startMessageEntry() {
currentMessage = "";
lcd.clear();
lcd.print("Enter Message:");
}
void handleSendInput(char key) {
if (key == 'D') {
sendMorse(currentMessage);
currentMenu = HOME;
return;
}
if (millis() - lastInputTime > 500) {
currentMessage += key;
} else {
currentMessage.setCharAt(currentMessage.length()-1, key);
}
lastInputTime = millis();
}
// =============== إرسال مورس =============== //
void sendMorse(String message) {
lcd.clear();
lcd.print("Sending...");
for (char c : message) {
String morse = charToMorse(toupper(c));
if (morse == "") continue;
for (char sym : morse) {
digitalWrite(RELAY_PIN, HIGH);
tone(SPEAKER_PIN, 558);
delay(sym == '.' ? DIT_TIME_MS : DAH_TIME_MS);
digitalWrite(RELAY_PIN, LOW);
noTone(SPEAKER_PIN);
delay(DIT_TIME_MS);
}
delay(DAH_TIME_MS); // مسافة بين الحروف
}
}
// =============== استقبال مورس =============== //
void startMorseReception() {
lcd.clear();
lcd.print("Listening...");
receivedMorse = "";
unsigned long startTime = millis();
while (millis() - startTime < 30000) {
int signal = analogRead(AUDIO_IN_PIN);
if (signal > 500) processSignal(HIGH);
else processSignal(LOW);
delay(10);
}
decodeMorse();
}
void processSignal(int state) {
static unsigned long lastStateChange = 0;
static int lastState = LOW;
if (state != lastState) {
unsigned long duration = millis() - lastStateChange;
analyzeSignal(duration, lastState);
lastState = state;
lastStateChange = millis();
}
}
void analyzeSignal(unsigned long duration, int state) {
if (state == HIGH) {
if (duration > DAH_TIME_MS) receivedMorse += '-';
else if (duration > DIT_TIME_MS/2) receivedMorse += '.';
} else {
if (duration > DIT_TIME_MS * 3) receivedMorse += ' ';
if (duration > DIT_TIME_MS * 7) decodeMorse();
}
}
void handleReceiveInput(char key) {
if (key == 'C') {
currentMenu = HOME;
showHomeScreen();
}
}
// =============== واجهة المستخدم =============== //
void showHomeScreen() {
lcd.clear();
lcd.print("A:Send B:Receive");
lcd.setCursor(0,1);
lcd.print("WPM:");
lcd.print(wpm);
lcd.print(" #:Toggle");
}
void updateDisplay() {
if (currentMenu == SEND_MENU) {
lcd.setCursor(0,1);
lcd.print(" ");
lcd.setCursor(0,1);
lcd.print(currentMessage);
}
}
// =============== دوال مساعدة =============== //
String charToMorse(char c) {
for (auto& pair : morseMap) {
if (pair.second == c) return pair.first;
}
return "";
}
void toggleWPM() {
wpm = (wpm == 20) ? 30 : 20;
showHomeScreen();
}
void decodeMorse() {
String decoded = "";
String currentSymbol = "";
for (char c : receivedMorse) {
if (c == ' ') {
if (morseMap.count(currentSymbol)) {
decoded += morseMap[currentSymbol];
}
currentSymbol = "";
} else {
currentSymbol += c;
}
}
lcd.clear();
lcd.print("Decoded:");
lcd.setCursor(0,1);
lcd.print(decoded);
delay(3000);
currentMenu = HOME;
}