November 22, 2024, 10:52:27 PM

News:

Got VSA?  Want to use your Prop-SX?  Now you can!  See the VSA section of the Library forum for Prop-SX code that works with VSA.


AP-16 with Arduino

Started by ScubaBearLA, March 03, 2014, 11:22:17 AM

Previous topic - Next topic

ScubaBearLA

I'm trying to get an AP-16+ to receive serial commands from an Arduino Uno, with zero success so far.  To verify that it is communicating, I'm just trying to toggle the onboard relay.  I am using software serial at 2400 baud with a 10K pullup to 5V on it for good measure.  I have the BR switch set to Off, A0 & A1 set to On, and the remaining three switches set to Off.

Here is my code:


#include <SoftwareSerial.h>

SoftwareSerial SoftSerial(13,4);

void setup() 
{
}

void loop(void)             // run over and over again
{

  SoftSerial.begin(2400); // start the object
  SoftSerial.write(13);
  SoftSerial.print("!AP16");
  SoftSerial.write(2);
  SoftSerial.print("R1");
  SoftSerial.write(13);

  delay(100);

  SoftSerial.write(13);
  SoftSerial.write(13);
  SoftSerial.print("!AP16");
  SoftSerial.write(2);
  SoftSerial.print("R0");
  SoftSerial.write(13);

  delay(100);
}

I have experimentally tried inverting the serial signal and I've also tried communicating at 38400, both true and inverted.  I've also tried communicating with the AP16 on address 0 as well.  I am assuming something is wrong with my code, but I sure can't find it.  I don't have much experience with C++ and Arduino, being an embedded programmer in Parallax Basic for a couple of decades now... hopefully someone can see me what the problem is.

Thanks--

Alan






JackMan

Do you have any wav files on an SD card and is the card in the AP16+?

ScubaBearLA

Yes, and if I press the START button the file will play.  The green light is on solid.

JonnyMac

March 03, 2014, 02:06:08 PM #3 Last Edit: March 03, 2014, 02:20:23 PM by JonnyMac
I've used the Arduino a grand total of three or four times -- so bear with me.

First things first: the Arduino uses 2-wire serial (traditional UART setup, even when "soft") while the Propeller uses a single-wire, open-collector/drain setup. If you don't need to read information from the AP-16+ (version string or status byte), you can simply hook the TX pin on the Arduino side to the SERIAL.W pin on the AP-16+. Make sure that GND on the Arduino connects to SERIAL.B on the AP-16+.

If you need feedback, I found this circuit though I have not tried it myself.
-- http://hackaday.com/2014/01/13/software-half-duplex-uart-for-avrs/

Quite some time ago I wrote a little Arduino code for the RC-4 that a customer claimed did work for him. I found that, and modified it for the AP-16+ with the information you provided.

#include <SoftwareSerial.h>

#define RX2 13
#define TX2  4

#define ON   1
#define OFF  0

SoftwareSerial SoftSerial(RX2, TX2);

void setup() 
{
  SoftSerial.begin(38400);      // start the object
  delay(100);
  stop_audio(0xFF);         // stop all   
}

void loop(void)
{
  set_relay(0x00, ON);
  delay(1000);
  set_relay(0x00, OFF);
  delay(1000);
}

void stop_audio(int addr)
{
  SoftSerial.write("!AP16");
  SoftSerial.write(addr);
  SoftSerial.write("X");
}


void play_sfx(int addr, int sfx, int rpts)
{
  SoftSerial.write("!AP16");
  SoftSerial.write(addr);
  SoftSerial.write("PS");
  SoftSerial.write(sfx);
  SoftSerial.write(rpts);
}


void set_relay(int addr, int state)
{
  SoftSerial.write("!AP16");
  SoftSerial.write(addr);
  SoftSerial.write("R");
  SoftSerial.write(state);
}



This has just a few functions, but should help you get things going.

One note on the Relay command: the next value is supposed to be a byte 0 or 1; in your original code you were sending an ASCII character ("0" or "1") which have decimal values of 48 and 49.

Please give this a try and let us know how it goes.
Jon McPhalen
EFX-TEK Hollywood Office

JonnyMac

BTW... if you like the Arduino form factor and would like to experience the awesome power of the Propeller, give this a look:
-- http://www.parallax.com/product/32214

As we are experts in the Propeller, we can show you all kinds of cool tricks with this dude.
Jon McPhalen
EFX-TEK Hollywood Office

