Lesson 2.1. BUTTONS. Morse trainer



  • The purpose of this lesson

    Hi! Today we will make a simple but effective simulator of Morse code (Fig. 1).

    Figure 1.

    When you turn on the device, the logo appears on the screen and instructions to press the first button to start. After the screen will appear alternately letters of the English alphabet and numbers. Also applies graphic and sound mapping. To knock out the code use the second button. To repeat the sound signal use the third button. If the user correctly taps the code, it will change the letter. After completing the entire cycle - everything starts again with the first letter of the alphabet.

    Thanks to the built-in buttons and dynamics to make such a device is not difficult.

    List of components for the lesson

    • M5STACK;
    • USB-C cable from standard kit.

    A bit of theory

    Morse code is a method of transmitting text information in the form of a series of on-off tone signal, which can be directly decoded by a qualified listener or observer without special equipment. It is named after S. F. B. Morse, inventor of the Telegraph. The international Morse code encodes the ISO basic Latin alphabet, some additional Latin letters, Arabic numerals and a small set of punctuation and procedural signals in the form of standardized sequences of short and long signals called "dots" and "dashes", as in Amateur radio practice. Since many non-English natural languages use more than the 26 Latin letters (Fig. 2), for these languages, there are extensions of the Morse code.

    Figure 2. Graphical diagram of Morse codes

    In an emergency situation, when it is necessary to send a distress signal, Morse code is also used. The most common distress signal is SOS or three dots, three dashes and three dots is an internationally recognized agreement.

    Figure 3. Telegraph key

    In order to knock out the Morse code, a Telegraph key is used (Fig.3), and the device that transmits information from the key is called the Telegraph.

    Let's start!

    Step 1. Write down the alphabetic names of the letters

    String MorseTelephony[] =
    {
      "Alfa",
      "Bravo",
      "Charlie",
      "Delta",
      "Echo",
      "Foxtrot",
      "Golf",
      "Hotel",
      "India",
      "Juliett",
      "Kilo",
      "Lima",
      "Mike",
      "November",
      "Oscar",
      "Papa",
      "Quebec",
      "Romeo",
      "Sierra",
      "Tango",
      "Uniform",
      "Victor",
      "Whiskey",
      "Xray",
      "Yankee",
      "Zulu",
      "1",
      "2",
      "3",
      "4",
      "5",
      "6",
      "7",
      "8",
      "9",
      "0"
    };
    

    Step 2. Let's write melodies for letters and numbers

    String MorsePhonic[] =
    {
      "AL-FAH",
      "BRAH-VOH",
      "CHAR-LEE",
      "DELL-TAH",
      "ECK-OH",
      "FOKS-TROT",
      "GOLF",
      "HOH-TEL",
      "IN-DEE-AH",
      "JEW-LEE-ETT",
      "KEY-LOH",
      "LEE-MAH",
      "MIKE",
      "NO-VEM-BER",
      "OSS-CAH",
      "PAH-PAH",
      "KEH-BECK",
      "ROW-ME-OH",
      "SEE-AIR-RAH",
      "TANG-GO",
      "YOU-NEE-FORM",
      "VIK-TAH",
      "WISS-KEY",
      "ECKS-RAY",
      "YANG-KEY",
      "ZOO-LOO",
      "WUN",
      "TOO",
      "TREE",
      "FOW-ER",
      "FIFE",
      "SIX",
      "SEV-EN",
      "AIT",
      "NIN-ER",
      "ZEE-RO"
    };
    

    Step 4. Write the Morse codes for letters and numbers

    Let's use 0 for "point" and 1 for "dash". If there is nothing, then -1. 5 numbers are allocated for each symbol.

    int MorseCodes[] =
    {
      0,1,-1,-1,-1, // A
      1,0,0,0,-1, // B
      1,0,1,0,-1, // C
      1,0,0,-1,-1, // D
      0,-1,-1,-1,-1, // E
      0,0,1,0,-1,  //F
      1,1,0,-1,-1, // G
      0,0,0,0,-1,  // H
      0,0,-1,-1,-1,  // I
      0,1,1,1,-1, // J
      1,0,1,-1,-1, // K
      0,1,0,0,-1, // L
      1,1,-1,-1,-1, // M
      1,0,-1,-1,-1,  // N
      1,1,1,-1,-1, // O
      0,1,1,0,-1,  // P
      1,1,0,1,-1,  // Q
      0,1,0,-1,-1, // R
      0,0,0,-1,-1, // S
      1,-1,-1,-1,-1, // T
      0,0,1,-1,-1, // U
      0,0,0,1,-1,  // V
      0,1,1,-1,-1, // W
      1,0,0,1,-1,  // X
      1,0,1,1,-1, // Y
      1,1,0,0,-1, // Z
      0,1,1,1,1, // 1
      0,0,1,1,1, // 2
      0,0,0,1,1, // 3
      0,0,0,0,1, // 4
      0,0,0,0,0, // 5
      1,0,0,0,0, // 6
      1,1,0,0,0, // 7
      1,1,1,0,0, // 8
      1,1,1,1,0, // 9
      1,1,1,1,1 // 0
    };
    

    Step 5. What does it sound and look like?

    To play, write the function void Play (int), which takes as an argument a sequence number from the array int MorseCodes[].

    void Play(int i) {
      for (int j = i * 5; j < i * 5 + 5; j++)
      {
        int k = j - i * 5;
        int x = 40 + (k * (dash_width + padding));
        int y = 160;
        delay(padding_time);
        if (MorseCodes[j] == 0)
        {
          M5.Lcd.fillCircle(x + dash_width / 2, y + dot_height, dot_height, 0x0000);
          M5.Speaker.tone(630);
          delay(dot_time);
          M5.Speaker.mute();
        } 
        else if (MorseCodes[j] == 1)
        {
          M5.Lcd.fillRect(x, y, dash_width, dash_height, 0x0000);
          M5.Speaker.tone(630);
          delay(dash_time);
          M5.Speaker.mute();
        }  
        else;
      }
    }
    

    For clarity, we will draw a diagram of the" point "and"dash".

    Step 6. All clear - let's button!

    As soon as the user clicks the bool M5 method button.BtnB.wasPressed() will return true and we are at this point will force the speaker to emit a tone with a frequency of 630 Hz, and note the current time, millis() to the variable previous_time. - Why is it necessary? - Now you will understand! After the user releases the button the method bool M5.BtnB.was released() will return true and we will remove the tone from the speaker. Next, we will again know the current millis () time and subtract the time saved earlier (which we talked about earlier), so we will know the time the user pressed the key.

    void loop() {
      for (int i = 0; i < sizeof(MorsePhonic) / sizeof(String); i++)
      {
        M5.Lcd.fillScreen(0xffff);
        M5.Lcd.drawRoundRect(40, 40, 64, 64, 10, 0x0000);
        M5.Lcd.setTextColor(0x0000);
        M5.Lcd.setTextSize(5);
        M5.Lcd.setCursor(60, 55);
        M5.Lcd.print(MorseTelephony[i][0]);
        M5.Lcd.setTextSize(2);
        M5.Lcd.setCursor(120, 50);
        M5.Lcd.print(MorseTelephony[i]);
        M5.Lcd.setCursor(120, 80);
        M5.Lcd.print(MorsePhonic[i]);
        Play(i);
        while (true)
        {
          int UserMorseCodeTime[5] = {};
          int actual_time = 0;
          for (int j = i * 5; j < i * 5 + 5; j++)
          {
            if (MorseCodes[j] > -1)
            {
              int k = j - i * 5;
              int previous_time = 0;         
              while (true)
              {
                if (M5.BtnB.wasPressed())
                {
                  previous_time = millis();
                  M5.Speaker.tone(630);
                }
                if (M5.BtnB.wasReleased())
                {
                  M5.Speaker.mute();
                  UserMorseCodeTime[k] = millis() - previous_time;
                  M5.update();
                  break;
                }
                if (M5.BtnC.wasReleased())
                {
                  Play(i);
                }
                M5.update();
              }
            }
          }
          int r = true;
          for (int j = i * 5; j < i * 5 + 5; j++)
          {
            int k = j - i * 5;
            if (MorseCodes[j] == 0)
              actual_time = dot_time;
            else if (MorseCodes[j] == 1)
              actual_time = dash_time;
            if (UserMorseCodeTime[k] == 0)
              break;
            int abs_ = abs(actual_time - UserMorseCodeTime[k]);
            int x = 50 + k * 50;
            int y = 190;
            M5.Lcd.fillRect(x, y, 305, 30, WHITE);
            M5.Lcd.setCursor(x, y);
            if (abs_ > actual_time / 4)
            {
              r = false;
              M5.Lcd.print(":(");
            }
            else
            {
              M5.Lcd.print(":)");
            }
          }
          if (r)
            break;
        }
      }
    }
    

    Next, we write each dot or dash for the symbol in the int usermorsecodetime[5] array and compare it with the reference time for the dot and dash with the assumption of 25%. That's all :)

    Final step. Launch!

    In section "Download" attached video demonstration. This concludes the lesson.

    HOMEWORK

    • Task 1 difficulty: add a greeting at the end of the passage of the alphabet and numbers;
    • Task 2 levels of difficulty: add a system of user ratings: the first attempt-the maximum score, etc.;
    • Task 3 difficulty levels: add a time indicator to hold the key while typing.

    Download