Tone & IRreceive problem

Status
Not open for further replies.
IR removed. Global variables use 762 bytes (37%) of dynamic memory, leaving 1,286 bytes for local variables. Maximum is 2,048 bytes.
Lines are all 70 characters now. Characters are still repeated. I will look to find a different random routine in 'C' that the compiler likes.

v i m q y c t , c i ? 4 s s f 9 l k w 3 k 1 e 3 8 e 9 d 8 e q d k k j 2 q p q 2 7 q d p k 2 j k 8 d k 2 j k : : w v 8 w v 8 w v : w v 8 w v
70 characters
" " e k r w r w 3 q 9 8 3 : 9 : e 8 3 : 9 8 e : 9 : k 8 k 8 e 8 9 8 k 8 k 2 e 8 3 2 " 2 k 2 k 8 e : 9 d 9 d 9 d 9 d 9 d 9 d 9 d 9 d " : 9 d
70 characters

In case pin 13 and random are using the same interrupt, I should build the answer string first and then send the characters!
Edit: I did and it did not help to make the run more random.
The code below is before I wrote this paragraph.
Found an article on improving random seed.

Code:
// send random Morse code
#include <Arduino.h>
byte signalPin = 13; // will control oscillator speaker
unsigned int wpm = 30;
unsigned int elementWait = 1200 / wpm;
unsigned int space = 2;
boolean signal_state = LOW;

void setup() {
  pinMode(signalPin, OUTPUT);
  Serial.begin(9600);
  menu();
}

void loop() {
  parser();
}

void menu() {
  Serial.println();
  Serial.println("Send a random group of characters for Morse practice");
  Serial.println();
  Serial.println("Press Spacebar [Enter] to start");
  Serial.println();
  Serial.println("Enter 's' to adjust letter space (1-whatever)");
  Serial.println();
  Serial.println("Enter w(value) to adjust wpm (Example: w20)");
  Serial.println();
}

void parser()
{
  unsigned int digits;
  unsigned int value = 0;
  do
  {
    digits = Serial.available();
  }
  while (digits < 1);
  char keypress = Serial.read();
  do
  {
    digits = Serial.available();
  }
  while
  (digits < 0);
  value = Serial.parseInt();
  Serial.flush();
  switch (keypress)
  {
    case ' ': // generate code
      {
        random_code();
        break;
      }
    case 's': // letter space
      {
        if (value != 0) space = value;
        break;
      }
    case 'w': // wpm
      {
        if (value != 0) wpm = value;
        elementWait = 1200 / wpm;
        break;
      }
  }
}

void dit() {
  digitalWrite(signalPin, HIGH);
  delay(elementWait);      // milliseconds - one dit
  digitalWrite(signalPin, LOW);
  delay(elementWait);
}

void dah() {
  digitalWrite(signalPin, HIGH);
  delay(elementWait * 3);
  digitalWrite(signalPin, LOW);
  delay(elementWait);
}

void letter_space() {
  delay(elementWait * space);
}

void random_code() {
  // send a random character's Morse equivlent
  char* code_char[] =
  { "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",
    ",", ".", "?", "!", ":", "\"", "'", "="
  };
  char* codes[] =
  { ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--",
    "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", // 26 letters
    "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----.",     // 10 numbers
    "--..--", ".-.-.-", "..--..", "..--.", "---...", ".-..-.", ".----.", "-...-"                  //  8 punctuation
  };
  String send_char; String answers;
  for (unsigned int t = 0; t < 70 ; t++) // each run will be 70 characters and 69 spaces, one line on my screen
  {
    randomSeed(analogRead(0));
    unsigned int randNumber = random(43); // 0 - 43, all characters
    send_char = codes[randNumber];
    String x;
    for (unsigned int i = 0; i < send_char.length(); i++)
    {
      x = send_char.substring(i, i + 1);
      if (x == ".") dit(); else dah();
    }
    letter_space();
    answers.concat(code_char[randNumber]); answers.concat(" ");
    //delay(15);
  }
  Serial.println(answers);
  Serial.print(answers.length() / 2); // remove space between characters from count
  Serial.println(" characters");
}
 
Last edited:
This is working well. (yea!) I think I'm happy with this. IR gone. Random stuff by itself, not toggling with setting a pin. New improved randomseed.
Code:
// send random Morse code
// uses external oscillator. pin D13 high to trigger.
// has improved random seed
#include <Arduino.h>
byte signalPin = 13; // will control oscillator speaker
unsigned int wpm = 20;
unsigned int elementWait = 1200 / wpm;
unsigned int row = 50;
unsigned int space = 2; // time between characters. It is good to send the chacters faster than the space between them for practice.

