Станция азбуки Морзе на Arduino Uno

Создадим станцию дешифровки азбуки Морзе с помощью Arduino Uno с использованием графического дисплея.

Компоненты

Для создания нашей станции азбуки Морзе нам понадобятся следующие компоненты:

  1. Arduino Uno
  2. Зуммер
  3. Резистор 220 Ом
  4. Резистор 10 кОм
  5. Графический OLED-дисплей, 128х64
  6. 5 мм светодиод: красный
  7. Тактильный переключатель с верхним приводом

О проекте

Код азбуки Морзе вводится нажатием кнопки. Одно короткое нажатие для точки и более длинное (не менее чем в два раза длиннее) для тире.

При вводе распознанного кода отображается буква или цифра, которую он представляет. Если между нажатиями сделать паузу примерно в 1,5 секунды, то на дисплее появится пробел, позволяющий вводить слова. Если код не распознан, на экране отобразится символ '?'.

Азбука Морзе является методом связи, который кодирует символы в виде серии точек и тире. Эта схема использует зуммер, чтобы сделать точки и тире слышимыми. Используя кнопку, вы вводите азбуку Морзе, при каждом нажатии кнопки раздается звуковой сигнал, а на OLED-дисплее отображается декодированное сообщение.

Большинство людей не знакомы с азбукой Морзе, поэтому изображение ниже показывает все международные коды азбуки Морзе:

Схема соединения

Соедините все комплектующие согласно схеме ниже:

Скетч

Загружаем в Arduino Uno скетч для платы ниже:

/**
 * A Morse code station for the Arduino Uno.
 * 
 * The display is a 128*64 OLED display and it uses the 
 * AdaFruit OLED driver libraries: 
 * - Adafruit GFX
 * - Adafruit SSD1306
 * 
 * You can search for these libraries and install them from within the Arduino
 * IDE. From the IDE menu choose Sketch->Include Library->Library Manager
 * enter the names of the libraries above and click install for each of them.
 * 
 * Author: Mario Gianota July 2020
 */
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)

#define BUZZER_PIN 2
#define LED_PIN 7
#define CODE_BUTTON 3

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

bool codeButtonArmed;
bool codeButtonPressed;
unsigned long codeTime;
unsigned long startTime;
unsigned long lastButtonPressTime;
bool letterDecoded;
bool newWord;

// Time range of a dot in milliseconds
const unsigned int dotTimeMillisMin = 40;
const unsigned int dotTimeMillisMax = 180;

// Array to store the times of the code button presses
unsigned long buttonPressTimes[5];
int bptIndex;

int row;
int col;

void setup() {
  pinMode(CODE_BUTTON, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(9600);
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println("SSD1306 allocation failed");
    for(;;); // Don't proceed, loop forever
  }
  display.clearDisplay();
  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(0, 0);     // Start at top-left corner
  display.cp437(true);         // Use full 256 char 'Code Page 437' font
  display.write("Morse Code Station");
  display.drawLine(0, 10, display.width(), 10, SSD1306_WHITE);

  display.setCursor(0, 12);
  display.display();
  delay(100);
}

void loop() {
  scanButtons();
  if( millis() - lastButtonPressTime > 1600 && newWord == true ) {
    Serial.println("New word");
    display.write(' ');
    display.display();
    newWord = false;
  }else if( millis() - lastButtonPressTime > 600 && letterDecoded == false) {
    decodeButtonPresses();
    letterDecoded = true;
  }
}

void codeButtonDown() {
  tone(BUZZER_PIN, 440, 10);
  digitalWrite(LED_PIN, HIGH);
  codeTime = millis() - startTime;
}
void codeButtonReleased() {
  digitalWrite(LED_PIN, LOW);

  // Most button bounces take less than 25 millis. If the code time
  // is greater than 25 millis then it was probably a legit button press
  if( codeTime > 25 ) {
    
    Serial.print("Code time: ");
    Serial.print(codeTime);
    Serial.println(" milliseconds");

    // Save codeTime
    buttonPressTimes[bptIndex] = codeTime;
    bptIndex++;
    if( bptIndex == 5 ) {
      
      for(int i=0; i<5; i++) {
        buttonPressTimes[bptIndex] = 0;
      }
    }
  }
}

void scanButtons() {
  if( ! codeButtonArmed && digitalRead(CODE_BUTTON) == HIGH ) {
    codeButtonArmed = true;
    // start timer
    startTime = millis();
    lastButtonPressTime = startTime;
    codeTime = 0;
    letterDecoded = false;
    newWord = true;
  }
  if( digitalRead(CODE_BUTTON) == HIGH ) {
    codeButtonPressed = true;
    codeButtonDown();
  }
  if( codeButtonPressed && digitalRead(CODE_BUTTON) == LOW ) {
    codeButtonPressed = false;
    codeButtonReleased();
    codeButtonArmed = false;
  }
}

void decodeButtonPresses() {
  Serial.print("DECODE LETTER: ");
  for(int i=0; i<bptIndex; i++) {
    if( isDot(buttonPressTimes[i]) ) 
      Serial.print(" DOT ");
    else if( isDash(buttonPressTimes[i]) )
      Serial.print(" DASH");
  }
  Serial.print("   ");
  char c = decodeMsg();
  Serial.print(c);
  Serial.println();
  display.write(c);
  display.display();
  bptIndex = 0;
  for(int i=0; i<5; i++) {
    buttonPressTimes[i] = 0;
  }
}
bool isDot(unsigned long t) {
  if( t >= dotTimeMillisMin && t <= dotTimeMillisMax )
    return true;
  return false;
}
bool isDash(unsigned long t) {
  if( t > dotTimeMillisMax )
    return true;
  return false;
}

