Go Down

Topic: Confused with output (Read 246 times) previous topic - next topic

Strahan

Aug 28, 2016, 05:12 am Last Edit: Aug 28, 2016, 08:36 am by Strahan
Hi.  I'm a beginner with Arduino stuff.  I was thinking up things I could do with it so I decided to make it accept text sent over the serial port and convert it to morse and flash the LED appropriately.  I have the morse part down so I decided to get fancy and allow reconfiguring the program over serial.  I figured I'd do "cfg-dit" to set dit length, "cfg-led" to set the pin for the LED and "cfg-pzo" to set the pin for the piezo buzzer.

I wrote the serial reader and started with the cfg-dit one.  Tested it, worked perfectly.  I then copied the code and pasted it and changed dit to led and changed the variable it updated.  I assumed that'd work but it broke it.

This is the code that works:
Code: [Select]

void loop() {
  if (Serial.available()) {
    char inputStr = Serial.read();
    if (String(inputStr) == "\n") {
      buffer.toLowerCase(); boolean skipMorse = false;
      if (buffer.substring(0,7) == "cfg-dit") {
        skipMorse = true;
        if (buffer.length() == 7) {
          Serial.println("Dit duration is currently: " + String(ditlength));
        } else {
          if (buffer.length() >= 9) {
            ditlength = buffer.substring(8, buffer.length()).toInt();
            Serial.println("Set dit duration to " + String(ditlength));
          } else {
            Serial.println("Invalid usage.");
          }
        }
      }
      if (!skipMorse) Morse(buffer);
      buffer = "";
    } else {
      buffer += inputStr;
    }
  }
}


ditlength is an int.  Using that code, I open a terminal emulator and send "cfg-dit" and I see this:

cfg-dit
Dit duration is currently: 93

Cool.  So this is what I had post adding led:

Code: [Select]

void loop() {
  if (Serial.available()) {
    char inputStr = Serial.read();
    if (String(inputStr) == "\n") {
      buffer.toLowerCase(); boolean skipMorse = false;
      if (buffer.substring(0,7) == "cfg-dit") {
        skipMorse = true;
        if (buffer.length() == 7) {
          Serial.println("Dit duration is currently: " + String(ditlength));
        } else {
          if (buffer.length() >= 9) {
            ditlength = buffer.substring(8, buffer.length()).toInt();
            Serial.println("Set dit duration to " + String(ditlength));
          } else {
            Serial.println("Invalid usage.");
          }
        }
      }
      if (buffer.substring(0,7) == "cfg-led") {
        skipMorse = true;
        if (buffer.length() == 7) {
          Serial.println("LED pin is currently: " + String(pinLED));
        } else {
          if (buffer.length() >= 9) {
            pinLED = buffer.substring(8, buffer.length()).toInt();
            Serial.println("Set LED pin to " + String(pinLED));
          } else {
            Serial.println("Invalid usage.");
          }
        }
      }
      if (!skipMorse) Morse(buffer);
      buffer = "";
    } else {
      buffer += inputStr;
    }
  }
}


Now when I send cfg-dit, I get nothing.  Just to see if maybe it worked for led now instead, I did cfg-led and still got nothing but it appeared like this:

cfg-dit

cfg-led

So it looks like it did send a response, it was just blank.  In trying to troubleshoot this I narrowed it down to the line in the LED section where it returns current pinLED (an int as well) value.  I thought maybe the casting broke something so I changed it to Serial.println("wtf").  When I ran it again, it was still broken but not quite the same:

cfg-dit
93

It gave the correct value of ditlength, but it didn't send the "Dit duration" text.  I'm really puzzled as to why a change in that block of code is affecting a prior block?  I assume I did some newbie mistake, lol, but I'm at a loss as to what that would be.  Thanks!

econjack

#1
Aug 28, 2016, 05:51 am Last Edit: Aug 28, 2016, 05:53 am by econjack
In Morse code, all timings are referenced off a dit length, which depends upon the words per minute (wpm) you're trying to send. The standard word is PARIS and the math works out to

ditLength = 1200 / wpm;

So, at 5 wpm, you'd be able to send the word PARIS 5 times, which is really slow. (Continents drift faster than that.) Based on that, you get:

Code: [Select]

#define DITLENGTH          (1200/wpm)
#define ELEMENTSPACE       (DITLENGTH)
#define LETTERSPACE        (DITLENGTH * 3)
#define WORDSPACE          (DITLENGTH * 7)