void setup() {
  pinMode(signalPin, OUTPUT);
  pinMode(1, INPUT); // used in random seed routine
  Serial.begin(9600);
  menu();
}

void loop() {
  parser();
}

void menu() {
  //Serial.println();
  Serial.println("Send a random group of characters for Morse practice");
  Serial.println("Press Spacebar [Enter] to start");
  //Serial.println();
  Serial.println("Enter 's'(value) to adjust letter space (1-whatever)");
  //Serial.println();
  Serial.println("Enter 'w'(value) to adjust wpm (Example: w20)");
  //Serial.println();
  Serial.println("Enter 'r'(value) to set how many characters in the row to send");
  //Serial.println();
  Serial.println("Enter 'm' to display this menu");
  //Serial.print();
  Serial.println("Enter 'c' to clear screen on real terminals");
  //Serial.print();
  Serial.print("Current state: s:"); Serial.print(space); Serial.print(" w:"); Serial.print(wpm); Serial.print(" r:"); Serial.println(row);
  Serial.println();
}

void parser()
{
  unsigned int digits;
  unsigned int value = 0;
  do
  {
    digits = Serial.available();
  }
  while (digits < 1);
  char keypress = Serial.read();
  do
  {
    digits = Serial.available();
  }
  while
  (digits < 0);
  value = Serial.parseInt();
  Serial.flush();
  switch (keypress)
  {
    case 'm': case 'M': // display menu
      {
        menu();
        break;
      }

    case ' ': // generate code
      {
        random_code();
        break;
      }
    case 's': case 'S': // letter space length
      {
        if (value != 0) space = value;
        Serial.print("Letter space(s) "); Serial.println(space);
        break;
      }
    case 'w': case 'W': // wpm
      {
        if (value != 0) wpm = value;
        elementWait = 1200 / wpm;
        Serial.print("wpm: "); Serial.println(wpm);
        break;
      }
    case 'r': case 'R': // how many to send (a row)
      {
        if (value != 0) row = value;
        Serial.print(row); Serial.println(" characters will be sent");
        break;
      }
    case 'c': case 'C':
      {
        refresh_Screen();
        break;
      }
  }
}

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

void dit() {
  digitalWrite(signalPin, HIGH);
  delay(elementWait);      // milliseconds - one dit
  digitalWrite(signalPin, LOW);
  delay(elementWait);
}

void dah() {
  digitalWrite(signalPin, HIGH);
  delay(elementWait * 3);
  digitalWrite(signalPin, LOW);
  delay(elementWait);
}

void letter_space() {
  delay(elementWait * space);
}

void random_code() {
  // send a random character's Morse equivlent
  char* code_char[] =
  { "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",
    ",", ".", "?", "!", ":", "\"", "'", "="
  };
  char* codes[] =
  { ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--",
    "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", // 26 letters
    "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----.",     // 10 numbers
    "--..--", ".-.-.-", "..--..", "..--.", "---...", ".-..-.", ".----.", "-...-"                  //  8 punctuation
  };
  String send_char; String answers; char* send_codes[row - 1];
  unsigned long seed = seedOut(31); randomSeed(seed);
  for (unsigned int t = 0; t < row ; t++) // each run will be 70 characters and 69 spaces, one line on my screen
  {
    unsigned int randNumber = random(43); // 0 - 43, all characters. let random do it's thing, then carry on.
    answers.concat(code_char[randNumber]); answers.concat(" ");
    send_codes[t] = (codes[randNumber]); // array of code character strings to be sent
  }
  for (unsigned int t = 0; t < row ; t++)
  {
    send_char = send_codes[t]; // send the code of a character
    for (unsigned int i = 0; i < send_char.length(); i++) // break it down
    {
      String x;
      x = send_char.substring(i, i + 1);
      if (x == ".") dit(); else dah();
    }
    letter_space();
  }
  Serial.println(answers); Serial.println();
}

// This code to develop a random seed is from here: http://www.utopiamechanicus.com/article/arduino-better-random-numbers/
unsigned int bitOut(void)
{
  static unsigned long firstTime = 1, prev = 0;
  unsigned long bit1 = 0, bit0 = 0, x = 0, port = 1, limit = 99;
  if (firstTime)
  {
    firstTime = 0;
    prev = analogRead(port);
  }
  while (limit--)
  {
    x = analogRead(port);
    bit1 = (prev != x ? 1 : 0);
    prev = x;
    x = analogRead(port);
    bit0 = (prev != x ? 1 : 0);
    prev = x;
    if (bit1 != bit0)
      break;
  }
  return bit1;
}

