deltaTime and loop() in arduino

I am currently working on a project where we take a string and iterate through it to receive the chars associated with it to morsecode. For example,
"Hi" would return .... .. one symbol at a time. However, we are attaching an led to this that would blink for each symbol but for a dash it would stay on for 3x the length it would stay on for a dot. However, we are prohibited from using any loops except the provided loop() in arduino. Can someone give me a headstart? I tried to create the program with the loops and already without delays() and instead with my deltaTime but I am so confused on how to break out of those loops.

***THANK YOU ALL. I finished my project and it worked out extremely well thanks to the resources you all pointed me towards.

school work ?

I would suggest to study

you have been guided in the trap of linear thinking by using the example-codes provided by the arduino-IDE that use delay().

As long as you try to stay inside linear thinking it will be impossible to think about how to solve this task.

For solving this task of only using void loop() for everything you have to get rid of

  1. the linear thinking that delay() is
  2. learning about conditional code-execution based on the switch-case-break-statement (state-machine)
  3. learning to think circular which is the complete opposite of linear

Using void loop() as the only loop

But this will be not enough
for the timing you will need non-blocking timing
Example-code for timing based on millis() easier to understand through the use of example-numbers / avoiding delay()

If you don't want to get lost in a big mess of many many if-conditions
you will have to learn how state-machines work

best regards Stefan

Politely, I have studied. But studying does not mean that I won't get stuck or still be at a loss. And yes it is school work but I simply need guidance. I am not looking for someone to write the code for me.

the link I gave you include code samples

otherwise what kind of guidance do you need ?

your code basically uses the "Producer Consumer design Pattern"


where one "process" produces data and store it somewhere and another process consumes the data asynchronously.

you could read about that to get an idea about how this is being dealt with.


In your case you first you have a human typing text into the Serial monitor, the bytes are sent over the Serial line and arrive in the Serial buffer of your arduino where Serial.read() can be used to retrieve one element.

Say the Human sent HELLO
Your producer process needs to remove the bytes as they come in and store them into a designated buffer

Then you have another process looking at the buffer and picking up the next byte and blinking the LED. This is the consumer


So your arduino program should basically do that

âžś two tasks

task1 : if a byte is available on the Serial line, remove it and store it in a FIFO buffer
task 2: if a byte is available in the FIFO buffer, remove it and blink the LED appropriately


The tutorials I mentioned:

  • Serial Input Basics shows how to listen to the Serial port without blocking. This is your Producer task

  • the three others tutorials show how to use millis to blink a LED without blocking. this is for your consumer task.


Side note: the Serial line of your arduino already offers the FIFO buffer but it's limited to 64 bytes. If you don't intend to go beyond dealing with 64 bytes at a given moment (given that the blinking can take longer than receiving chars) then you don't need to code the Producer and you can use the Serial class to read from the buffer.


Does this help ???

1 Like

If you post your attempt how you tried to write the code. You can be guided based on your code which will be much more effective than a generalised explanation

best regards Stefan

These guides, expressed in video form:

Using millis()

Several things at the same time

YES! Thank you!

will certainly do the job in a producer consumer configuration.

Since the incoming characters are already being buffered, why not just consume the bytes off that directly?

the task : if a byte is available on the Serial line, remove it and blink the LED appropriately

a7

That is presumably the hard part.
There are several pieces:
translate the character into some number of dits and dahs.
Count which symbol you are on.
Keep track of whether you are sending a dit, a dah, or the gap in between them, using something like the "blink without delay" example.

Hi @lachi ,

Welcome to the forum..
Morse code, made a lib a while back..
Just checking the sketch I used in it's development..
Got 2 loops, that probably could be removed quite easily..
Maybe it helps..

AsyncMorse

good luck.. ~q

However, we are prohibited from using any loops except the provided loop() in arduino.

I don't think using delay( ) is a big issue in a Morse sender. The only thing in the code posted below which violates the prohibition is the while block when sending a character. As @westfw says, that will need to be turned into a routine which counts the dit and dahs and is called multiple times in loop until the character is completed.

void flashSequence (char* sequence)
{
  int i = 0;
  while  (sequence[i] != NULL)
  {
    flashDotOrDash(sequence[i]);
    i++;
  }
  delay(dotDelay * 3);     //gap between letters, international standard
}
//Sketch 5_05Test   Morse Interpreter including punctuation

int ledPin = 13;
int dotDelay = 200; //set the delay to a quarter second

char ch;
byte newch;

char* letters[] =
{
  ".-", "-...", "-.-.", "..", ".",                          //A-Z
  "..-.", "--.", "....", "..",
  ".---", "-.-", ".-..", "--", "-.",
  "---", ".--.", "--.-", ".-.",
  "...", "-", "..-", "...-", ".--",
  "-..-", "-.--", "--.."
};

