Interactive talking robot (wave shield) help!!!!!!

ello everyone, I am currently working on a robot that plays wave files from the arduino wave shield from an incoming serial line from another microcontroller. and much trial and error i got it working, but when I added a second if then statement to play a wave file based on the serial input it uploaded fine but in the serial monitor it says too many files open unable to open. How can I fix this? My project’s due date is coming up and im at a lost. (Im using the Arduino Duemilanovie with the ATMega328) Any help would be very appreciated! Ik I have plenty of flash memory left so that can’t be the problem

post your code I bet somebody could help if you did ;) Use the insert code when posting (makes things easier)

thank you for the advice :slight_smile:

#include <NewSoftSerial.h>
#include <AF_Wave.h>
#include <avr/pgmspace.h>
#include "util.h"
#include "wave.h"


NewSoftSerial BS2 = NewSoftSerial(0, 255);   // receive only 
int bs2data = BS2.read(); 

#define TWOBIT "TWOBIT.WAV"
#define SING   "SONG.WAV"

AF_Wave card;
File f;
Wavefile wave;      // only one!

#define redled 9

int wasplaying = 0;

void setup() {
  Serial.begin(9600);
  BS2.begin(9600);  
  Serial.begin(9600);           // set up Serial library at 9600 bps
  Serial.println("Wave test!");

  pinMode(2, OUTPUT); 
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(redled, OUTPUT);
  
  if (!card.init_card()) {
    putstring_nl("Card init. failed!"); return;
  }
  if (!card.open_partition()) {
    putstring_nl("No partition!"); return;
  }
  if (!card.open_filesys()) {
    putstring_nl("Couldn't open filesys"); return;
  }
  if (!card.open_rootdir()) {
    putstring_nl("Couldn't open dir"); return;
  }

  ls();

}

void loop() { 
   char c, *toplay;
   
   
   if(BS2.available() > 0) {        
   bs2data = BS2.read();
   Serial.print("Received from BS2: ");
   Serial.println(bs2data);                

     if (bs2data == 'A') {
       toplay = TWOBIT;
     }
     else if (bs2data == 'B') {
       toplay = SING;
    
     }
     
     if (wave.isplaying) {// already playing something, so stop it!
         wave.stop(); // stop it
         card.close_file(f);
     }
     playfile(toplay);
   }

   if (wave.isplaying && !wasplaying) {
     digitalWrite(redled, HIGH);
   } else if (!wave.isplaying && wasplaying) {
     digitalWrite(redled, LOW);
   }
   wasplaying = wave.isplaying;
}


void ls() {
  char name[13];
  card.reset_dir();
  putstring_nl("Files found:");
  while (1) {
    if (!card.get_next_name_in_dir(name)) {
       card.reset_dir();
       return;
    }
    Serial.println(name);
  }
}

void playfile(char *name) {
   f = card.open_file(name);
   if (!f) {
      putstring_nl("Couldn't open file"); return;
   }
   if (!wave.create(f)) {
     putstring_nl("Not a valid WAV"); return;
   }
   // ok time to play!
   wave.play();
}
NewSoftSerial BS2 = NewSoftSerial(0, 255);

You're trying to use the hardware serial pin for software serial. How's that working out for you?

#define TWOBIT "TWOBIT.WAV"
#define SING   "SONG.WAV"

These names (TWOBIT and SING) are replaced where they appear in the code before the compiler is called. The compiler then sees:

     if (bs2data == 'A') {
       toplay = "TWOBIT.WAV";
     }
     else if (bs2data == 'B') {
       toplay = "SONG.WAV";

This is not the proper way to assign a pointer.

Try this:

char toplay[48];
     if (bs2data == 'A') {
       strcpy(toplay, TWOBIT);
     }
     else if (bs2data == 'B') {
       strcpy(toplay, SING);

Yes, but Its serial data is comming from ANOTHER microcontroller not the computer so I would use the hardware serial pin

PaulS,

What's wrong with assigning a literal string to a variable declared 'char *'?

Regards,

-Mike

Doing it once is OK. The memory is allocated for the literal string, and the pointer points to that memory location.

char *charPtr = “literal”; allocates memory for the literal string, and stores the location of the literal string in the variable charPtr.

Then, if charPtr is pointed somewhere else, the memory occupied by the literal string is still occupied, but you have no way of accessing it.

In this code:

     if (bs2data == 'A') {
       toplay = "TWOBIT.WAV";
     }
     else if (bs2data == 'B') {
       toplay = "SONG.WAV";

the compiler will see the literal string “TWOBIT.WAV”, and allocate memory for it. It will store the location in the pointer toplay. Then, it will see the literal string “SONG.WAV”, and allocate memory for it. It will store the location in the pointer toplay, resulting in nothing containing the address where the literal “TWOBIT.WAV” is stored, meaning that the memory can not be accessed again. You can never re-assign toplay to point to that memory address, because you have not stored the address anywhere.

This code:

char *songone = "TWOBIT.WAV";
char *songtwo = "SING.WAV";

char *toplay;
.
.
.
     if (bs2data == 'A') {
       toplay = songeone;
     }
     else if (bs2data == 'B') {
       toplay = songtwo;

will work just fine, though, because the memory locations for both literal strings are always available, and toplay points to one or the other at any given time.

@steedmiste

If the data is coming in to the TX pin, and going out the RX pin (or not going out at all), you can use the hardware serial class, Serial, rather than the emulation class, NewSoftSerial.

It matters not where the data is coming [u]from[/u]; it matters only where it is coming [u]in[/u].

the compiler will see the literal string "TWOBIT.WAV", and allocate memory for it. It will store the location in the pointer toplay. Then, it will see the literal string "SONG.WAV", and allocate memory for it. It will store the location in the pointer toplay, resulting in nothing containing the address where the literal "TWOBIT.WAV" is stored, meaning that the memory can not be accessed again. You can never re-assign toplay to point to that memory address, because you have not stored the address anywhere.

@PaulS - you're just making that stuff up! ;D