unsigned long seedOut(unsigned int noOfBits)
{
  // return value with 'noOfBits' random bits set
  unsigned long seed = 0;
  for (int i = 0; i < noOfBits; ++i)
    seed = (seed << 1) | bitOut();
  return seed;
}
 
Last edited:
It has to do with AGC recovery time and latency in between, which is what I am trying to tell you all along....
I assume you have a preamble..... maybe thats it. you don't have one. doh.

Report bit errors and bit position and ensure you read the IR Rx spec and follow all requirements for timing.

The end
 
Last edited:
A version not needing an external oscillator - just a sounder and resistor in series if you don't want to draw 40ma intermittently. I used 220 ohm.
Code:
// send random Morse code
// has improved random seed
// uses tone/notone instead of external oscillator.
// Plug speaker to Analog pin8 and gnd. Use a resistor or pot in series if you want to. I used 220 ohm.

#include <Arduino.h>
byte signalPin = 13; // will control oscillator speaker
unsigned int wpm = 20;
unsigned int elementWait = 1200 / wpm;
unsigned int row = 50;
unsigned int space = 2; // time between characters. It is good to send the chacters faster than the space between them for practice.
unsigned int pitch = 846; // a volume peak on my sounder. needed because I'm using a 220 ohm resistor in series.
const int morseOutPin = 13;    // For Morse code output

void setup() {
  pinMode(signalPin, OUTPUT);
  pinMode(1, INPUT); // used in random seed routine
  noTone(8);
  pinMode(morseOutPin, OUTPUT);
  Serial.begin(9600);
  menu();
}

void loop() {
  parser();
}

void menu() {
  //Serial.println();
  Serial.println("Send a random group of characters for Morse practice");
  Serial.println("Press Spacebar [Enter] to start");
  //Serial.println();
  Serial.println("Enter 's'(value) to adjust letter space (1-whatever)");
  //Serial.println();
  Serial.println("Enter 'w'(value) to adjust wpm (Example: w20)");
  //Serial.println();
  Serial.println("Enter 'p'(value) to set tone pitch <p31-24000 or <0 for off");
  //Serial.println();
  Serial.println("Enter 'r'(value) to set how many characters in the row to send");
  //Serial.println();
  Serial.println("Enter 'm' to display this menu");
  //Serial.print();
  Serial.println("Enter 'c' to clear screen on real terminals");
  //Serial.print();
  Serial.print("Currently: s:"); Serial.print(space); Serial.print(" w:"); Serial.print(wpm);
  Serial.print(" r:"); Serial.print(row); Serial.print(" P:"); Serial.println(pitch);
  Serial.println();
}

void parser()
{
  unsigned int digits;
  unsigned int value = 0;
  do
  {
    digits = Serial.available();
  }
  while (digits < 1);
  char keypress = Serial.read();
  do
  {
    digits = Serial.available();
  }
  while
  (digits < 0);
  value = Serial.parseInt();
  Serial.flush();
  switch (keypress)
  {
    case 'm': case 'M': // display menu
      {
        menu();
        break;
      }
    case ' ': // generate code
      {
        random_code();
        break;
      }
    case 's': case 'S': // letter space length
      {
        if (value != 0) space = value;
        Serial.print("Letter space(s) "); Serial.println(space);
        break;
      }
    case 'w': case 'W': // wpm
      {
        if (value != 0) wpm = value;
        elementWait = 1200 / wpm;
        Serial.print("wpm: "); Serial.println(wpm);
        break;
      }
    case 'r': case 'R': // how many to send (a row)
      {
        if (value != 0) row = value;
        Serial.print(row); Serial.println(" characters will be sent");
        break;
      }
    case 'c': case 'C':
      {
        refresh_Screen();
        break;
      }
    case 'p': case 'P':
      {
        pitch = value;
        if (pitch == 0)
        {
          pitch = 0;
          noTone(8);
          Serial.println("Tone echo is now off."); // stare at the led
          break;
        }
        if (pitch < 31)
        {
          Serial.println("31 is minimum");
          break;
        }
        if (pitch > 24000)
        {
          Serial.print("24000 is max");
          break;
        }
        Serial.print("Tone pitch in Hz:"); Serial.println(pitch, DEC);
        tone(8, pitch, 400);
        break;
      }
  }
}

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