void drawChar(char c) {
  display.write(c);
  display.display();
}
char decodeMsg() {
  char c = '?';
  if( isDot(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && buttonPressTimes[2] == 0 )
    c = 'A';
  else if( isDash(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && isDot(buttonPressTimes[3]) && buttonPressTimes[4]== 0 )
    c = 'B';
  else if( isDash(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && isDot(buttonPressTimes[3]) && buttonPressTimes[4]== 0 )
    c = 'C';
  else if( isDash(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && buttonPressTimes[3]== 0 )
    c = 'D';
  else if( isDot(buttonPressTimes[0]) && buttonPressTimes[1] == 0 )
    c = 'E';
  else if( isDot(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && isDot(buttonPressTimes[3]) && buttonPressTimes[4]== 0 )
    c = 'F';
  else if( isDash(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && buttonPressTimes[3]== 0 )
    c = 'G';
  else if( isDot(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && isDot(buttonPressTimes[3]) && buttonPressTimes[4]== 0 )
    c = 'H';
  else if( isDot(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && buttonPressTimes[2]== 0 )
    c = 'I';
  else if( isDot(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && isDash(buttonPressTimes[3]) && buttonPressTimes[4]== 0 )
    c = 'J';
  else if( isDash(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && buttonPressTimes[3]== 0 )
    c = 'K';
  else if( isDot(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && isDot(buttonPressTimes[3]) && buttonPressTimes[4]== 0 )
    c = 'L';
  else if( isDash(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && buttonPressTimes[2]== 0 )
    c = 'M';
  else if( isDash(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && buttonPressTimes[2]== 0 )
    c = 'N';
  else if( isDash(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && buttonPressTimes[3]== 0 )
    c = 'O';
  else if( isDot(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && isDot(buttonPressTimes[3]) && buttonPressTimes[4]== 0 )
    c = 'P';
  else if( isDash(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && isDash(buttonPressTimes[3]) && buttonPressTimes[4]== 0 )
    c = 'Q';
  else if( isDot(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && buttonPressTimes[3]== 0 )
    c = 'R';
  else if( isDot(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && buttonPressTimes[3]== 0 )
    c = 'S';
  else if( isDash(buttonPressTimes[0]) && buttonPressTimes[1]== 0 )
    c = 'T';
  else if( isDot(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && buttonPressTimes[3]== 0 )
    c = 'U';
  else if( isDot(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && isDash(buttonPressTimes[3]) && buttonPressTimes[4]== 0 )
    c = 'V';
  else if( isDot(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && buttonPressTimes[3]== 0 )
    c = 'W';
  else if( isDash(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && isDash(buttonPressTimes[3]) && buttonPressTimes[4]== 0 )
    c = 'X';
  else if( isDash(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && isDash(buttonPressTimes[3]) && buttonPressTimes[4]== 0 )
    c = 'Y';
  else if( isDash(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && isDot(buttonPressTimes[3]) && buttonPressTimes[4]== 0 )
    c = 'Z';
  else if( isDot(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && isDash(buttonPressTimes[3]) && isDash(buttonPressTimes[4]))
    c = '1';
  else if( isDot(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && isDash(buttonPressTimes[3]) && isDash(buttonPressTimes[4]))
    c = '2';
  else if( isDot(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && isDash(buttonPressTimes[3]) && isDash(buttonPressTimes[4]))
    c = '3';
  else if( isDot(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && isDot(buttonPressTimes[3]) && isDash(buttonPressTimes[4]))
    c = '4';
  else if( isDot(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && isDot(buttonPressTimes[3]) && isDot(buttonPressTimes[4]))
    c = '5';
  else if( isDash(buttonPressTimes[0]) && isDot(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && isDot(buttonPressTimes[3]) && isDot(buttonPressTimes[4]))
    c = '6';
  else if( isDash(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDot(buttonPressTimes[2]) && isDot(buttonPressTimes[3]) && isDot(buttonPressTimes[4]))
    c = '7';
  else if( isDash(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && isDot(buttonPressTimes[3]) && isDot(buttonPressTimes[4]))
    c = '8';
  else if( isDash(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && isDash(buttonPressTimes[3]) && isDot(buttonPressTimes[4]))
    c = '9';
  else if( isDash(buttonPressTimes[0]) && isDash(buttonPressTimes[1]) && isDash(buttonPressTimes[2]) && isDash(buttonPressTimes[3]) && isDash(buttonPressTimes[4]))
    c = '0';
  return c;
}

Можно попробовать поиграть с кодом, чтобы после декодирования нажатий вывести на последовательный монитор полное слово или предложение.

5 июля 2020 в 03:06
Опубликовано: | Оригинал
Уроки,

1 комментарий

  1. Максим
    12 июля 2021 в 20:27

    Ну я поиграл я и получилось такое — подключаюсь по блютуз у и с телефона набираю слова и ардуинка их пищит

    Ответить

Добавить комментарий

Ваш E-mail не будет никому виден. Обязательные поля отмечены *