Id.exe fails to compile when my sketch exceeds about 165 lines.

Tried IDEs 1.6.2 and 1.6.3. Compile fails every time displaying "Id.exe has encountered a problem and needs to close" when my sketch grows to over about 165 lines. I'm using SoftwareSerial to receive an ascii byte from another UNO and generate morse code. It's the receiver sketch that is failing to compile. It compiles and works fine if I keep the number of lines below about 165. Other instructions in the sketch are: a Switch Case with fifteen cases corresponding to the numeric and alpha ascii characters expected with a handful of variable settings each case; after the Case Select are ten DigitalWrites each with its own delay(nn) to turn on the beeper. The delay parameters are integer variables. I only have 15 of the desired 36 alpha/numeric characters in the Case Select at the point that compile fails.

Any ideas?

I would turn on verbose build messages to see if it says anything useful before it exits.

Thanks for the response. I'm not immediately seeing how to turn on verbose build messages. :)

File > Preferences > Show verbose output during: compilation

Thank you.

When I add just 3 lines of code to the loop the sketch compile fails. I got 10 pages of verbose output. The good compile output matches the bad compile output except for the last 18 lines of the good compile. So, when they start to differ, there are 18 lines of good but only 2 lines of bad compile output.

Here are the good compile's last 18 lines: "C:\Documents and Settings\Administrator\Application Data\Arduino15\packages\arduino\tools\avr-gcc\4.8.1-arduino2/bin/avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\build7975192946701027366.tmp/AsciiToMorse_RX_1.cpp.elf C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\build7975192946701027366.tmp/AsciiToMorse_RX_1.cpp.eep C:\Documents and Settings\Administrator\Application Data\Arduino15\packages\arduino\tools\avr-gcc\4.8.1-arduino2/bin/avr-objcopy -O ihex -R .eeprom C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\build7975192946701027366.tmp/AsciiToMorse_RX_1.cpp.elf C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\build7975192946701027366.tmp/AsciiToMorse_RX_1.cpp.hex

Sketch uses 3,580 bytes (11%) of program storage space. Maximum is 32,256 bytes. Global variables use 143 bytes (6%) of dynamic memory, leaving 1,905 bytes for local variables. Maximum is 2,048 bytes."

Here are the bad compile's last 2 lines (where output differs): "collect2.exe: error: ld returned 5 exit status Error compiling."

The 3 lines of code added to the loop's switch case resulting in the bad compile: case 65: // e time1=240; // length of first cw cipher break;

Here is the last line that matches: "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\build7975192946701027366.tmp/core.a -LC:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\build7975192946701027366.tmp -lm "

Any ideas?

I don't see anything in those few messages from which I can draw a conclusion.

Perhaps there is some way to re-write the sketch using arrays rather than a large switch statement. I don't know if that will work around the problem but it couldn't hurt.

I got rid of the switch case statements, substituting if statements. It stopped compiling after the 14th one. I need to have 36.

case 49: // decimal 1 time1=240; // length of first cw cipher time3=240; // length of second time5=816; // length of third time7=816; // length of fourth time9=816; // length of fifth break;

Am now using up to 20 of these before the same compile error:

