Jump to content

Arduinos, signal transmission and Morse codes


Delay

Recommended Posts

you want to learn how to do things on the arduino, get the datasheet for the microcontroller. its a tresure trove of useful information, and tells you how to use features arduino never tells you about. 

and as much as they like to tell you there is an 'arduino language', its all c++. while most sketches use functional programming, you find that libraries tend to just be c++ classes though sometimes you find libraries done the c way. if you want to use classes you usually have to put them in a separate file, which is kind of confusing, especially when its just a small class used in a not very complex sketch. when you write libraries you pretty much use the headers that come with winavr. in fact you can get win avr and ditch the arduino toolchain all together. 

arduino libraries do come in handy if you need to make something work in a short period of time. like on halloween i had 12 hours to blink some leds and add sound effects, and i managed to get it working about 15 minutes before trick or treat started. i could have made a more robust design but i only needed it for one day. think next year il just get some led strips.

 

also if you want to transmit data, cheap rf modules are available. like the $3 esp8266 wifi module. the board is sufficiently powerful that you can usually ditch the arduino and just use it directly as your mcu board. the esp32 that followed it up was even more powerful and has bluetooth as well. doing ir usually requires using a timer to generate your carrier wave which is anded with your data. then have another timer drive an isr to shift out data. its easier to read ir data as you just need to do a pin change interrupt to detect the carrier and count out the pulses for timing. this is where reading data sheets comes in handy.

Edited by Nuke
Link to comment
Share on other sites

Here's a concept for decoding. I'm basically using a tree with each of the two branches representing either "short" or "long".

char Decode[] = "";

char CharacterTree[] = "etianmsurwdkgohvf-l-pjbxcyzq-- ";

int index = 0;

char MorseDecoder(signal){
   switch(signal){
   case 'dot':
      index = 2 * index + 2;
      break;
   case 'dash':
      index = 2 * index + 3;
      break;
   case 'space':				//Signal matches "space", character at that index is added and index is reset to 0
      Decode = Decode + CharacterTree[index];
      index = 0;
      break;
   case 'word_terminate':
      Decode = Decode + CharacterTree[30];	//Character 30 is a space
      index = 0;
      break;
   }
}



void loop(){
   //does arithmetic to figure out if it's a dot, a dash, space or a word termination
   MorseDecoder(transmitted)   //part of the arithmetic function above, "transmitted" being dot, dash,... for use in the switch
}

it's a quick thing I put together in 20 minutes. I use a tree because it's very easy to do arithmetic in it.

Edited by Delay
kinda important, but I realized a mistake in the tree
Link to comment
Share on other sites

anyway if you still have problems with garbled data, look up manchester coding. it will halve your throughput but will give you much cleaner data. you can also stick a checksup or crc at the end to confirm the data is good.

Link to comment
Share on other sites

@0111narwhalz

I had my head so wrapped in the morse part of it, I completely glossed over other encoding methods.  Then you referred to dits and dahs in your initial explanation, that I completely lost what you were saying.

 

2 hours ago, Delay said:

Here's a concept for decoding.

I can tell it has problems, but I haven't looked at it long enough yet.

On first glance, let's take 'E' as an example.  You receive a dot, the letter E in morse.  You enter the switch, and you reach index = 2 * index + 2;

index is 0, therefore index * 2 is also zero.  Add 2, and you get 2.  This points to the letter 'i' in your tree.

The same happens with the dash, index = 2 * index + 3;  Basic math says you'll never get indexes 0 or 1.  I think you might need to leave of the addition?

Link to comment
Share on other sites

5 hours ago, razark said:

I think you might need to leave of the addition?

I'd encounter a similar problem; index * 2 would always be 0 unless it's a dash.

The first signal has to be treated differently to the rest of the tree. After those are done it works as I expect it to. It's just these first two that don't.

Edit: I might have solved this already. I move the space used for word_terminate to index 0 and start with "E" at index 1 (still counting from 0). Then the sequences for dot/dash would be 2n+1/2n+2.

 

The problem was that I started the numbers not at the beginning of the tree, but at the first "short" branch. Now I start counting at the beginning of the tree as index 0 (not index -1) with " ".

Edited by Delay
Link to comment
Share on other sites

I was just about to suggest a dictionary like data structure for looking up codes against characters but it might be a better idea to dive into a good c book to avoid frustration :-)

 

Things are worse. C distinguishes between declarations and definitions and these concepts must be clear.

A declaration for a function goes like

returndatatype functionname( argumentlist )

where argumentlist is composed of datatypes and variable names, but can be omitted.

The definition includes the body of the function.