void dit() {
  digitalWrite(signalPin, HIGH);
  if (pitch != 0) tone(8, pitch);
  delay(elementWait);      // milliseconds - one dit
  digitalWrite(signalPin, LOW);
  noTone(8);
  delay(elementWait);
}

void dah() {
  digitalWrite(signalPin, HIGH);
  if (pitch != 0) tone(8, pitch);
  delay(elementWait * 3);
  digitalWrite(signalPin, LOW);
  noTone(8);
  delay(elementWait);
}

void letter_space() {
  delay(elementWait * space);
}

void random_code() {
  // send a random character's Morse equivlent
  char* code_char[] =
  { "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",
    ",", ".", "?", "!", ":", "\"", "'", "="
  };
  char* codes[] =
  { ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--",
    "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", // 26 letters
    "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----.",     // 10 numbers
    "--..--", ".-.-.-", "..--..", "..--.", "---...", ".-..-.", ".----.", "-...-"                  //  8 punctuation
  };
  String send_char; String answers; char* send_codes[row - 1];
  unsigned long seed = seedOut(31); randomSeed(seed);
  for (unsigned int t = 0; t < row ; t++) // each run will be 70 characters and 69 spaces, one line on my screen
  {
    unsigned int randNumber = random(43); // 0 - 43, all characters. let random do it's thing, then carry on.
    answers.concat(code_char[randNumber]); answers.concat(" ");
    send_codes[t] = (codes[randNumber]); // array of code character strings to be sent
  }
  for (unsigned int t = 0; t < row ; t++)
  {
    send_char = send_codes[t]; // send the code of a character
    for (unsigned int i = 0; i < send_char.length(); i++) // break it down
    {
      String x;
      x = send_char.substring(i, i + 1);
      if (x == ".") dit(); else dah();
    }
    letter_space();
  }
  Serial.println(answers); Serial.println();
}

// This code to develop a random seed is from here: http://www.utopiamechanicus.com/article/arduino-better-random-numbers/
unsigned int bitOut(void)
{
  static unsigned long firstTime = 1, prev = 0;
  unsigned long bit1 = 0, bit0 = 0, x = 0, port = 1, limit = 99;
  if (firstTime)
  {
    firstTime = 0;
    prev = analogRead(port);
  }
  while (limit--)
  {
    x = analogRead(port);
    bit1 = (prev != x ? 1 : 0);
    prev = x;
    x = analogRead(port);
    bit0 = (prev != x ? 1 : 0);
    prev = x;
    if (bit1 != bit0)
      break;
  }
  return bit1;
}

unsigned long seedOut(unsigned int noOfBits)
{
  // return value with 'noOfBits' random bits set
  unsigned long seed = 0;
  for (int i = 0; i < noOfBits; ++i)
    seed = (seed << 1) | bitOut();
  return seed;
}
 
Last edited:
I dont appreciate your derogatory remarks.

Can you state your objectives more clearly and improve your test methods?

I am seeing a lot of random jibberish (intended by your goal to find a random error with pseudo random data), which as I have tried to guide you and failed is the wrong approach.
 
Can you sketch a block diagram?

I understand you wish to communicate 120 wpm without framing errors or buffer over-runs or modulation sidebands or serial I/O FIFO errors, but I am not familiar with any past posts or present objects.

In 40 yrs, I have never had a unsolvable comm error , be it DS1 or T1 to a hundred homes in '81 or 9600 baud between two calculators over 1km in a remote SCADA (before the name was invented ) in 1977 on HP stuff which had DMA issues, but symbol quality in both Tx, Rx and errors depend on both analog and digital format, CPU handling of interrupts, sideband filtering etc etc.

For me, it important to see what is missing with a block diagram with abbreviated features, if you please.
 
Last edited:
I was going to edit post #30 but you posted already so here is your answer about my objectives and how I have perceived your responses. Like I said, we are in different worlds.
Block diagram...can you not understand the 'C' code at all?
Well here is the response I was preparing. I'll get back about the block diagram if you really need it.
---
OK, I'll try to summarize (even though it's still spring).

The thread started because I noticed that IRreceive and tone() did not play well together.
I decided it was an interrupt issue.

Stopped using tone() and built an oscillator.
It was simpler than trying to change libraries I did not understand.
I only have SOME basic programming skills.

IRreceive was working fine at this point.
tone() was removed from the sketch (program).
I see your first post about IR.
I told you IR was fine.

Then I noticed random() was performing poorly.
It's purpose is to help output random letters.
Whole lines of text were repeating!
I was dumbfounded. (where does that word come from)

You decide the problem is IR because you did not bother to read the code or understand what the program is supposed to do. IRreceive is only used to select menu items. It does not have any other function in the sketch.