char* numbers[] =
{
  "-----", ".----", "..---", "...--", "....-",  //numbers 0-9
  ".....", "-....", "--...", "---..", "----."
};

char* punct[] =      // punctuation marks in order of frequency
{
  ".-.-.-", "--..--", ".----.",  "..--..",       //  .  ,   '   ?
  "-.--.", "-.--.-", "-.-.--", "-.-.-.",        //  (  )   !   ;
  "---...", ".-..-.", ".--.-.", "-....-",        //  :  "  @  -
  "..--.-", ".-.-.", "...-..-", "-...-",         //  _  +  $  =
  ".-..."                                       //  &
};

void setup()
{
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  Serial.println("To send text to be displayed in Morse Code, type words above and press Send");
}

void loop()
{
  if (Serial.available() > 0)
  {
    ch = Serial.read();                                        //read a single letter

    if (ch >= 'a' && ch <= 'z')                              // is it lower case letter?
    {
      flashSequence(letters [ch - 'a']);
    }
    else if (ch >= 'A' && ch <= 'Z')                           // is it a capital letter?
    {
      flashSequence(letters [ch - 'A']);
    }
    else if (ch >= '0' && ch <= '9')                          // is it a number?
    {
      flashSequence (numbers[ch - '0']);
    }
    else if (ch >= 33  &&  ch <=  95)                     // is it punctuation?   
    {

      punctuationTranspose();
      flashSequence (punct[newch]);

    }
    else if (ch == ' ')                                      // is it a blank space?
    {
      delay(dotDelay * 7);                           //gap between words
    }
    {
      Serial.print(ch);
    }
  }
}

void flashSequence (char* sequence)

{
  int i = 0;
  while  (sequence[i] != NULL)
  {
    flashDotOrDash(sequence[i]);
    i++;
  }
  delay(dotDelay * 3);     //gap between letters, international standard
}

void flashDotOrDash (char dotOrDash)
{
  digitalWrite(ledPin, HIGH);
  if (dotOrDash == '.')
  {
    delay (dotDelay);
  }
  else                                          // must be a -
  {
    delay (dotDelay * 3);     //long dah 3x dit international standard
  }
  digitalWrite(ledPin, LOW);
  delay(dotDelay);               //gap between flashes, international standard
}

void  punctuationTranspose()
{
  switch (ch)
  {
    case '.':
      newch = 0;
      break;

    case ',':
      newch = 1;
      break;

    case 39:
      newch = 2;
      break;

    case '?':
      newch = 3;
      break;

    case '(':
      newch = 4;
      break;

    case ')':
      newch = 5;
      break;

    case '!':
      newch = 6;
      break;

    case ';':
      newch = 7;
      break;

    case ':':
      newch = 8;
      break;

    case '"':
      newch = 9;
      break;

    case '@':
      newch = 10;
      break;

    case '-':
      newch = 11;
      break;

    case '_':
      newch = 12;
      break;

    case '+':
      newch = 13;
      break;

    case '$':
      newch = 14;
      break;

    case '=':
      newch = 15;
      break;

    case '&':
      newch = 16;
      break;
  }
} 
1 Like

That’s what I explained here

It depends on the incoming flow versus buffer size and time to consume. At 115200 bauds you fill up the 64 bytes in less than 6ms. The average time for the sending one Morse code for one char is about 50ms much longer (10x to 100x) so if you plan to receive messages more than 64 bytes long messages then you need to either modify the Serial buffer size or provide your own container / FIFO queue.

1 Like

Did you miss a digit? Ham license speed is 5 words/min, with “paris” the standard word (a nice even 50 symbols.) That’s pretty close to 500ms per char.
10x that speed puts you in world record neighborhoods.

you are right, at a speed of 5 words per minute (beginner level like me at my best :slight_smile: ), a dot is approximately 60 milliseconds, and a dash (-) is three times that so around 180 milliseconds...

My late uncle who was using morse professionally was above 30 WPM - it was impressive to see.

So even more important to thing about the need of buffering outside the Serial buffer or not


Yes you had, sry. I read uncarefully or not at all, stopping when I saw too many buffers!

As we see Morse code is slow, it is

I might have done anyway without any analysis or thought. I am often finding that I am working in other circumstances with no nice serial buffer at all beyond the UART hardware or peripheral capability close to zero use it or lose it buffering. So I don't remember the build in buffer of 64 bytes.

Nice charts, BTW. Just now on my screen they lined up and it looked like your pizza avatar was about to go into the consumption side buffer. Mmm pizza.

a7

ready for the oven :wink:

2 Likes

Infinite sized buffers won't help in the general case. "Thinking" means deciding on whether you want to try to deal with messages greater than the size of the serial buffer (64 bytes.)

It’s either « you want to try » or you « need to». It comes down to the spec / requirements of what max size is acceptable.

That will influence also the choice of arduino (go for one with way more Memory for example if you need a megabyte buffer)

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.