This concept is extremely important when it comes to more complex programs (header files, forward declarations, etc.)

The same holds for variables, though "normally" a variable declaration comes along together with the definition, like int number = 0, if there are no important reasons to split declaration and definition.

--------

So, you would have to say in your example: void Function( char argument ) { ... } in your case if your function has no return value. If your function returns something you must write the datatype of the return value instead of void.

Edited by Green Baron
Link to comment
Share on other sites

13 hours ago, Green Baron said:

but it might be a better idea to dive into a good c book to avoid frustration

I have a book on C++... So close!

13 hours ago, Green Baron said:

o, you would have to say in your example: void Function( char argument ) { ... }

I was going for a function call. Just realized that you don't need { and } then.
If a function requires an argument to work, the name for its argument(s) can still be arbitrarily assigned. For the function declaration I could use "function_argument", but call it with "output" to be used as "function_argument".

 

Anyways, there's something that I really don't understand, not even my teacher could figure out what was wrong in the limited amount of time left.

char Text[] = "";

char CharacterTree[] = " etianmsurwdkgohuf-l-pjbxcyzq--";
int index = 0;
int dotTime = 0;			//(plan here is to make the transmission rate completely up to the transmitter)
int Input = A0;				//photosensor stuff
int sensorWert = 0;			//above

char Tree(char input){
  switch(input){
    case 'dot':
      index = 2 * index + 1;
      break;
    case 'dash':
      index = 2 * index + 2;
      break;
    case 'space':
      Text = Text + CharacterTree[index];		//this line works just fine
      index = 0;
      break;
    case 'long_space':
      Text = Text + CharacterTree[index];		//this line also works
      index = 0;
      Text = Text + CharacterTree[index];		//Problematic line
      break;
  }
}

void setup() {
  Serial.begin(9600);			//just some setup according to a website with Arduino coding examples (most importantly a photosensor)
}

void loop() {
  sensorWert = analogRead(Input);	//refer to above. setup and loop are so far only testing the sensor and shouldn't be relevant here.
  Serial.println(sensorWert);
}

The marked line is supposed to add a character to the string "Text".
For this particular line, "index" is equal to 0, which would be space.

However, instead of doing that it throws an error back at me. I can't remember its content, but looking it up it probably was "invalid conversion from 'const char*' to 'char' " or something similar.

What I don't get is that this is the only line to cause this problem. Especially since there are two very similar lines above this one, and it reads these just fine. The only difference between them is this is the only line to refer to CharacterTree[0], but that should be a valid index. Or is " " different? What's wrong here?

Indices start at 0, right?

Edited by Delay
Link to comment
Share on other sites

I am sorry, but you do not need an argument for a c function, but you do need a return type or void, that's what i wrote above. And C++ and C are very different.

The problem in the marked line is that C cannot add strings (arrays before all) with the + operator and assign a string (a char array) with an = assignment. This should not even compile (*), or are you using C syntax and a C++ compiler ? Do not do that. It is a miracle to me that your teacher did not see that in a second ...

(*)Another problem is that that you use char-syntax('') to define a string, that is a syntax error as well. In a switch statement you can only use an expression that evaluates to a simple datatype, if i am not lying. No arrays are allowed. That must be done with an array comparison, e.g. by strstr(). and your function must return a char as it is declared in the header.

 

Solution:

To concatenate and assign strings in C, include string.h and use the strcat() or strncat() (or strcat_s() or strncat_s()) function. If you're on a Linux OS you can get a full explanation by typing "man 3 strcat" in a terminal window. To assign strings you can use strcpy() or strncpy().

 

Edited by Green Baron
Link to comment
Share on other sites

Thanks, but I don't get why the compiler only flags an error for the last one. The correlation with index = 0 might've been a little far-fetched (I was just going off some assumptions and the differences in the lines), but why does it "wait" until the last occasion to tell me that there are some fundamental things wrong?

 

As for my teacher... Not sure if this begs the questions of how he even managed to get into teaching CS, I started questioning that since the moment he simply threw us into C without a warning.


We were doing some basic theory before that... how computers store things, ASCII, two's complement.
Suddenly: Arduino.

Link to comment
Share on other sites

Oh it is ok to learn C from the start imo ! C is so beautifully straight forward ! And your problem perfectly fits into a basic course, maybe towards the middle.

It is just, you need a good book. Are you German, as i understand from one of the variable names ? :-)

Grab Jürgen Wolf: C von A bis Z, newest edition on C11. There is no better basic course, not even in English !

 

Link to comment
Share on other sites

1 minute ago, Green Baron said:

Are you German, as i understand from one of the variable names ? :-)