I suggest the problem is elsewhere. You are adamant that I delve into the workings of the IR communication. I know this is not necessary. IRreceive has no problem selecting menu items. That is all it has to do. I explain I still believe the problem is with random().
You will not accept this. You still do not try to understand the sketch and see what the program does and how it does it. You tell me again to study ISI.

I do not immediately respond to your post. I don't want to tell someone of your experience that you are completely off base.

I play with random(). Moving the routine to various places in the code.

I try to tell you the problem is with random(). You start to grasp that you do not understand the sketch and say that I was not clear and that's why. You still have not commented on the code. You tell me I need to study randomness.

I'm thinking the random() function sucks! Simply bad coding. In the 90s I wrote a simple random function in 8080 assembler and it worked fine. I remove random() from the program and everything is perfect. Line lengths are correct anyway. Since the problems are strange for a sketch to produce I assume that memory is being corrupted in runtime.

I remove all code except the program feature I'm interested in.
Line length is now consistent but the randomness is still poor.
I remove IRreceive because I suspect it may be sharing an interrupt with random().
I then had random() do it's job completely instead of calling it between other things to be done. This did not help.

Next I looked for a better random function for the Arduino thinking someone else must be unhappy with what came with the compiler. I found a better randomseed routine.
Used it and the program results were improved!

I post that the program is working well and you tell me the problem is AGC (which I know as Automatic Gain Control) and latency. You don't care that IRreceive is not part of the program anymore. If I want the program to work I must do as you say. You don't like that the program does not have a preamble. You finally look at the code! Well no, you look for a comment section. What the biblical place do you think this thread is if not comments on the code?

Again you insist your points are completely on track and I'm a very poor student.
I can't believe you are so out of touch and accuse you of trolling.
 
Last edited:
i still dont know the performance parameters and attributes of your communication link.

Please list all relevant parameters, for desired protocols and rates for bit, word, frame , async method, parity, and purpose of link.

Even Apple II had a horrible random function. We used it to address every sector on a HDD test then displayed the sectors in a pixel map to see the problem. Using time of day and other hashcodes, we made it work. Whenever, I designed PRSG patterns I used simple XOR Shift Register terms to match optimum maximal length sequence, and use suitable hash for initial condition. Rolling Codes use more elegant solutions in Microchip's offerings.
 
There is no link except USB. (no IR)
The Arduino Uno R3 has a USB2 port. Do you know what an Arduino is?
The USB connects to a Windows desktop computer USB2 port.
After programming the Arduino the port is used as a terminal link to/from Arduino and computer.
Keyboard input (no IR) screen output (no IR).
I use, for now, the random() code that came with the free compiler that is offered here:
https://www.arduino.cc/en/Main/Software

I am not going to delve into the math of randomness. I don't have the brain for it. My math training and skills are basic.
If I find a better rand routine I'll try it.

Your skills may be impressive but they are of no use to me, it seems. (hint hint)
 
https://www.google.ca/search?q=maximal length sequence generator&client=safari&hl=en&source=lnms&tbm=isch&sa=X&ei=IlVGVYa2J4qtyQTvgoHoBg&ved=0CAgQ_AUoAWoVChMIhs-_hIemxQIVilaSCh1vQQBt&biw=1024&bih=644 Your inability to define the goal/problem is what restricts me or anyone from giving you the solution.

From my Xtal ball,google images, i share some trivial random solutions for random number sequence generators, which can be implemented in a few bytes of code or a shift register and XOR gates of length N like N=19 or 2^19 -1 for half a million unique words or 2^7-1 for the ASCII set. There are only solutions for a few prime-related integers that are practical. In your case, addition filters to skip non-used ASCII values may be needed. You need a seed that does not violate the stuck all 1's or 0's depending if you use XNOR or XOR.
 
Goal (for now): Have a look at the code in post #22, please. ~ line 174.
Have random(43) build a string of 44 characters that do not repeat. This will be String answers.

I feel this can be done by checking the string as it is being built and jumping a step (concat) and not incrementing the for loop if a character match is found. I will try this. If it works I will have what I need and then some.
This may add a second or three at run time. I can live with that. Actually I expect it will not. Maybe a few milliseconds.

So I have to develop a little bit of code to check the new number that random() has spit out against the string answers as it is being built. Hope that is clear.

That is my goal...today.
Broader goal. Increase my Morse receiving skill by practice.
 
I've moved the project to another site.
It's pretty much finished and I believe useful for code practice.
If anyone is interested send me a private message.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…