ScubaBearLA

Hi JonnyMac--

I figured that I was sending the characters you mentioned in the wrong format, what I could not figure out was how to do it correctly.  Your code set me on the right track, thank you very much!  I now have the serial communication working and can proceed with writing the rest of my routines.  Here is the code the code that now works for me:

#include <SoftwareSerial.h>

SoftwareSerial SoftSerial(13,4);

void setup() 
{ SoftSerial.begin(2400); // start the object
}

void loop(void)             // run over and over again
{    int state = 1;
     int addr = 0;
     
      SoftSerial.write("!AP16");
      SoftSerial.write(addr);
      SoftSerial.write("R");
      SoftSerial.write(state);
      delay(500);
     
      state = 0;
      SoftSerial.write("!AP16");
      SoftSerial.write(addr);
      SoftSerial.write("R");
      SoftSerial.write(state);
   
      delay(500);
     
      int rtn = 13;
      int rpts = 1;
      SoftSerial.write("!AP16");
      SoftSerial.write(addr);
      SoftSerial.write("PW");
      SoftSerial.write("WAITSONG");
      SoftSerial.write(rtn);
      SoftSerial.write(rpts);
   
      delay(4000);
     
      SoftSerial.write("!AP16");
      SoftSerial.write(addr);
      SoftSerial.write("PW");
      SoftSerial.write("WAITSONG");
      SoftSerial.write(rtn);
      SoftSerial.write(rpts);
     
      delay(4000);

}

JonnyMac

March 03, 2014, 07:20:35 PM #6 Last Edit: March 04, 2014, 10:38:23 AM by JonnyMac
Glad things are working.

Tip: Force yourself to write modular code and used named constants where you can. Hard-coding routines in the main loop and using "magic numbers" is never a good idea. I know these seem like niggly things when you're just trying to get a program going, but you'll be happier later, especially when you want to use the routines elsewhere.

Here's how I'd write a routine for playing a named WAV file (I already showed you how to do a numbered SFX).

void play_wav(int addr, char *wavname, int rpts)
{
  SoftSerial.write("!AP16");
  SoftSerial.write(addr);
  SoftSerial.write("PW");
  SoftSerial.write(wavname);
  SoftSerial.write(0x0D);
  SoftSerial.write(rpts);
}


Here's your updated program:

#include <SoftwareSerial.h>

#define RX2  13
#define TX2   4

#define ON    1
#define OFF   0

#define ALL  0xFF                       // global address


SoftwareSerial SoftSerial(RX2, TX2);


void setup() 
{
  SoftSerial.begin(38400);              // start the object
  delay(100);
  stop_audio(ALL);                      // stop all   
}


void loop(void)
{
  set_relay(0x00, ON);
  delay(500);

  set_relay(0x00, OFF);
  delay(500);

  for(int i = 0; i < 2; i++) {
    play_wav(0x00, "WAITSONG", 1);
    delay(4000);
  }
}


// Stop audio in selected AP-16+
//
void stop_audio(int addr)
{
  SoftSerial.write("!AP16");
  SoftSerial.write(addr);
  SoftSerial.write("X");
}


// Play SFXnn.WAV on AP-16+
// -- addr is 0..3, or 0xFF for all (global)
// -- nn is 0 to 15
// -- rpts is number of repeats (0 to loop)
//
void play_sfx(int addr, int sfx, int rpts)
{
  SoftSerial.write("!AP16");
  SoftSerial.write(addr);
  SoftSerial.write("PS");
  SoftSerial.write(sfx);
  SoftSerial.write(rpts);
}


// Play named WAV file
//
void play_wav(int addr, char *wavname, int rpts)
{
  SoftSerial.write("!AP16");
  SoftSerial.write(addr);
  SoftSerial.write("PW");
  SoftSerial.write(wavname);
  SoftSerial.write(0x0D);
  SoftSerial.write(rpts);
}


// Set AP-16+ relay to state
// -- state is 0 (off) or 1 (on)
//
void set_relay(int addr, int state)
{
  SoftSerial.write("!AP16");
  SoftSerial.write(addr);
  SoftSerial.write("R");
  SoftSerial.write(state);
}


Note how much cleaner the main loop is -- this is key. Redundancy is removed (copy-and-paste often induces errors) and the code is written such that you could have more than one AP-16+ attached and control it.
Jon McPhalen
EFX-TEK Hollywood Office