Yes, though for some reason I like to give things english names.

2 minutes ago, Green Baron said:

Grab Jürgen Wolf: C von A bis Z, newest edition on C11.

Thanks, I'll take a look at it.

Link to comment
Share on other sites

another thing about strings on mcu is they love to eat your memory, things to think about when you only have 2k. avrs provide ways to stick strings in flash or even the eeprom. ive written robust cli interfaces for things just to have them eat all the memory because i put all my strings in char arrays. 

Link to comment
Share on other sites

Another thing that met my eye: if you work with arrays, you must also do the memory dance :-)

Before you copy characters into the variable "Text" you must provide enough space in there via malloc(), and when you're done with it, you must free() it again. Be aware that you know about the stack and the heap and the scope of variables before doing so inside functions etc.

 

Edited by Green Baron
Link to comment
Share on other sites

lol :-)

As a hobbyist i am faster with c than python, at least with problems like these. It is only the first steps that you are missing and that make you frustrated now:

Expressions, control flow, variable scope, the call stack, the heap, pointers and memory allocation. Do not give up !

You can omit the memory stuff for your problem if you simply declare your char arrays long enough. This isn't production quality but at least lets you be successful until you're through with the chapter on the heap and what to do with it :-)

C is punkrock !

Link to comment
Share on other sites

2 hours ago, Green Baron said:

and when you're done with it, you must free()

Wait, so you can't actually overwrite a string with nothing? Since you can "=" it to something?

