error: 'setChar' was not declared in this scope

Hy,

I am trying to write a program, that reads a short text from the serial connection, and sends it out as a morse code.
I wanted to test it out with the few characters I've added, but I get a compiler error: "Serial_to_morse:39: error: 'setChar' was not declared in this scope"

Here is the code:

/* This program reads a text up to 63 charakters through the Serial connection,
 puts it into an array of bytes
 and sends out the morse code. */

byte spk = 11;  //speaker pin

byte text[63];  //63 is max, because Serial.available() can't be bigger, Arduino can't buffer more than that.
boolean newText = false;
byte part[9];  //the parts of the morse code

byte wpm = 10; //words per minute, set speed
int Hz = 800; //morse code frequency (in herz)

void setup() {
  pinMode(spk, OUTPUT);
  Serial.begin(9600);
  Serial.println("Power On");
}

void loop()
{
  if(Serial.available()){  //read the text from serial
    delay(5);  //let arduino buffer some letters
    for(int i=0; i<63; i++){
      text[i] = Serial.read();
      delay(5);  //needed for stability
    }
    for(int i=0; i<63; i++){  //if there are no setChars to read, Serial.read reads 255
      if(text[i] == 255) text[i] = 0;
    }
    newText = true;
  }


  if(newText){
    for(int i=0; i<63; i++){
      
      switch(text[i]){  //convert ASCII numbers to morse code
      case 32:  //space 
        setChar(4);
        break;
      case 33:  //!
        setChar(1,0,1,0,1,1);
        break;
      case 34: //"
        setChar(0,1,0,0,1,0);
        break;
      case 36:  //$
        setChar(0,0,0,1,0,0,1);
        break;
      case 38:  //&
        setChar(0,1,0,0,0);
        break;
      case 39:  //'
        setChar(0,1,1,1,1,0);
        break;
      case 40:  //(
        setChar(1,0,1,1,0);
        break;
      case 41:  //)
        setChar(1,0,1,1,0,1);
        break;
      case 43:  //+
        setChar(0,1,0,1,0);
        break;

//other charakters including letters and numbers to be added


      default:  //do nothing
        break;
      }
      charakter();  //output morse code
      text[i] = 0; //reset text
    }
  }
}

//couldn't find any other solutions to put the parts of the morse code in an array, default is 9
void setChar(byte p0=9, byte p1=9, byte p2=9, byte p3=9, byte p4=9, byte p5=9, byte p6=9, byte p7=9, byte p8=9){
  part[0] = p0;
  part[1] = p1;
  part[2] = p2;
  part[3] = p3;
  part[4] = p4;
  part[5] = p5;
  part[6] = p6;
  part[7] = p7;
  part[8] = p8;
}

void charakter(){
  for(byte i=0; i<9; i++){
    if(part[i] == 9) break;
    morse(part[i]);
  }
}

void morse(byte element){
  if(element == 0){  //dot
    tone(spk, Hz, 1000 / wpm);
    delay(1000 / wpm);
  }
  else if(element == 1){  //dash
    tone(spk, Hz, 3000 / wpm);
    delay(3000 / wpm);
  }
  else if(element == 2){  //inter-element gap
    delay(1000 / wpm);
  }
  else if(element == 3){  //short gap (between letters)
    delay(3000 / wpm);
  }
  else if(element == 4){  //medium gap (between words)
    delay(7000 / wpm);
  }
}

I appretiate any help.