Now, if you change the wpm speed, all of the related spacing changes with it. Note that this is for "standard" Morse code. Farnsoworth encoding takes a little more calculating. You could also use these definitions using the const keyword instead to define variables.

OldSteve

#2
Aug 28, 2016, 05:58 am Last Edit: Aug 28, 2016, 05:59 am by OldSteve
This caught my attention:-
Code: [Select]
if (String(inputStr) == "\n")
'inputStr' is a single char, so why not:-
Code: [Select]
if(inputStr == '\n')

Everything that you're doing can be done better/smaller/faster without using the "String" class, using standard C/C++ string functions.
Please do not PM me for help. I am not a personal consultant.
And others will benefit as well if you post your question publicly on the forums.

Strahan

In Morse code, all timings are referenced off a dit length, which depends upon the words per minute (wpm) you're trying to send.
Thanks for the info.  That makes it a lot easier, I changed it to a single int then multiplied as you shown.  I'd rather use an int so speed can be easily reconfigured.  I should've figured there'd be standards, but when I wrote it I just pulled delay amounts out of the air lol.


Everything that you're doing can be done better/smaller/faster without using the "String" class, using standard C/C++ string functions.
So conventions in C/C++ all port over to Arduino sketches?  That's awesome, because that means I can get books on C and read up.  There are a lot more of them than Arduino books.  My experience with coding has been mostly in PHP, which is very type relaxed.  Most of my hair pulling headaches learning Arduino have been trying to understand the right way to handle data.  For instance, I still can't figure out how to (if it's even possible) do something like a text indexed array.  I wanted to have the morse alphabet stored like morse["f"] = "..-." but I couldn't figure that out.  If you think the code I shown is a mess, I'd hate for you to see the method I came up with lol.

OldSteve

#4
Aug 28, 2016, 08:05 am Last Edit: Aug 28, 2016, 08:15 am by OldSteve Reason: Added more info.
So conventions in C/C++ all port over to Arduino sketches?
The (so-called) Arduino language is just C++, which is backwards-compatible with C, so you can use all of the standard C/C++ conventions.

Quote
That's awesome, because that means I can get books on C and read up.  There are a lot more of them than Arduino books.
Yep, but concentrate on C++, because it supports many newer features not seen in C.
There are also a plethora of C++ websites that can help enormously, like cplusplus.com

Quote
My experience with coding has been mostly in PHP, which is very type relaxed.  Most of my hair pulling headaches learning Arduino have been trying to understand the right way to handle data.  For instance, I still can't figure out how to (if it's even possible) do something like a text indexed array.  I wanted to have the morse alphabet stored like morse["f"] = "..-." but I couldn't figure that out.  If you think the code I shown is a mess, I'd hate for you to see the method I came up with lol.
You can use normal C/C++ arrays etc with Arduino.

You can actually write in pure C/C++, using no 'Arduino' functions whatsoever, as you would do in, for example, 'Atmel Studio', and it will compile and run without problems.

Although there's usually no good reason to do so, you can even drop the 'setup()'/'loop()' framework, and simply write a normal 'main()' function, using direct register/port access and it will work fine.
ie Blink (For an UNO/ATMega328P):-
(Change "PB5" to "PB7" for a Mega2560.)
Code: [Select]
int main()
{
   DDRB |= (1 << PB5);          // Set Arduino pin 13 as output.
   while(true)
   {
       PORTB |= (1 << PB5);     // Set Arduino pin 13 high.
       _delay_ms(500);
       PORTB &= ~(1 << PB5);    // Set Arduino pin 13 low.
       _delay_ms(500);
   }
}


Edit: You'll find a ton of extra info here, too:- avr-libc

Please do not PM me for help. I am not a personal consultant.
And others will benefit as well if you post your question publicly on the forums.

Strahan

#5
Aug 28, 2016, 08:39 am Last Edit: Aug 28, 2016, 08:45 am by Strahan
Pretty interesting, thanks again!

I updated my code (and my original post above to reflect that) and noticed something new.  Now with the second if block the first one doesn't just send a blank reply it sends the ditlength int value... but not the preceding text.  Ehh??  I know you said I'm not using efficient data types, but would that account for that behavior?  I've no idea why a change in one if block is affecting a prior one.

OldSteve

Pretty interesting, thanks again!

I updated my code (and my original post above to reflect that) and noticed something new.  Now with the second if block the first one doesn't just send a blank reply it sends the ditlength int value... but not the preceding text.  Ehh??  I know you said I'm not using efficient data types, but would that account for that behavior?  I've no idea why a change in one if block is affecting a prior one.
If you want any real help, you need to post all of your code, not just part of it.
It's pretty hard to copy just the 'loop()' function into an IDE and have it compile/run for testing.

