1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

Morse encoder/decoder - my first project

Discussion in 'Arduino' started by flat5, Mar 23, 2015.

  1. be80be

    be80be Well-Known Member

    Joined:
    Aug 23, 2008
    Messages:
    4,798
    Likes:
    134
    Location:
    morristown,tn
    You could use a serial LCD backpack
     
  2. flat5

    flat5 Member

    Joined:
    Oct 26, 2008
    Messages:
    866
    Likes:
    8
    Location:
    Amsterdam
    I have some 2x16 displays and backpacks. The Uno does not have enough memory (was it variable? I think so) for all of it to compile. Well, as I remember, it did compile with a warning but the program did not run.

    I wonder if it is possible to use two Unos to run an application.
    Perhaps one to just handle the display or if there is a board to do this.
     
  3. be80be

    be80be Well-Known Member

    Joined:
    Aug 23, 2008
    Messages:
    4,798
    Likes:
    134
    Location:
    morristown,tn
    The backpack I'm thinking would just use the serial your sending to the computer there would be no extra code
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. flat5

    flat5 Member

    Joined:
    Oct 26, 2008
    Messages:
    866
    Likes:
    8
    Location:
    Amsterdam

    Can you write an example?
    Would this need to be converted?
    Serial.print("LA TI DA");

    Seems I have the Nokia-5110 LCD display.
    Breadboard time...once the level shifters arrive.
     
    Last edited: Apr 21, 2015
  6. flat5

    flat5 Member

    Joined:
    Oct 26, 2008
    Messages:
    866
    Likes:
    8
    Location:
    Amsterdam
    Still working on the 567 tone decoder. Fine tuning some capacitor values and types. Would using back to back germanium diodes at the input help or hinder, etc.
    Code update. Lot of memory saved by a trick I just found!
    Changing 'Serial.print("something")' to Serial.print(F("something")) really makes a difference if you have lots of such statements!
    Code (text):

    /*
      sketch_morse_3.1_analog
      MORSE EN-DE-CODER 1.06
      A Morse encoder / decoder for the Arduino.
      May, 11, 2015
    */

    // BB variables
    unsigned int pitch = 800;
    boolean refreshScreen = true; //false;
    const byte pinA = 2;  // encoder pin A to Arduino pin 2 which is also interrupt pin 0 which we will use
    const byte pinB = 3;  // encoder pin B to Arduino pin 3 which is also interrupt pin 1 but we won't use it
    byte state = 0;  // will store two bits for pins A & B on the encoder which we will get from the pins above
    int bump[] = {0, 0, -1, 1};
    int level = 0;  // rotary encoder
    boolean switchState = 1;  // encoder pin state
    // switch stuff unused!
    int encoderSwitchPin = 4;  //encoder pin
    //boolean switchState = 1;  // encoder pushswitch
    int increment = 4;  // rotary encoder increment - 1
    // BB -----------------------------------

    // Simple analog input signal threshold (512 = middle-ish)
    // Set high enough to avoid noise, low enough to get signal
    // ( 512 + noise < AudioThreshold < 512 + signal )
    int AudioThreshold = 400; // (BB) works for me using my preamp
    unsigned int wpm = 20; // Word-per-minute speed
    const char MorseCommand = '<'; // Used as a command character to adjust some settings via serial.
    unsigned long debounceDelay = 20; // the debounce time. Keep well below dotTime!! 20 this is ok to at least 200wpm
    // Other Morse variables
    unsigned long dotTime = 1200 / wpm;  // morse dot time length in ms
    unsigned long dashTime = 3 * 1200 / wpm;
    unsigned long wordSpace = 7 * 1200 / wpm;
    const int analogPin = 0;  // Analog input pin for audio morse code
    const int morseInPin = 7;  // The Morse keyer button
    const int morseOutPin = 13;  // For Morse code output
    unsigned long markTime = 0;  // timers for mark and space in morse signal
    unsigned long spaceTime = 0;  // E=MC^2 ;p
    boolean morseSpace = false;  // Flag to prevent multiple received spaces
    boolean gotLastSig = true;  // Flag that the last received morse signal is decoded as dot or dash
    const int morseTreetop = 63;  // This is for ITU with puncutation, but without non-english extensions
    const int morseTableLength = (morseTreetop * 2) + 1;
    const int morseTreeLevels = log(morseTreetop + 1) / log(2);
    int morseTableJumper = (morseTreetop + 1) / 2;
    int morseTablePointer = morseTreetop;

    // This is the table for ITU with punctuation (but without non-english characters - for now)
    char morseTable[] = "*5*H*4*S***V*3*I***F***U?!_**2*E***L\"**R*+.****A***P@**W***J'1* *6-B*=*D*/"
      "*X***N***C;*!K*()Y***T*7*Z**,G***Q***M:8*****O*9***0*"; //BB 52 characters, I think

    int morseSignals;  // nr of morse signals to send in one morse character
    char morseSignal[] = "......"; // temporary string to hold one morse character's signals to send
    int morseSignalPos = 0;
    int sendingMorseSignalNr = 0;
    unsigned long sendMorseTimer = 0;
    boolean morseEcho = false; // Echoes character to encode back to serial and Morse signal input to output pin
    boolean listeningAudio = false;
    boolean sendingMorse = false;
    boolean morseSignalState = false;
    boolean lastKeyerState = false;
    unsigned long lastDebounceTime = 0;  // the last time the input pin was toggled

    void setup()
    {
      // BB rotary encoder stuff ------------------------------------
      pinMode(pinA, INPUT);  // reads Pin A of the encoder
      pinMode(pinB, INPUT);  // reads Pin B of the encoder
      digitalWrite(pinA, HIGH);
      digitalWrite(pinB, HIGH);
      level = wpm;  // starting point for encoder
      tone(8, pitch); // (BB) duration is always on (port,freq,millseconds)
      pinMode(encoderSwitchPin, INPUT); //switch
      digitalWrite(encoderSwitchPin, HIGH); //turn pullup resistor on
      // Set up to call our knob function any time pinA rises
      attachInterrupt(0, knobTurned, RISING);  // calls 'knobTurned()' function when pinA goes from LOW to HIGH
      pinMode(morseInPin, INPUT);
      digitalWrite(morseInPin, HIGH); // internal pullup resistor on
      pinMode(morseOutPin, OUTPUT);
      // ------------------------------------------------------------
      Serial.begin(115200); // 9600 115200 300 2  <------- if garbage on screen, check terminal baud rate ***
      Serial.println(F("Morse en-/de-coder by raron. Customed by Flat5"));
      help();
      displayCurrentSettings(); // default settings at this point (BB added)
      markTime = millis();
      spaceTime = millis();
    }

    void loop()
    {
      switchState == digitalRead(encoderSwitchPin);
      if (switchState != HIGH) {
      knobTurned();
      }
      boolean morseKeyer = !digitalRead(morseInPin); // inverted for active-low input
      // If the switch changed, due to noise or pressing:
      if (morseKeyer != lastKeyerState)
      {
      lastDebounceTime = millis(); // reset timer
      listeningAudio = false;  // disable listen to audio-mode
      }

      // debounce the morse keyer, unless listening to audio morse signal
      if (!listeningAudio && (millis() - lastDebounceTime) > debounceDelay)
      {
      // whatever the reading is at, it's been there for longer
      // than the debounce delay, so take it as the actual current state:
      morseSignalState = morseKeyer;
      // differentiante mark and space times
      if (morseSignalState) markTime = lastDebounceTime; else spaceTime = lastDebounceTime;
      }

      // If no manual morse keying the last second, enter audio listen mode
      if (!morseKeyer && millis() - lastDebounceTime > 1000)  listeningAudio = true;

      // Filter audio morse signal
      if (listeningAudio)
      {
      int audioMorse = analogRead(analogPin);
      unsigned long currentTime = millis();

      // Check for an audio signal...
      if (audioMorse > AudioThreshold)
      {
      // If this is a new morse signal, reset morse signal timer
      if (currentTime - lastDebounceTime > dotTime / 2)
      {
      markTime = currentTime;
      morseSignalState = true; // there is currently a signal
      }
      lastDebounceTime = currentTime;
      } else {
      // if this is a new pause, reset space time
      if (currentTime - lastDebounceTime > dotTime / 2 && morseSignalState == true)
      {
      spaceTime = lastDebounceTime; // not too far off from last received audio
      morseSignalState = false;  // No more signal
      }
      }
      }

      // Morse output, or a feedback when keying.
      if  (!sendingMorse && morseEcho) digitalWrite(morseOutPin, morseSignalState);

      // Encode Morse code or execute commands
      if (Serial.available() > 0 && !sendingMorse)
      {
      char encodeMorseChar = Serial.read();
      // if a command instead, adjust some settings
      if (encodeMorseChar == MorseCommand)
      {
      // parser BB modified ----------------------------------------------------------------------------------
      int digits;
      int value = 0;
      int var = wpm; // If wpm is very fast keyboard input requires very fast typing. After command input re-set wpm
      wpm = 5;  // for now
      do
      {
      digits = Serial.available();
      }
      while (digits < 1);
      // Read what setting
      char morseSet = Serial.read();
      do
      {
      digits = Serial.available();
      }
      while (digits < 0);
      value = Serial.parseInt();
      Serial.flush(); // just in case
      // Adjust and print the new setting
      // BB added
      if (refreshScreen == true) refresh_Screen();
      else Serial.println();
      switch (morseSet)
      {
      case '>':
      refresh_Screen();
      break;

      case 'a': case 'A': // Audio input threshold value
      AudioThreshold = value;
      if (AudioThreshold < 0) AudioThreshold = 0; // not recommended
      Serial.print(F(" > Audio threshold:"));
      Serial.print (value, DEC);
      Serial.println(" <");
      break;

      case 'd': case 'D': // Debounce value
      debounceDelay = (unsigned long) value;
      if (debounceDelay < 0) debounceDelay = 0;
      Serial.print(F(" > Debounce (ms):"));
      Serial.print (value, DEC);
      Serial.println(F(" <"));
      break;

      case 'e': case 'E': // Turn on / off Morse echo back to serial and Morse output pin
      if (value > 0)
      {
      morseEcho = true;
      Serial.println(F(" > Echo: on <"));
      } else {
      morseEcho = false;
      Serial.println(F(" > Echo: off <"));
      }
      break;

      // BB added ------------------------------------

      case 'p': case 'P': // tone frequency
      pitch = value;
      if (pitch == 0)
      {
      pitch = 0;
      noTone(8);
      Serial.println(F(" > Tone echo is now off. <"));
      break;
      }
      if (pitch < 31)
      {
      Serial.println(F(" > 31 is minimum <"));
      break;
      }
      if (pitch > 24000)
      {
      Serial.print(F(" > 24000 is max <"));
      break;
      }
      Serial.print(F(" > Tone freq. is "));
      Serial.print(pitch, DEC);
      Serial.println(F(" <"));
      tone(8, pitch);
      break;

      case 'r': case 'R': // clear screen. works only with real terminals otherwise puts garbage on screen.
      if (value > 0)  // r1 to enable | r to disable
      {
      refreshScreen = true;
      Serial.println(F(" > Screen refresh enabled <"));
      }
      else
      {
      refreshScreen = false;
      Serial.println(F(" >Screen refresh disabled <"));
      }
      break;

      case 'h': case 'H': case '?': case 'm': case 'M': // display options and current settings
      help();
      displayCurrentSettings();
      break;

      case 't': case 'T': // encoder increment
      if (value > 0 && value < 201)
      {
      increment = value - 1;
      Serial.print(F("> Increment: "));
      Serial.println(value);
      Serial.print(F(" <"));
      }
      else
      {
      Serial.println(F("> out of range: 1-200 <"));
      }
      break;
      //--------------------------------------------- BB

      case 'w': case 'W': // Morse speed setting in wpm
      wpm = value;
      var = value;  // re-set wpm again at end of command parsing
      if (wpm <= 4)
      {
      wpm = 5;
      var = 5;
      Serial.println(F(" > 5 min <"));
      }
      if (wpm > 200)
      {
      wpm = 200;
      var = 200;
      Serial.println(F(" > 200 max <"));
      }
      setDotDash();
      Serial.print(F(" > wpm: "));
      Serial.print (wpm, DEC);
      Serial.println(F(" <"));
      break;

      case 'i': case 'I': // Display info (current settings).
      wpm = var;
      displayCurrentSettings();
      break;

      default:
      Serial.print(F(" > Unrecognized command <"));
      }
      // Mark that we have executed a command (don't send morse)
      encodeMorseChar = MorseCommand;
      wpm = var; // done typing, re-set wpm
      }
      // end of command parsing ------------------------------------------------------------
      if (encodeMorseChar != MorseCommand)
      {
      // change to capital letter if not
      if (encodeMorseChar > 'Z') encodeMorseChar -= 'z' - 'Z';

      // Scan for the character to send in the Morse table
      int i;
      for (i = 0; i < morseTableLength; i++) if (morseTable[i] == encodeMorseChar) break;
      int morseTablePos = i + 1; // 1-based position

      // Reverse dichotomic / binary tree path tracing

      // Find out what level in the binary tree the character is
      int test;
      for (i = 0; i < morseTreeLevels; i++)
      {
      test = (morseTablePos + (0x0001 << i)) % (0x0002 << i);
      if (test == 0) break;
      }
      int startLevel = i;
      morseSignals = morseTreeLevels - i; // = the number of dots and/or dashes
      morseSignalPos = 0;

      // Travel the reverse path to the top of the morse table
      if (morseSignals > 0)
      {
      // build the morse signal (backwards from last signal to first)
      for (i = startLevel; i < morseTreeLevels; i++)
      {
      int add = (0x0001 << i);
      test = (morseTablePos + add) / (0x0002 << i);
      if (test & 0x0001 == 1)
      {
      morseTablePos += add;
      // Add a dot to the temporary morse signal string
      morseSignal[morseSignals - 1 - morseSignalPos++] = '.';
      } else {
      morseTablePos -= add;
      // Add a dash to the temporary morse signal string
      morseSignal[morseSignals - 1 - morseSignalPos++] = '-';
      }
      }
      } else {  // unless it was on the top to begin with (A space character)
      morseSignal[0] = ' ';
      morseSignalPos = 1;
      morseSignals = 1; // cheating a little; a wordspace for a "morse signal"
      }
      morseSignal[morseSignalPos] = '\0';

      // Echo back the letter with morse signal as ASCII to serial output
      if (morseEcho)
      {
      Serial.print(encodeMorseChar);
      Serial.print(morseSignal);
      Serial.print(" ");
      }
      if (morseTablePos - 1 != morseTreetop)

      {
      Serial.println();
      // Serial.print(F("..Hm..error? MorseTablePos = "));
      // Serial.println(morseTablePos);
      }
      // start sending the character
      sendingMorse = true;
      sendingMorseSignalNr = 0;
      sendMorseTimer = millis();
      if (morseSignal[0] != ' ') digitalWrite(morseOutPin, HIGH);
      }
      }

      // Send Morse signals to output
      if (sendingMorse)
      {
      switch (morseSignal[sendingMorseSignalNr])
      {
      case '.': // Send a dot (actually, stop sending a signal after a "dot time")
      if (millis() - sendMorseTimer >= dotTime)
      {
      digitalWrite(morseOutPin, LOW);
      sendMorseTimer = millis();
      morseSignal[sendingMorseSignalNr] = 'x'; // Mark the signal as sent
      }
      break;
      case '-': // Send a dash (same here, stop sending after a dash worth of time)
      if (millis() - sendMorseTimer >= dashTime)
      {
      digitalWrite(morseOutPin, LOW);
      sendMorseTimer = millis();
      morseSignal[sendingMorseSignalNr] = 'x'; // Mark the signal as sent
      }
      break;
      case 'x': // To make sure there is a pause between signals and letters
      if (sendingMorseSignalNr < morseSignals - 1)
      {
      // Pause between signals in the same letter
      if (millis() - sendMorseTimer >= dotTime)
      {
      sendingMorseSignalNr++;
      digitalWrite(morseOutPin, HIGH); // Start sending the next signal
      sendMorseTimer = millis();  // reset the timer
      }
      } else {
      // Pause between letters
      if (millis() - sendMorseTimer >= dashTime)
      {
      sendingMorseSignalNr++;
      sendMorseTimer = millis();  // reset the timer
      }
      }
      break;
      case ' ': // Pause between words (minus pause between letters - already sent)
      default:  // Just in case its something else
      if (millis() - sendMorseTimer > wordSpace - dashTime) sendingMorse = false;
      }
      if (sendingMorseSignalNr >= morseSignals) sendingMorse = false; // Ready to encode more letters
      }

      // Decode morse code
      if (!morseSignalState)
      {
      if (!gotLastSig)
      {
      if (morseTableJumper > 0)
      {
      // if pause for more than half a dot, get what kind of signal pulse (dot/dash) received last
      if (millis() - spaceTime > dotTime / 2)
      {
      // if signal for more than 1/4 dotTime, take it as a valid morse pulse
      if (spaceTime - markTime > dotTime / 4)
      {
      // if signal for less than half a dash, take it as a dot, else if not, take it as a dash
      // (dashes can be really really long...)
      if (spaceTime - markTime < dashTime / 2) morseTablePointer -= morseTableJumper;
      else morseTablePointer += morseTableJumper;
      morseTableJumper /= 2;
      gotLastSig = true;
      }
      }
      } else { // error if too many pulses in one morse character
      Serial.println(F("<ERROR: unrecognized signal!>"));
      gotLastSig = true;
      morseTableJumper = (morseTreetop + 1) / 2;
      morseTablePointer = morseTreetop;
      }
      }
      // Write out the character if pause is longer than 2/3 dash time (2 dots) and a character received
      // if ((millis() - spaceTime >= (dotTime * 2)) && (morseTableJumper < ((morseTreetop+1)/2)))
      if ((millis() - spaceTime >= (dotTime * 2)) && (morseTableJumper < ((morseTreetop + 1) / 2)))
      {
      char morseChar = morseTable[morseTablePointer];
      Serial.print(morseChar);
      morseTableJumper = (morseTreetop + 1) / 2;
      morseTablePointer = morseTreetop;
      }
      // Write a space if pause is longer than 2/3rd wordspace
      if (millis() - spaceTime > (wordSpace * 2 / 3) && morseSpace == false)
      {
      Serial.print(" ");
      morseSpace = true ; // space written-flag
      }

      } else {
      // while there is a signal, reset some flags
      gotLastSig = false;
      morseSpace = false;
      }

      // save last state of the morse signal for debouncing
      lastKeyerState = morseKeyer;
    }

    // end loop ----------------------------------------------------

    void displayCurrentSettings() {
      Serial.println();
      Serial.print(F("Morse speed: ")); Serial.print (wpm, DEC); Serial.print(F(" wpm (dot=")); Serial.print (dotTime, DEC);
      Serial.print(F("ms, dash=")); Serial.print (dashTime, DEC); Serial.println(F("ms)"));
      Serial.print(F("Rotary Encoder increment: ")); Serial.println(increment + 1);
      Serial.print(F("Audio threshold: ")); Serial.println(AudioThreshold, DEC);
      Serial.print(F("Tone freq: ")); Serial.print(pitch); Serial.println(F("Hz"));
      Serial.print(F("Debounce: ")); Serial.print(debounceDelay, DEC); Serial.println(F(" ms."));
      Serial.print(F("Screen Refresh ")); if (refreshScreen == 0) Serial.println(F("off")); else Serial.print(F("on"));
      Serial.println();
    }

    void knobTurned() { // rotary encoder
      level = wpm;
      state = 0;  // reset this value each time
      state = state + digitalRead(pinA);  // add the state of Pin A
      state <<= 1;  // shift the bit over one spot
      state = state + digitalRead(pinB);  // add the state of Pin B
      delay(2); // (BB) using .01uf caps & 4.7k resistors for debounce. It is causing a double speak.
      level = level + bump[state];
      if (level > wpm) wpm = level + increment; if (wpm > 200) wpm = 200; // increment wpm by 5 or user defined. stop at 200
      else  wpm = level - increment; if (wpm < 5) wpm = 5;  // decrement wpm by 5 or user defined. stop at 5
      setDotDash();
      refresh_Screen;
      Serial.println(); Serial.print(wpm);
      delay(2); // debounce
    }

    void setDotDash()
    {
      dotTime = 1200 / wpm;
      dashTime = 3 * 1200 / wpm;
      wordSpace = 7 * 1200 / wpm;
    }

    void refresh_Screen()
    {
      if (refreshScreen == true)
      {
      Serial.write(27); // ESC
      Serial.write("[2J"); // clear screen
      Serial.write(27); // ESC
      Serial.write("[H"); // cursor to home
      }
    }

    void help() // Help Screen
    {
      Serial.println();
      Serial.println(F("To change paramaters"));
      Serial.println(F("Options begin with: <\n"));
      Serial.println(F("This help screen: <h"));
      Serial.println(F("Morse speed: <w5-200"));
      Serial.println(F("Rotary Encoder increment: <t1-200"));
      Serial.println(F("Hz. Tone pitch: <p31-24000 or <0 for off"));
      Serial.println(F("Display current settings: <i"));
      Serial.println(F("ms. Debounce: <d0-50"));
      Serial.println(F("ms. Audio threshold: <a300-600"));
      Serial.println(F("Screen Refresh for real terminals: <r (off) <r1 (on)"));
      Serial.println(F("To refresh screen: <>\n"));
      Serial.println(F("Reset monitor or Arduino to restore default settings"));
    }

    /*
    Some of these comments are outdated (BB)

    3 input methods for decoding and encoding:
    -  Audio Morse signals on an analog input (for decoding).
    -  Morse keying on digital input (for decoding).
    -  ASCII text via serial communication (for encoding. Also for adjusting settings).

    2 outputs for encoded and decoded Morse:
    -  Morse-code toggled output pin (for encoded Morse).
    -  ASCII text via serial communication (for decoded Morse) .

    It will enter audio listen mode if nothing is keyed in within a second.

    Serial input:
    Only International Morse Code (letters A-Z, numbers), and space, are
    encoded and sent as Morse code automatically unless whatever the "command"
    character is (default '<') is received.
    No punctuation supported (but the morse table can be extended easily for that)

    Morse en-/de-coder < commands via serial:
    The ASCII "less than" character '<' denotes a command instead of encoding and
    sending Morse. The format is:

      <Lxxx

    where L is a letter and xxx is a three-digit decimal number 000-999.
    One exception is the <i command for info (displays current settings).
    The letter can be upper or lower case W, A, D, E or I. Examples:

      <w008 - sets speed to 8 wpm
      <a900 - sets audio threshold to be 900
      <D020 - sets debounce delay to be 20 milliseconds.
      <e000 - turn off Morse echo back to serial as ASCII and output pin as Morse
      <e001 - turn on Morse echo (any value above 0 will do)
      <i  - info - displays some settings

    Full duplex:
    It can both transmit and receive simultaneously, but serial output will
    be a mixed mess unless echo is turned off.

    NOTE: Values for tolerance (like dot time or dash time divided by 2 etc) are
      more or less arbitrarily/experimentally chosen.

      Sorry the source code is a big mess for now...

    Based on Debounce example from the Arduino site for the morse keyer button
    (http://www.arduino.cc/en/Tutorial/Debounce).
    Loosely based on Morse Decoder 3.5 from 1992 for the Amiga by the same guy.
    Contact: raronzen@gmail.com  (not checked too often..)

    Copyright (C) 2010 raron

      This program is free software: you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.

      You should have received a copy of the GNU General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.

    History:
    1992.01.06 - Morse decoder 3.5 - 68000 Assembler version for the Amiga 600
      using a binary tree (dichotomic table) for Morse decoding
    2010.11.11 - Rewrite for the Arduino
    2010.11.27 - Added Morse encoding via reverse-dichotomic path tracing.
      Thus using the same Morse table / binary tree for encoding and decoding.
    2010.11.28 - Added a simple audio Morse signal filter. Added a simple command parser
    2010.11.29 - Added echo on/off command

    2015.3 - some modification by Barry Block to use the 'tone' ability.
      input & output circuits modified
      plan to add a rotary encoder to adjust speed.

    TODO: Make the timings signed long again, to avoid rollover issue
      Avoid calling millis() all the time?
      Make functions or classes out of it sometime...
      Generally tidy it up
    Not enough variable memory to include the LCD backpack routines. :-(
    */
     
     
    Last edited: May 23, 2015
  7. flat5

    flat5 Member

    Joined:
    Oct 26, 2008
    Messages:
    866
    Likes:
    8
    Location:
    Amsterdam
    up-dated input interface using a tone decoder to improve 'off the air' detection.
    Not finished. Suggestions very welcome.
    Edit: Maybe finished :)

    Arduino Morse Interface v2(3).png
    NE567 tone decoder board pic1.jpg
     
    Last edited: May 27, 2015

Share This Page