(Not that that'd help, I just want an option to reset the string here)

Edited by Delay
Link to comment
Share on other sites

6 minutes ago, Delay said:

Wait, so you can't actually overwrite a string if nothing? Since you can "=" it to something?

You can use = here (as in, it'll compile and probably act like it does what you want), but you shouldn't. Since C strings are character arrays, and since C arrays are fancy pointers (the type of a string is char *), the = operator for strings doesn't overwrite the left-hand string with the right-hand one. Instead, it assigns the right-hand string's pointer to the left-hand string. The region allocated for the left-hand string still exists, but you've now forgotten where it is (because your pointer to it has been overwritten), and you can't free it up - which means the effective amount of memory you have to work with is smaller by the size of that string (plus some heap metadata). This is called a memory leak, and they are to be avoided.

Edited by IncongruousGoat
Link to comment
Share on other sites

@IncongruousGoat This makes me question my script for sending the Morse code. I'm now slightly worried that I did this somewhere or similar beginner's mistakes before.

Should I post the complete script?
Don't see this as "correcting someone's work because they're too dumb" or something. See it as an opportunity for me to learn from my mistakes by drawing attention to them.

Though your head will probably explode in the process of making the list. Or you run out of papers. Or hard-drive space. Whatever comes first.

Edited by Delay
Link to comment
Share on other sites

6 minutes ago, Delay said:

@IncongruousGoat This makes me question my script for sending the Morse code. I'm now slightly worried that I did this somewhere.

Should I post the complete script?

Probably, yes. I'll take a look at it when I have a minute and let you know if I see anything.

EDIT:

6 minutes ago, Delay said:

Don't see this as "correcting someone's work because they're too dumb" or something. See it as an opportunity for me to learn from my mistakes by drawing attention to them.

That was exactly the idea. Just saying "That's wrong, don't do it" doesn't do anyone any good, especially in a language like C.

Edited by IncongruousGoat
Link to comment
Share on other sites

Here it is:

#include <string.h>

int LED = 10;
char Text[] = "Hello World!";
int dotTime = 250; //in ms

/* Signal types: */
void send_start(){
  digitalWrite(LED, HIGH);
  delay(4 * dotTime);
  digitalWrite(LED, LOW);
  delay(4 * dotTime);
}

void send_dot(){
  digitalWrite(LED, HIGH);
  delay(dotTime);
  digitalWrite(LED, LOW);
  delay(dotTime);
}

void send_dash(){
  digitalWrite(LED, HIGH);
  delay(3 * dotTime);
  digitalWrite(LED, LOW);
  delay(dotTime);
}

void send_space(){
  delay(2 * dotTime); //1 unit + 2 units = 3 units
}

void send_wordspace(){
  delay(6 * dotTime); //1 unit + 6 units = 7 units
}

void send_end(){
  digitalWrite(LED, HIGH);
  delay(5 * dotTime);
  digitalWrite(LED, LOW);
  delay(5 * dotTime);
}
  

/* letter -> Morse code: */
char MorseCoder(char in_char){
  switch(in_char){
    case ' ':
      send_wordspace();
      break;
    case 'A':     //A: KL
    case 'a':
      send_dot();
      send_dash();
      send_space();
      break;
     case 'B':    //B: LKKK
     case 'b':
      send_dash();
      send_dot();
      send_dot();
      send_dot();
      send_space();
      break;
     case 'C':    //C: LKLK
     case 'c':
      send_dash();
      send_dot();
      send_dash();
      send_dot();
      send_space();
      break;
     case 'D':    //D: LKK
     case 'd':
      send_dash();
      send_dot();
      send_dot();
      send_space();
      break;
     case 'E':    //E: K
     case 'e':
      send_dot();
      send_space();
      break;
     case 'F':    //F: KKLK
     case 'f':
      send_dot();
      send_dot();
      send_dash();
      send_dot();
      send_space();
      break;
     case 'G':    //G: LLK
     case 'g':
      send_dash();
      send_dash();
      send_dot();
      send_space();
      break;
     case 'H':    //H: KKKK
     case 'h':
      send_dot();
      send_dot();
      send_dot();
      send_dot();
      send_space();
      break;
     case 'I':    //I: KK
     case 'i':
      send_dot();
      send_dot();
      send_space();
      break;
     case 'J':    //J: KLLL
     case 'j':
      send_dot();
      send_dash();
      send_dash();
      send_dash();
      send_space();
      break;
     case 'K':    //K: LKL
     case 'k':
      send_dash();
      send_dot();
      send_dash();
      send_space();
      break;
     case 'L':    //L: KLKK
     case 'l':
      send_dot();
      send_dash();
      send_dot();
      send_dot();
      send_space();
      break;
     case 'M':    //M: LL
     case 'm':
      send_dash();
      send_dash();
      send_space();
      break;
     case 'N':    //N: LK
     case 'n':
      send_dash();
      send_dot();
      send_space();
      break;
     case 'O':    //O: LLL
     case 'o':
      send_dash();
      send_dash();
      send_dash();
      send_space();
      break;
     case 'P':    //P: KLLK
     case 'p':
      send_dot();
      send_dash();
      send_dash();
      send_dot();
      send_space();
      break;
     case 'Q':    //Q: LLKL
     case 'q':
      send_dash();
      send_dash();
      send_dot();
      send_dash();
      send_space();
      break;
     case 'R':    //R: KLK
     case 'r':
      send_dot();
      send_dash();
      send_dot();
      send_space();
      break;
     case 'S':    //S: KKK
     case 's':
      send_dot();
      send_dot();
      send_dot();
      send_space();
      break;
     case 'T':    //T: L
     case 't':
      send_dash();
      send_space();
      break;
     case 'U':    //U: KKL
     case 'u':
      send_dot();
      send_dot();
      send_dash();
      send_space();
      break;
     case 'V':    //V: KKKL
     case 'v':
      send_dot();
      send_dot();
      send_dot();
      send_dash();
      send_space();
      break;
     case 'W':    //W: KLL
     case 'w':
      send_dot();
      send_dash();
      send_dash();
      send_space();
      break;
     case 'X':    //X: LKKL
     case 'x':
      send_dash();
      send_dot();
      send_dot();
      send_dash();
      send_space();
      break;
     case 'Y':    //Y: LKLL
     case 'y':
      send_dash();
      send_dot();
      send_dash();
      send_dash();
      send_space();
      break;
     case 'Z':    //Z: LLKK
     case 'z':
      send_dash();
      send_dash();
      send_dot();
      send_dot();
      send_space();
      break;
     default:
      send_space();
  }
}

void setup() {
  pinMode(LED, OUTPUT);
}

void loop() {
  send_start();
  for (int i=0; i < strlen(Text); i++){
    MorseCoder(Text[i]);
  }
  send_end();
  delay(2000);
}

Pretty sure that "MorseCoder" could actually be void, since it doesn't return anything. It takes input, does somethings, execution goes back to the loop and repeats it. Nothing returned as far as I can see.

Link to comment
Share on other sites

20 minutes ago, Delay said:

Pretty sure that "MorseCoder" could actually be void, since it doesn't return anything. It takes input, does somethings, execution goes back to the loop and repeats it. Nothing returned as far as I can see.

C arrays are no pointers, but they decay into pointers when passed as arguments. A slight but important difference :-), namely that from inside a function you can change data outside instead of working on a copy on the stack.

Be that as it may, it looks good to me from afar, at least syntactically. I can't compile it because i have no arduino and lack the library. And you are correct, the compiler will complain that there is no return in a function that returns a value. Declare the function void or return a char.

I understand that the main function is somewhere else.

Edited by Green Baron
Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...