Also, once you've received replies, you should never go back and edit your opening post. It makes things very confusing, and no one knows what was originally posted and already addressed. If you need to add anything, do it in a later reply.
Please do not PM me for help. I am not a personal consultant.
And others will benefit as well if you post your question publicly on the forums.

Robin2

@Strahan, From a quick look at the code in the Original Post it seems to me you are trying to cram too much into the loop() function. If you use several small functions it will make the code easier to develop, maintain and debug. Have a look at Planning and Implementing a Program

Also have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Strahan

Thanks, I'll remember that.  Thanks too for the links, I'll check it out.  My sister is an engineer who works on embedded software for satellites, she looked at it and got me straightened out so I'm good to go.  Now off to read all this stuff you guys linked me to :)

Thanks!

Robin2

My sister is an engineer who works on embedded software for satellites,
So we can't any more say "It's not rocket science"  :(

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Jiggy-Ninja

So conventions in C/C++ all port over to Arduino sketches?  That's awesome, because that means I can get books on C and read up.  There are a lot more of them than Arduino books.  My experience with coding has been mostly in PHP, which is very type relaxed.  Most of my hair pulling headaches learning Arduino have been trying to understand the right way to handle data.  For instance, I still can't figure out how to (if it's even possible) do something like a text indexed array.  I wanted to have the morse alphabet stored like morse["f"] = "..-." but I couldn't figure that out.  If you think the code I shown is a mess, I'd hate for you to see the method I came up with lol.
Arduino is built on the back of avr-gcc, with the C++ standard set to C++11. Basically all the C++ features are available except most of the STL.

With the STL, you could easily have a text indexed array with the std::map template. While there is an AVR STL port available that has std::map, it's apparently a memory hog due to the binary tree structure used to organize it, so you'd best avoid it.

Strahan

So we can't any more say "It's not rocket science"  :(

...R
Hehe, actually you can.  She was writing code for cubesats.  They navigate with some kind of weird inertial thing, it has no actual rocket booster on it :)


Arduino is built on the back of avr-gcc, with the C++ standard set to C++11. Basically all the C++ features are available except most of the STL.

With the STL, you could easily have a text indexed array with the std::map template. While there is an AVR STL port available that has std::map, it's apparently a memory hog due to the binary tree structure used to organize it, so you'd best avoid it.
Thanks.  I really need to get reading, because I don't even know what you mean by STL lol.  I should know better than to jump into a project blindly but I was too eager.  I'm gonna go school myself on C now ;)

Jiggy-Ninja

#12
Aug 31, 2016, 08:16 pm Last Edit: Aug 31, 2016, 08:18 pm by Jiggy-Ninja
Thanks.  I really need to get reading, because I don't even know what you mean by STL lol.  I should know better than to jump into a project blindly but I was too eager.  I'm gonna go school myself on C now ;)
STL = Standard Template Library. There's a lot of predefined container classes, stream classes, and algorithm templates defined in it that make C++ life much easier. Unfortunately, many of them are not appropriate for microcontroller use due to being memory hogs, whether RAM or Flash. Their flexibility has a price.

School yourself on C++, not C.

You don't need that though. You can easily make a wrapper struct around an array and use member functions and operator overloading to get some pretty sophisticated behavior. Here's a sample that takes a takes an ascii index and normalizes it to 0-35 to look up in the array:
Code: [Select]
struct ASCIIArray
{
  typedef int value_type;

  value_type& operator[](char idx)
  {
    if( isDigit(idx) ) idx -= '0';
    else if( isLowerCase(idx) ) idx -= 'a' += 10;
    else if( isUpperCase(idx) ) idx -= 'A' += 10;
    else ; // do something here for when it's not an alphanum.

    return _arr[idx];
  }
private:
  value_type _arr[36];
};

// Initialization
ASCIIArray morse_code = {{ 1, 2, 3, 4, etc... }}

// Sample Usage
Serial.println( morse_code['1'] );

The double curly braces to initialize it is not a typo. There's a lot that can be done to extend this (begin and end iterators for example), but it's a start.

PaulMurrayCbr

The difficulty is that memory on an Arduino can be really tight, so we tend to avoid the C++ library classes that use unknown amounts of dynamically-allocated heap (String, in particular). Generally, you are not doing anyhting big and complicated enough to really need maps and collection classes when you are coding up an arduino.
http://paulmurraycbr.github.io/ArduinoTheOOWay.html

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy