Tricksy ASCII programme

My intention is to have the arduino connected to the computer which can send ascii messages to it. When the connection has been terminated the arduino will read through the message (under 501 bytes) it's stored and blink the correct pattern for each letter.
Problem is, when the connection is terminated it (the LED I've got in pin1 - the only one of the pins connected as yet) just blinks madly no matter what the message was. If any of you could see where I've been going wrong I'd be very grateful.

Here's the code;

// 1st april 2008

int pin1 = 13;
int pin2 = 12;
int pin3 = 11;
int dot1 = 0;
int dot2 = 0;
int dot3 = 0;
int dot4 = 0;
int dot5 = 0;
int dot6 = 0;
int counter = 0;
int jemmy = 0;
char valerie[501];


void setup() {
pinMode(pin1,OUTPUT);
pinMode(pin2,OUTPUT);
pinMode(pin3,OUTPUT);
Serial.begin(9600);
}

void loop ()
{
while (Serial.available() > 0)
      {
      for (counter = 0; counter <=500; counter++)
            {
            jemmy = Serial.read();
            valerie[counter] = jemmy;
            }
      
      for (counter = 0; counter <=500; counter ++)
            {
            dot1 = 0;
            dot2 = 0;
            dot3 = 0;
            dot4 = 0;
            dot5 = 0;
            dot6 = 0;
            
            if (valerie[counter] = 'a')
                  {
                  dot1 = 1;
                  }
            if (valerie[counter] = 'b')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  }
            if (valerie[counter] = 'c')
                  {
                  dot1 = 1;
                  dot4 = 1;
                  }
            if (valerie[counter] = 'd')
                  {
                  dot1 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] = 'e')
                  {
                  dot1 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] = 'f')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot4 = 1;
                  }
            if (valerie[counter] = 'g')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] = 'h')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot5 = 1;
                        }
            if (valerie[counter] = 'i')
                  {
                  dot2 = 1;
                  dot4 = 1;
                  }
            if (valerie[counter] = 'j')
                  {
                  dot2 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  }
            
            if (valerie[counter] = 'k')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  }
            if (valerie[counter] = 'l')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot3 = 1;
                  }
            if (valerie[counter] = 'm')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  }
            if (valerie[counter] = 'n')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] = 'o')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] = 'p')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  }
            if (valerie[counter] = 'q')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] = 'r')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot3 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] = 's')
                  {
                  dot2 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  }
            if (valerie[counter] = 't')
                  {
                  dot2 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  }
            
            if (valerie[counter] = 'u')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] = 'v')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot3 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] = 'x')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] = 'y')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] = 'z')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot5 = 1;
                  dot6 = 1;
                  }
            
            if (valerie[counter] = 'w')
                  {
                  dot2 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] = '!')
                  {
                  dot2 = 1;
                  dot3 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] = ',')
                  {
                  dot2 = 1;
                  }
            if (valerie[counter] = '-')
                  {
                  dot3 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] = '.')
                  {
                  dot2 = 1;
                  dot5 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] = '?')
                  {
                  dot2 = 1;
                  dot3 = 1;
                  dot6 = 1;
                  }
            
            if (dot1 = 1)
                  {
                  digitalWrite(pin1,HIGH);
              }
            else
                  {
                   digitalWrite(pin1, LOW);      
                  }
            if (dot2 = 1)
                  {
                  digitalWrite(pin2,HIGH);
              }
            else
                  {
                   digitalWrite(pin2, LOW);      
                  }
            if (dot3 = 1)
                  {
                  digitalWrite(pin3,HIGH);
              }
            else
                  {
                   digitalWrite(pin3, LOW);      
                  }
            delay(10);
            digitalWrite(pin1,LOW);
            digitalWrite(pin2,LOW);
            digitalWrite(pin3,LOW);
            delay(70);
            
            if (dot4 = 1)
                  {
                  digitalWrite(pin1,HIGH);
              }
            else
                  {
                   digitalWrite(pin1, LOW);      
                  }
            if (dot5 = 1)
                  {
                  digitalWrite(pin2,HIGH);
              }
            else
                  {
                   digitalWrite(pin2, LOW);      
                  }
            if (dot6 = 1)
                  {
                  digitalWrite(pin3,HIGH);
              }
            else
                  {
                   digitalWrite(pin3, LOW);      
                  }
            delay(10);
            digitalWrite(pin1,LOW);
            digitalWrite(pin2,LOW);
            digitalWrite(pin3,LOW);
            delay(110);
            }
      }
}

One problem with that sketch is that it doesn't wait for the entire message to be received. How do you want to determine when a message is complete? One way would be to detect a special character (such as a carriage return) to indicate the end of message.

Here is some pseudo code assuming you use a carriage return to indicate end of message

// pins and dots would be defined here....

int counter = 0; 
int jemmy = 0; 
char valerie[501]; 

void ProcessMessage( int count){
  for (int i = 0; i < count; i++){
       if (valerie[i] = 'a')
      // do your stuff here
    }
}

  loop () { 
      while (Serial.available() > 0)   { 
      jemmy = Serial.read(); 
      if(jemmy == '\r') {              // carriage return??  
         ProcessMessage( counter);  // message received so process it
         counter = 0;
      }
      else  
         valerie[counter++] = jemmy;   //add serial data to buffer 
    }           
}

Thanks, I'll try to encorporate that now.

This may be more optimization then you want or need, but FWIW here is an idea for handling the conversion of letters to dots. The code uses an array (called monty) that has bits set corresponding to each the 6 pins for each letter. You would need to define all the letters, I did the first few.

I hope the fragment is reasonably clear but feel free to ignore it if it looks like gobbledygook

// array of pin settings for characters 'a' through 'z' (Letter B indicates this is binary representation)
byte monty[] = {B1,B11,B1001,B11001,B10001}; // ToDo: masks needed for chars 'f' through 'z'

void OutDots( byte mask){    
     // turn the first three dots on if the bit mask is set, turn off of bit mask is 0
     digitalWrite(pin1,(mask  & 1)); // dot1
     digitalWrite(pin2,(mask  & 2)); // dot3         
     digitalWrite(pin3,(mask  & 4)); // dot3         
     delay(10);      
     digitalWrite(pin1,LOW); 
     digitalWrite(pin2,LOW); 
     digitalWrite(pin3,LOW); 
     delay(70); 
     // now turn on or off dots 4-6 depending on the mask    
     digitalWrite(pin1,(mask  & 8)); // dot1
     digitalWrite(pin2,(mask  & 16)); // dot3         
     digitalWrite(pin3,(mask  & 32)); // dot3      

     delay(10); 
     digitalWrite(pin1,LOW); 
     digitalWrite(pin2,LOW); 
     digitalWrite(pin3,LOW); 
     delay(110);        
}
  
  
void ProcessMessage( int count){
  for (int i = 0; i < count; i++){
     char letter = valerie[i];
     if( letter >= 'a' && letter <= 'z')
         OutDots(monty[letter - 'a' ]) ;   // this passes the first entry in monty for 'a', the second for 'b'  etc.      
     else
      ;   // handle punctuation here 

    }
}

To be honest it does look a little gobbledgookeque, but only because I'd never even seen the language before monday, let alone try to programme in it. I certainly won't be ignoring it though - more learning from it.
Just a few things;

ProcessMessage( counter)

As I understand it this is the C equivelant of Gosub in basic, and the "counter" is the variable which should be carried in to be used within it. Does this mean that only the counter variable can be used within the function? And why the space before "counter"?

void OutDots( byte mask)

So it's a function, but "byte mask"? Similarly,

digitalWrite(pin1,(mask  & 1)); // dot1

I understand the concept of masking, but not the syntax. How does it know from that command what segment of code to mask off?

OutDots(monty[letter - 'a' ]) ;   // this passes the first entry in monty for 'a', the second for 'b'  etc.

Got a bit lost here. You subtract an 'a' from the letter . . . How does that send the first entry for 'a'?

All terribly newbie questions I'm afraid, but I couldn't find the answers to them on the reference page.

ProcessMessage( counter) > As I understand it this is the C equivelant of Gosub in basic
yes, ProcessMessage is a function, like gosub in basic

"counter" is the variable which should be carried in to be used within it.
right again, the value of counter is passed to the function

And why the space before "counter"?
no reason, spaces before or after expressions are ignored

void OutDots( byte mask) >So it's a function, but "byte mask"?
This is the declaration of the function OutDots. Outdots takes one parameter, a byte called mask.

I understand the concept of masking, but not the syntax.
How does it know from that command what segment of code to mask off?
that code uses the C bitwise and operator '&'. You may want to have a serch on C bitwise operators on google.

You subtract an 'a' from the letter . . . How does that send the first entry for 'a'?
the character 'a' has an ascii value of 97, so subracting 'a' from a lower case letter will give the offset of that latter from 'a'. We want that offset because we use it to look up the mask in our array where 'a' is the first mask, 'b' is the second and so on down the alphabet.

Sorry, I am afraid I threw in way too many arcane aspects of C if this is your first effort.

Ok, I've got the code working (although not fully implementing mem's suggestions yet, due to my lack of confidence with the language), as shown below.
Once hooked up the arduino reads text sent to it until recieves a line feed or carriage return. However, I've been trying to convert the valerie[] value to flash memory so I can expand the length of the string. Couldn't get my head around the http://tinyurl.com/5ntnqm library. Whats the most simple way to do this?
Thanks.

// 8th arduino programme - 9th april 2008

int pin1 = 13;
int pin2 = 12;
int pin3 = 11;
int dot1 = 0;
int dot2 = 0;
int dot3 = 0;
int dot4 = 0;
int dot5 = 0;
int dot6 = 0;
int counter = 0;
int jemmy = 0;
char valerie[501];


void setup() {
Serial.begin(115200);
}

void loop() {
  serialtomemory();
}

void serialtomemory() {
  if (Serial.available () > 0)
    {
      // read the incoming byte:
      jemmy = Serial.read ();

      // Store it in a character array
      valerie[counter] = jemmy;
      counter++;

      // check if we have over 499 characaters or we recieve a return or line feed
      if (counter > 499 || jemmy == 10 || jemmy == 13)
        {
          valerie[counter] = 10;
          for (; counter < 499; counter ++) {
           valerie[counter] = 10;
          } 
          memorytomechanics();
        } // endif
    } // endif
  } // function end
  
void memorytomechanics() {
  for (counter = 0; counter < 27; counter ++) {
            dot1 = 0;
            dot2 = 0;
            dot3 = 0;
            dot4 = 0;
            dot5 = 0;
            dot6 = 0;
            
            if (valerie[counter] == 'a')
                  {
                  dot1 = 1;
                  }
            if (valerie[counter] == 'b')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  }
            if (valerie[counter] == 'c')
                  {
                  dot1 = 1;
                  dot4 = 1;
                  }
            if (valerie[counter] == 'd')
                  {
                  dot1 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] == 'e')
                  {
                  dot1 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] == 'f')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot4 = 1;
                  }
            if (valerie[counter] == 'g')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] == 'h')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot5 = 1;
                        }
            if (valerie[counter] == 'i')
                  {
                  dot2 = 1;
                  dot4 = 1;
                  }
            if (valerie[counter] == 'j')
                  {
                  dot2 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  }
            
            if (valerie[counter] == 'k')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  }
            if (valerie[counter] == 'l')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot3 = 1;
                  }
            if (valerie[counter] == 'm')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  }
            if (valerie[counter] == 'n')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] == 'o')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] == 'p')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  }
            if (valerie[counter] == 'q')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] == 'r')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot3 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] == 's')
                  {
                  dot2 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  }
            if (valerie[counter] == 't')
                  {
                  dot2 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  }
            
            if (valerie[counter] == 'u')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] == 'v')
                  {
                  dot1 = 1;
                  dot2 = 1;
                  dot3 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] == 'x')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] == 'y')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] == 'z')
                  {
                  dot1 = 1;
                  dot3 = 1;
                  dot5 = 1;
                  dot6 = 1;
                  }
            
            if (valerie[counter] == 'w')
                  {
                  dot2 = 1;
                  dot4 = 1;
                  dot5 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] == '!')
                  {
                  dot2 = 1;
                  dot3 = 1;
                  dot5 = 1;
                  }
            if (valerie[counter] == ',')
                  {
                  dot2 = 1;
                  }
            if (valerie[counter] == '-')
                  {
                  dot3 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] == '.')
                  {
                  dot2 = 1;
                  dot5 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] == '?')
                  {
                  dot2 = 1;
                  dot3 = 1;
                  dot6 = 1;
                  }
            if (valerie[counter] == 10)
                  {
                        counter = 0;
                        Serial.println();
                  return;
                  }
            Serial.print(valerie[counter]);
            if (dot1 == 1)
                  {
                  Serial.print(1);
                        digitalWrite(13,HIGH);
              }
            else
                  {
                   Serial.print(2);      
                         digitalWrite(13,LOW);
                  }
                delay(100);
            if (dot2 == 1)
                  {
                  Serial.print(1);
              }
            else
                  {
                  Serial.print(2);      
                  }
                delay(100);
            if (dot3 == 1)
                  {
                  Serial.print(1);
              }
            else
                  {
                   Serial.print(2);
                  }
                delay(100);
            
            
            if (dot4 == 1)
                  {
                  Serial.print(1);
              }
            else
                  {
                  Serial.print(2);      
                  }
                delay(100);
            if (dot5 == 1)
                  {
                  Serial.print(1);
              }
            else
                  {
                  Serial.print(2);      
                  }
                delay(100);
            if (dot6 == 1)
                  {
                  Serial.print(1);
              }
            else
                  {
                  Serial.println(2);      
                  }
                delay(200);
                digitalWrite(13,LOW);
                delay(600);
                
  } // for end
} // function end

Hi Monty, good to see your progress.

I think you may find this describes an easier way to do what you want: PROGMEM - Arduino Reference

 prog_char      - a signed char (1 byte) -127 to 128
 prog_uchar     - an unsigned char (1 byte) 0 to 255

Hmm. So are ascii values stored from 0 to 127 on both, or -127 to 0 on the former and 0 to 127 on the latter. Can't see the point of the distinction. Prog_uchar seems the best guess to me.

Yes, I don't think it would matter in your sketch but Prog_uchar does seem the more natural fit.

Writing to flash memory is an unnecessarily complex process. In fact this whole language is unnecessarily complex. Even learning L.in.oleum (anywherebb.com) was a less painful process. Makes me all the more grateful for your help actually.

Here I seem to have got myself into a seemingly idiotic cul de sac. The expression prog_uchar valerie[] PROGMEM  = jemmy; produces the error message;

In function 'void serialtomemory()':
error: variable-sized object 'valerie' may not be initialized

Where as when I change it from counter to say, 4, it works. It seems that the flash library doesn't want to mingle intimately with variables from RAM.

// 10th arduino programme - 9th april 2008
#include <avr/pgmspace.h>

int pin1 = 13;
int pin2 = 12;
int pin3 = 11;
int dot1 = 0;
int dot2 = 0;
int dot3 = 0;
int dot4 = 0;
int dot5 = 0;
int dot6 = 0;
int counter = 0;
int jemmy = 0;
PROGMEM prog_uchar valerie[9001];
char crab;


void setup() {
Serial.begin(115200);
}

void loop() {
  serialtomemory();
}

void serialtomemory() {
  if (Serial.available () > 0)
    {
      // read the incoming byte:
      jemmy = Serial.read ();

      // Store it in a character array
      prog_uchar valerie[] PROGMEM  = jemmy;
      counter++;

// . . . and it continues on.

Writing to flash memory is an unnecessarily complex process.

Complex is an understatement. It's because in the processor architecture, program memory is completely separate from data memory. This makes an efficient chip but very ugly for trying to store data in program space.

The example code in the Progmem reference has the strings known at compile time. I have no idea how (or if) the PROGMEM functionality works for strings like yours that are only known at runtime. You may be able to find something in one of the AVR forums but if its possible at all it will not be pretty.

It looks like you have happened to have chosen a project that is much more difficult to implement then one would expect.

I wonder if it will be simpler for you to use some kind of external memory, there are some references to interfacing with SD cards in the playground, for example: http://www.arduino.cc/playground/Code/Dataflash

I hope you are having fun :wink:

The example code in the Progmem reference has the strings known at compile time. I have no idea how (or if) the PROGMEM functionality works for strings like yours that are only known at runtime.

You can't use PROGMEM for strings that are only known at runtime.*

How big do you want to make the strings? Would a combination of RAM and the on-chip EEPROM be enough? Would a more efficient way of storing the patterns be a possibility?

--Phil.

  • For those of you reading who can think of a convoluted method involving a custom bootloader, SPM instructions, copied Flash segments and black magic, just keep quiet, we don't want to go there... :stuck_out_tongue:

I suppose I'm dodging the problem really. In my mostly working code (posted yesterday at 19:02:46), which uses only RAM, I have a string 501 bytes long. Roughly a hundred words. Yet when it's sent a string from the serial port longer than about 25 characters it only outputs the first 25, and then loops itself whenever enter is pressed rather than reset itself as it should. I thought that if I moved it over to flash memory this would somehow change, maybe because there would be more memory available. But if I could get the full 501bytes in ram then that would be sufficient. Otherwise, yes I probably will have to use that dataflash. Arg! More complexity! When I found the arduino I thought it was going to make the whole project so much simpler, and it almost has, almost.

That code only reads the first 27 bytes.

in memorytomechanics() try changing
for (counter = 0; counter < 27; counter ++) {
to
for (counter = 0; counter < 499; counter ++) {

but add a check for the end of the string

Cough< Err, yes, well spotted, just testing. >Tries not to catch his eye<