/* Arduino UNO R4 モールス送信プログラム ------------------------------------------ ・D13(内蔵LED)とA0(DAC, 700Hz正弦波, analogWave)でモールス送信 ・LCD(I2C 16x2)1行目にWPM、2行目に送信中の文字列を表示 ・WPMと送信文字列はシリアルコンソールにも同時出力 */ #include #include #include "analogWave.h" #define LED_PIN 13 #define SINE_FREQ 700 // 正弦波周波数(Hz) #define MODE_RANDOM false // WPMランダムモード #define FIXED_WPM 20 #define WPM_MIN 10 #define WPM_MAX 30 LiquidCrystal_I2C lcd(0x27, 16, 2); analogWave wave(A0); // UNO R4 MinimaのDAC出力はA0ピン const char* message = "The quick brown fox jumps over the lazy dog. 1234567890"; struct MorseCode { char symbol; const char *code; }; const MorseCode morseTable[] = { // 英字 {'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', "--.."}, // 数字 {'0', "-----"}, {'1', ".----"},{'2', "..---"}, {'3', "...--"}, {'4', "....-"}, {'5', "....."},{'6', "-...."}, {'7', "--..."}, {'8', "---.."},{'9', "----."}, // 記号 {'.', ".-.-.-"},{',', "--..--"},{'?', "..--.."},{'/', "-..-."}, {'=', "-...-"},{'+', ".-.-."},{'-', "-....-"},{':', "---..."}, {'\'', ".----."},{'\"', ".-..-."},{'(', "-.--."},{')', "-.--.-"}, {'@', ".--.-."},{'!', "-.-.--"} }; unsigned int dotDuration; unsigned int dashDuration; unsigned int symbolSpace; unsigned int letterSpace; unsigned int wordSpace; unsigned int currentWPM = FIXED_WPM; // WPMに基づくタイミング値の更新 void updateWPM(unsigned int wpm) { currentWPM = wpm; dotDuration = 1200 / wpm; dashDuration = dotDuration * 3; symbolSpace = dotDuration; letterSpace = dotDuration * 3; wordSpace = dotDuration * 7; } // 文字からモールス符号を取得 const char* getMorseCode(char c) { if (c >= 'a' && c <= 'z') c -= 32; for (unsigned int i = 0; i < sizeof(morseTable)/sizeof(MorseCode); i++) { if (morseTable[i].symbol == c) return morseTable[i].code; } return NULL; } // モールス1記号の送信 void sendMorseSymbol(char symbol) { digitalWrite(LED_PIN, HIGH); wave.start(); // 正弦波ON if (symbol == '.') { delay(dotDuration); } else if (symbol == '-') { delay(dashDuration); } digitalWrite(LED_PIN, LOW); wave.stop(); // 正弦波OFF delay(symbolSpace); } // 1文字の送信 void sendMorseChar(char c) { const char* code = getMorseCode(c); if (code) { for (unsigned int i = 0; code[i] != '\0'; i++) { sendMorseSymbol(code[i]); } delay(letterSpace - symbolSpace); } } // LCD 1行目にWPM表示、シリアルにも同時出力 void displayWPM() { lcd.setCursor(0, 0); lcd.print("WPM: "); lcd.print(currentWPM); for (int i = 6 + (currentWPM < 10 ? 1 : (currentWPM < 100 ? 2 : 3)); i < 16; i++) { lcd.print(" "); } // シリアルにも出力 Serial.print("WPM: "); Serial.println(currentWPM); } // LCD 2行目に送信中の文字列を左詰め・スクロール表示 void displayMessage(const char* buf, size_t len) { lcd.setCursor(0, 1); size_t start = len > 16 ? len - 16 : 0; for (size_t i = 0; i < 16; i++) { if (start + i < len) { lcd.print(buf[start + i]); } else { lcd.print(" "); } } } void setup() { pinMode(LED_PIN, OUTPUT); lcd.init(); lcd.backlight(); randomSeed(analogRead(A1)); // 未接続ピンでOK Serial.begin(115200); updateWPM(FIXED_WPM); displayWPM(); lcd.setCursor(0, 1); lcd.print("Ready! "); wave.sine(SINE_FREQ); // 波形生成は一度だけ wave.stop(); // 初期状態はOFF delay(1000); } void loop() { // WPMをランダムにする場合は毎回更新、固定の場合は何もしない if (MODE_RANDOM) { unsigned int newWPM = random(WPM_MIN, WPM_MAX + 1); updateWPM(newWPM); } // LCDとシリアルにWPMを表示 displayWPM(); delay(200); // 表示を目視しやすくするためのウェイト char displayBuf[128] = {0}; size_t dispLen = 0; Serial.print("TX: "); // シリアル送信文字列のヘッダ for (size_t i = 0; message[i] != '\0'; i++) { char c = message[i]; // LCDに流す if (dispLen < sizeof(displayBuf) - 1) { displayBuf[dispLen++] = c; displayBuf[dispLen] = '\0'; } displayMessage(displayBuf, dispLen); // シリアルには1文字ずつ連続で出力(改行しない) Serial.print(c); // モールス送信 if (c == ' ') { // --- 単語間スペースのdelayについて --- // 文字間スペース(3ドット分)は直前の送信で既にdelay済み // 追加で必要なのは「単語間スペース(7ドット分)」から「文字間スペース(3ドット分)」を引いた「4ドット分」 delay(wordSpace - letterSpace); } else { sendMorseChar(c); } } Serial.println(); // 送信完了後に改行 delay(2000); }