if (inChar == 49){ // decimal 1 time1 = 240; // length of first cw cipher time3 = 240; // length of second time5 = 816; // length of third time7 = 816; // length of fourth time9 = 816; // length of fifth }

Is there some kind of 'lines allowed in loop limit' or something that I am exceeding? Or is it simply an IDE bug?

How would I use arrays to accomplish this? I'm very new to C. Thanks.

daviddanali: Is there some kind of 'lines allowed in loop limit' or something that I am exceeding? Or is it simply an IDE bug?

I'd guess it is a compiler/linker bug of some kind. Perhaps the compiler is generating short jumps that only allow for +/-128 byte offsets and the linker errors when it is asked to put a larger offset in.

daviddanali: How would I use arrays to accomplish this?

That depends on how many different lengths of beep you need. The one example you show has five beeps in two different lengths. I would expect International Standard (ITU) Morse Code to have one to five tones in two lengths. You can fit each code into a 16-bit integer by using binary: 1 for dit, 11 for dah, and 0 for space.

unsigned int Alphabet[] = {
0b0000000000001011, //A
0b0000000011010101, //B
0b0000000110101101, //C
0b0000000000110101, //D
0b0000000000000001, //E
0b0000000010101101, //F
.
.
.
0b0000000110110101 //Z};

The longest code is for '0' (five dashes) which takes up 14 of the 16 available bits: 0b0011011011011011.

Then it's just a matter of fetching the integer from the array and turning the 1's and 0's into dots, dashes, and spaces.

void playMorse(unsigned int pattern) {
    unsigned int mask = 0b1000000000000000;
    int lastBit=0;  // Pattern always starts with 0's

    // Search for the first 1 in the pattern
    while (mask != 0 && (pattern&mask) == 0)
        pattern >>= 1;  // Shift pattern right one bit

    if (mask == 0)
        return;  // No 1's found!

    // Continue processing each bit until all 16 have been used.
     for (;mask != 0; mask >>= 1) {
        if ((pattern&mask) != 0){  // Part of a DIT or DAH
            if (lastBit == 0)
               play(DIT_LENGTH);  // First 1 of DIT or DAH
            else
               play(DAH_LENGTH - DIT_LENGTH); // 2nd 1 of DAH
         } else { //Space
            delay(SPACE_LENGTH);
         }

        lastBit = (pattern&mask) != 0;

     }
    // All bits processed.  Add the inter-letter space
    delay(LETTER_SPACE);
}

I see how the 36 alphanumeric characters I need can be encoded in 36 unsigned integers. This is very efficient. The code to But, how can I select the proper integer to 'play' when an ascii character from 48 to 57 or 97 to 122 is received without using a switch case or if instructions? Thanks. I can't see my way from ascii char to choosing the right integer in the array.

if (input >= 'A' && input <= 'Z') {
    playMorse(Alphabet[input - 'A']);
} else if (input >= 'a' && input <= 'z') {
    playMorse(Alphabet[input - 'a']);
} else if (input >= '0' && input <= '9') {
    playMorse(Digitst[input - '0']);
} else if (input == ' ') {
    delay(WORD_SPACE - LETTER_SPACE);
}

Oops: I had this part wrong:

    // Search for the first 1 in the pattern
    while (mask != 0 && (pattern&mask) == 0)
        pattern >>= 1;  // Shift pattern right one bit

It should be:

    // Search for the first 1 in the pattern
    while (mask != 0 && (pattern&mask) == 0)
        mask >>= 1;  // Shift mask right one bit

Thanks for all the help! You've written most of my program, I think. The mask concept I haven't bumped into for a while. My programming experience over the years has been in PIC and Z80 assembly language and Basic. The C language strikes me as being concise. You can do a lot with little text. But it is taking me a while to ramp up.

What does >>= do in the line for (;mask != 0; mask >>= 1) ?

I'm not sure I have the curly braces right (especially in the last half dozen) in:

void playMorse(unsigned int pattern) { unsigned int mask = 0b1000000000000000; int lastBit = 0; // Pattern always starts with 0's // Search for the first 1 in the pattern while (mask != 0 && (pattern & mask) == 0) // != means not equal mask >>= 1; // Shift mask right one bit if (mask == 0) return; // No 1's found! go back to loop // Continue processing each bit until all 16 have been checked for (; mask != 0; mask >>= 1) { // if ((pattern & mask) != 0) { // Part of a DIT or DAH if (lastBit == 0){ // play(DIT_LENGTH) First 1 of DIT or DAH digitalWrite(5, HIGH); // beeper on delay(240); digitalWrite(5, LOW);} // beeper off else if { // play(DAH_LENGTH - DIT_LENGTH) 2nd 1 of DAH digitalWrite(5, HIGH); // beeper on delay(816 - 240); digitalWrite(5, LOW);} // beeper off else { // space delay(SPACE_LENGTH);} // time between dihs and dahs in a character } // end if else lastBit = (pattern & mask) != 0; // All bits processed. Add the inter-letter space delay(LETTER_SPACE); } // end for } // end function

= is using the shift and assignment operators

mask >>= 1

is the same as

mask = mask >> 1

It is taking the value of mask and bit shifting it once to the right and reassigning it back to mask.

The line: for (; mask != 0; mask >>= 1)

Is looping while mask is non zero and each iteration shifting the value in mask to the right 1 bit position.

--- bill

Thank you, Bill, for the explanation on >>= etc.
I did get the sketch to compile today. Made a few little changes from John’s version.
It’s ‘complete’ but doesn’t work. No beeps at all from the MuRata beeper on pin 5. Works with other sketches. I probably broke something. Had to add several “unsigned int” to get it to compile. So…?
I’ll work on it tomorrow.
I’m going to paste it here, just in case you, John or someone can see a problem quickly.
The RX line is getting an ascii j every 5 seconds from another UNO.

#include <SoftwareSerial.h>

// uses array to encode morse characters
// johnwasser helped me a lot
// Receive from other UNO 1 ascii character per 5 seconds
// Digital 8 wired to other UNO Digital 9
// Digital 9 wired to other UNO Digital 8
// UNO GND wired to other UNO GND

SoftwareSerial receiver (8, 9); // RX, TX

char inChar = 0;
int SPACE_LENGTH = 240; // time between dihs and dahs in a character
int LETTER_SPACE = 816; // time between characters
int DIT_LENGTH = 240;
int DAH_LENGTH = 816;

unsigned int alphaNum = { // unsigned integers representing 5 wpm morse code
0b0011011011011011, // 0 48 // starting from left:
0b0001011011011011, // 1 49 // a “1” represents a dih-beep (240ms)
0b0000101011011011, // 2 50 // a “11” represents a dah-beep (816ms)
0b0000010101011011, // 3 51 // a “0” represents an inter-beep-delay (240ms)
0b0000001010101011, // 4 52 // array elements [0…35]
0b0000000101010101, // 5 53
0b0000001101010101, // 6 54
0b0000011011010101, // 7 55
0b0000110110110101, // 8 56
0b0001101101101101, // 9 57
0b0000000000001011, // a 97 10 97 - 87 = 10
0b0000000011010101, // b 98 11
0b0000000110101101, // c 99 12
0b0000000000110101, // d 100 13
0b0000000000000001, // e 101 14
0b0000000010101101, // f 102 15
0b0000000001101101, // g 103 16
0b0000000001010101, // h 104 17
0b0000000000000101, // i 105 18
0b0000001011011011, // j 106 19
0b0000000010101101, // k 107 20
0b0000000010110101, // l 108 21
0b0000000000011011, // m 109 22
0b0000000000001101, // n 110 23
0b0000000011011011, // o 111 24
0b0000000101101101, // p 112 25
0b0000001101101011, // q 113 26
0b0000000000101101, // r 114 27
0b0000000000010101, // s 115 28
0b0000000000000011, // t 116 29
0b0000000000101011, // u 117 30
0b0000000010101011, // v 118 31
0b0000000001011011, // w 119 32
0b0000000110101011, // x 120 33
0b0000001101011011, // y 121 34
0b0000000110110101}; // z 122 35 36 variable array

void setup() {

pinMode(5, OUTPUT); // Beeper driver pin
receiver.begin(9600);
}

void loop() {

if (receiver.available() > 0) {
inChar = receiver.read();
}

// Use inChar to select integer to play from alphaNum
if (inChar >= ‘0’ && inChar <= ‘9’) {
unsigned int pattern = alphaNum[inChar - ‘0’]; // select element
playMorse(pattern);
} else if (inChar >= ‘a’ && inChar <= ‘z’) {
unsigned int pattern = alphaNum[inChar - 87]; // select element
playMorse(pattern);
} else if (inChar == ’ ') { // 32 ascii space
delay(816);
}
}

// Play Morse code from selected integer
void playMorse(unsigned int pattern) {
unsigned int mask = 0b1000000000000000;
int lastBit = 0; // Pattern always starts with 0’s
// Search for the first 1 in the pattern
while (mask != 0 && (pattern & mask) == 0)
mask >>= 1; // Shift mask right one bit
if (mask == 0)
return; // No 1’s found! go back to loop
// Continue processing each bit until all 16 have been checked
for (; mask != 0; mask >>= 1) { //
if ((pattern & mask) != 0) { // Part of a DIT or DAH
if (lastBit == 0) {
// play(DIT_LENGTH) First 1 of DIT or DAH
digitalWrite(5, HIGH); // beeper on
delay(240);
digitalWrite(5, LOW);
} // beeper off
else {
// play(DAH_LENGTH - DIT_LENGTH) 2nd 1 of DAH
digitalWrite(5, HIGH); // beeper on
delay(816 - 240);
digitalWrite(5, LOW);
} // beeper off
}
else { // space
delay(SPACE_LENGTH); // time between dihs and dahs in a character
}
} // end if

lastBit = (pattern & mask) != 0;

// All bits processed. Add the inter-letter space
delay(LETTER_SPACE);
}

PLEASE use code tags when posting code.

John, Bill, Federico,

Two days ago I must have been sending a bogus ascii character. Last night I tried a different character and the code worked fine. I am going to add code to receive a string of ascii characters (up to 20 perhaps). And there's a little fine tuning to do. But I want you (especially John) to know that it's now working! Thanks so much for all your help! David