You can't normally have functions with variable numbers of arguments. You must specify all the args. You might make the last one -1 to signal to SetChar() that you don't need to go any farther.

  if(Serial.available()){  //read the text from serial
    delay(5);  //let arduino buffer some letters
    for(int i=0; i<63; i++){
      text[i] = Serial.read();
      delay(5);  //needed for stability
    }

If there is one character available, read all 64 of them. Those delay()s are band-aids for not understanding how serial data is transmitted and received, and for the lack of the sender properly packaging the data.

Make the sender properly terminate the packet, and make the receiver receive whatever data exists, without any delay()s. Only act upon the data when the end of packet marker arrives.

KeithRB:
You can't normally have functions with variable numbers of arguments. You must specify all the args. You might make the last one -1 to signal to SetChar() that you don't need to go any farther.

Well, "Serial.write" and "tone" also have some optional arguments. I don't understand, why I couldn't use them?

PaulS:
If there is one character available, read all 64 of them. Those delay()s are band-aids for not understanding how serial data is transmitted and received, and for the lack of the sender properly packaging the data.

Make the sender properly terminate the packet, and make the receiver receive whatever data exists, without any delay()s. Only act upon the data when the end of packet marker arrives.

That isn't my problem...

That isn't my problem...

Yet.

PaulS:
Yet.

I've tested it out before and it works just fine. I couldn't get it to work properly in an another way...

/* This program reads a text up to 63 charakters through the Serial connection,
puts it into an array of bytes
and prints it back out to the computer. */

byte text[63];  //63 is max, because Serial.available() can't be bigger, Arduino can't buffer more than that.
boolean newText = false;

void setup() {
  Serial.begin(9600);
  Serial.println("Power On");
}

void loop()
{
  if(Serial.available()){
    delay(5);  //let arduino buffer some letters
    for(int i=0; i<63; i++){
      text[i] = Serial.read();
      delay(5);  //needed for stability
    }
    for(int i=0; i<63; i++){  //if there are no charakters to read, Serial.read reads 255
      if(text[i] == 255) text[i] = 0;
    }
    newText = true;
  }

  if(newText){
    for(int i=0; i<63; i++){
      Serial.write(text[i]);
      text[i] = 0;  //reset
    }
    Serial.println("");
    newText = false;
  }
}

I've tested it out before and it works just fine. I couldn't get it to work properly in an another way...

What other ways have you tried? Like, maybe, using a while(Serial.availale()) loop?

Why did you decide on 5 milliseconds as a big enough waste of time? Why not 50000?

Because those are classes, not functions. Classes can have multiple methods with varying arguments.

Because those are classes, not functions

?

PaulS:
What other ways have you tried? Like, maybe, using a while(Serial.availale()) loop?

Why did you decide on 5 milliseconds as a big enough waste of time? Why not 50000?

Yes, I have also tried while(Serial.availale()), but it mostly split my text and made only arrays with fragments of the text instead being together in one array.

Why did I decide 5 milliseconds? It's just testing. It still didn't work with 1, so I tried 5 and now it works. I might be able to reduce it, but it doesn't matters.

KeithRB:
Because those are classes, not functions. Classes can have multiple methods with varying arguments.

Can I also make a class (whatever it is)?

You can have a function have a fixed number of parameters, with unspecified ones being defaulted.
This probably won't work for you in this application.
You can Google va_args which probably will do what you want.

Neither approach has anything to do with classes.

Well, "Serial.write" and "tone" also have some optional arguments. I don't understand, why I couldn't use them?

...

Because those are classes, not functions. Classes can have multiple methods with varying arguments.

In C++ any function can have optional arguments. Example:

int foo (int a, int b, int c = 0, bool d = false)
  {
  int result = a + b;
  if (d)
    result -= c;
  else
    result += c;
  return result; 
  }

void setup ()
  {
  foo (1, 2);
  foo (4, 5, 6);
  foo (8, 9, 42, true);  
  }  // end of setup
  
void loop () { }

Hasi321:
... I get a compiler error: "Serial_to_morse:39: error: 'setChar' was not declared in this scope"

It looks like the function prototype-generator used by the IDE didn't recognize that prototype with the default arguments. Move setChar before loop, and it compiles OK.

Your problem may be caused by the IDE declaring function prototypes for you. Try moving the setChar function definition up before it is called.

Edit: Nick, yet again, you typed more quickly!

Ach!

And I discovered it is a known issue, else I would have reported it:

http://code.google.com/p/arduino/issues/detail?id=386

(Been around for over 2 years so don't hold your breath).

Sorry to be late to the party, but I thought I'd throw in the Morse and Morse2 examples that ship with Bitlash as specimens worth study for those coding Morse generators, especially those coming up against the problems of state machines for the first time.

Both examples use a compressed table to store the morse code translations. The first example is blocking, and the second, Morse2, is fully non-blocking.

They are both in the Bitlash distribution, which you can get at http://bitlash.net. I've attached them here for reference or you can see them online at bitlash/examples/morse at master · billroy/bitlash · GitHub and bitlash/examples/morse2 at master · billroy/bitlash · GitHub

-br

morse.pde (7.62 KB)

morse2.pde (9.52 KB)

Thanks that really works!

It is ready and it works flawlessly! Thanks guys for your help!

PaulS: I have to apologize, you were right; it is better to use "while(Serial.available()){", and I could go down with the delay as low as 2 microseconds.

Here is the final code:

/* This program reads a text up to 100 characters through the Serial connection,
 puts it into an array of bytes
 and sends out the morse code. */

const byte spk = 10;  //speaker pin
const byte led = 13;  //led pin

byte text[100];  //array for charakters
boolean newText = false;
byte part[9];  //array for the morse code of a charakter

byte wpm = 13; //words per minute, set speed
int Hz = 800; //morse code frequency (in herz)

void setup() {
  pinMode(spk, OUTPUT);
  pinMode(led, OUTPUT);
  Serial.begin(9600);
  Serial.println("Power On");
}

//couldn't find any other solutions to put the parts of the morse code in an array, default is 9
void setChar(byte p0=9, byte p1=9, byte p2=9, byte p3=9, byte p4=9, byte p5=9, byte p6=9, byte p7=9, byte p8=9){
  part[0] = p0;
  part[1] = p1;
  part[2] = p2;
  part[3] = p3;
  part[4] = p4;
  part[5] = p5;
  part[6] = p6;
  part[7] = p7;
  part[8] = p8;
}

void loop()
{
  int numb = 0;
  while(Serial.available()){  //read the text from serial
    text[numb] = Serial.read();
    if(text[numb] == 255) text[numb] = 0; //if there are no characters to read, Serial.read reads 255
    numb++;
    delay(2);  //needed for stability
    newText = true;
  }
  

  if(newText){
    for(byte i=0; i<100; i++){
      // if there is a next character (excluding space) -> gap between letters
      if(text[i] > 32) morse(3);
      
      switch(text[i]){  //convert ASCII numbers to morse code

      case 32:  //space
        setChar(4);
        break;
      case 'A':
      case 'a':
        setChar(0,1);
        break;
      case 'B':
      case 'b':
        setChar(1,0,0,0);
        break;
      case 'C':
      case 'c':
        setChar(1,0,1,0);
        break;
      case 'D':
      case 'd':
        setChar(1,0,0);
        break;
      case 'E':
      case 'e':
        setChar(0);
        break;
      case 'F':
      case 'f':
        setChar(0,0,1,0);
        break;
      case 'G':
      case 'g':
        setChar(1,1,0);
        break;
      case 'H':
      case 'h':
        setChar(0,0,0,0);
        break;
      case 'I':
      case 'i':
        setChar(0);
        break;
      case 'J':
      case 'j':
        setChar(0,1,1,1);
        break;
      case 'K':
      case 'k':
        setChar(1,0,1);
        break;
      case 'L':
      case 'l':
        setChar(0,1,0,0);
        break;
      case 'M':
      case 'm':
        setChar(1,1);
        break;
      case 'N':
      case 'n':
        setChar(1);
        break;
      case 'O':
      case 'o':
        setChar(1,1,1);
        break;
      case 'P':
      case 'p':
        setChar(0,1,1,0);
        break;
      case 'Q':
      case 'q':
        setChar(1,1,0,1);
        break;
      case 'R':
      case 'r':
        setChar(0,1,0);
        break;
      case 'S':
      case 's':
        setChar(0,0,0);
        break;
      case 'T':
      case 't':
        setChar(1);
        break;
      case 'U':
      case 'u':
      case 'ú':
        setChar(0,0,1);
        break;
      case 'V':
      case 'v':
        setChar(0,0,0,1);
        break;
      case 'W':
      case 'w':
        setChar(0,1,1);
        break;
      case 'X':
      case 'x':
        setChar(1,0,0,1);
        break;
      case 'Y':
      case 'y':
        setChar(1,0,1,1);
        break;
      case 'Z':
      case 'z':
        setChar(1,1,0,0);
        break;
      case '0':
        setChar(1,1,1,1,1);
        break;
      case '1':
        setChar(0,1,1,1,1);
        break;
      case '2':
        setChar(0,0,1,1,1);
        break;
      case '3':
        setChar(0,0,0,1,1);
        break;
      case '4':
        setChar(0,0,0,0,1);
        break;
      case '5':
        setChar(0,0,0,0,0);
        break;
      case '6':
        setChar(1,0,0,0,0);
        break;
      case '7':
        setChar(1,1,0,0,0);
        break;
      case '8':
        setChar(1,1,1,0,0);
        break;
      case '9':
        setChar(1,1,1,1,0);
        break;
      case '.':
        setChar(0,1,0,1,0,1);
        break;
      case ',':
        setChar(1,1,0,0,1,1);
        break;
      case '?':
        setChar(0,0,1,1,0,0);
        break;
      case 39:  //Apostrophe
      case 96:
        setChar(0,1,1,1,1,0);
        break;
      case '!':
        setChar(1,0,1,0,1,1);
        break;
      case '/':
        setChar(1,0,0,1,0);
        break;
      case '(':
        setChar(1,0,1,1,0);
        break;
      case ')':
        setChar(1,0,1,1,0,1);
        break;
      case '&':
        setChar(0,1,0,0,0);
        break;
      case ':':
        setChar(1,1,1,0,0,0);
        break;
      case ';':
        setChar(1,0,1,0,1,0);
        break;
      case '=':
        setChar(1,0,0,0,1);
        break;
      case '+':
        setChar(0,1,0,1,0);
        break;
      case '-':
        setChar(1,0,0,0,0,1);
        break;
      case '_':
        setChar(0,0,1,1,0,1);
        break;
      case '"':
        setChar(0,1,0,0,1,0);
        break;
      case '

:
        setChar(0,0,0,1,0,0,1);
        break;
      case '@':
        setChar(0,1,1,0,1,0);
        break;
      case 'ä':
        setChar(0,1,0,1);
        break;
      case 'á':
        setChar(0,1,1,0,1);
        break;
      case 'é':
        setChar(0,0,1,0,0);
        break;
      case 'ó':
      case 'ö':
      case '?':
        setChar(1,1,1,0);
        break;
      case 'ü':
      case '?':
        setChar(0,0,1,1);
        break;

default:  //do nothing
        setChar();
        break;
      }
      Serial.write(text[i]);
      character();  //output letter
      text[i] = 0;  //reset
    }
    Serial.println("");
    newText = false;
  }
}

void character(){
  for(byte i=0; i<9; i++){
    if(part[i] == 9) break;
    else if(part[i] == 4) morse(4);
    else{
      morse(part[i]);
      morse(2);
    }
  }
}

void morse(byte element){
  if(element == 0){  //dot
    digitalWrite(led, HIGH);
    tone(spk, Hz, 1000 / wpm);
    delay(1000 / wpm);
    digitalWrite(led, LOW);
  }
  else if(element == 1){  //dash
    digitalWrite(led, HIGH);
    tone(spk, Hz, 3000 / wpm);
    delay(3000 / wpm);
    digitalWrite(led, LOW);
  }
  else if(element == 2){  //inter-element gap
    delay(1000 / wpm);
  }
  else if(element == 3){  //short gap (between letters)
    delay(3000 / wpm);
  }
  else if(element == 4){  //medium gap or space (between words)
    delay(7000 / wpm);
  }
}