-1

I've been trying to get an Arduino (I have a Mega and Uno lying around) to read values from a small array of 3 ColorPal 20380, which individually, work as intended with some reflective material. The demo gives no problem, but I am confused as to how to approach activating all the 3 sensors and reading the 3 different sets of values so that I can analyze them in a program on the Arduino.

How can I get all three sensors to output data to my program in parallel? I want to use the values at the same point in time on all three sensors to do some calculations in my program. Should I approach something like a state machine? Or at least near-parallel (a few ms delay is fine too)? How would an example look like?

The most confusing thing for me is the non-inverted, open-drain protocol it uses. From the documentation:

Because of the open-drain protocol, the pin used to communicate with the ColorPAL should always be configured as an input, except when being driven low. Also, when starting up, you should wait for this pin to be pulled high by the ColorPAL before trying to send it any commands.

I tried modifying the demo to something silly in sequence like this just to see how it would work in the Arduino but I got nothing (pins 2, 4 and 6 are the data pins):

/* ColorPal Sensor Example for Arduino
  Author: Martin Heermance, with some assistance from Gordon McComb
  This program drives the Parallax ColorPAL color sensor and provides
  serial RGB data in a format compatible with the PC-hosted 
  TCS230_ColorPAL_match.exe color matching program.
*/

#include <SoftwareSerial.h>

int sio = 0;            
const int unused = 255;         // Non-existant pin # for SoftwareSerial
const int sioBaud = 4800;
const int waitDelay = 10;

// Received RGB values from ColorPAL
int red;
int grn;
int blu;

// Set up two software serials on the same pin.
SoftwareSerial serin = SoftwareSerial(sio, unused);
SoftwareSerial serout = SoftwareSerial(unused, sio);

void setup() {

  // Unoptimized setup

      sio = 2;
      serin = SoftwareSerial(2, unused);
      serout = SoftwareSerial(unused, 2);
      Serial.begin(9600);
      reset();                // Send reset to ColorPal
      serout.begin(sioBaud);
      pinMode(2, OUTPUT);
      serout.print("= (00 $ m) !");       // Loop print values, see ColorPAL documentation
      serout.end();           // Discontinue serial port for transmitting

      serin.begin(sioBaud);           // Set up serial port for receiving
      pinMode(2, INPUT);

      sio = 4;
      serin = SoftwareSerial(4, unused);
      serout = SoftwareSerial(unused, 4);
      Serial.begin(9600);
      reset();                
      serout.begin(sioBaud);
      pinMode(4, OUTPUT);
      serout.print("= (00 $ m) !"); 
      serout.end();          

      serin.begin(sioBaud);    
      pinMode(4, INPUT);

      sio = 6;
      serin = SoftwareSerial(6, unused);
      serout = SoftwareSerial(unused, 6);
      Serial.begin(9600);
      reset();               
      serout.begin(sioBaud);
      pinMode(6, OUTPUT);
      serout.print("= (00 $ m) !"); 
      serout.end();         

      serin.begin(sioBaud);     
      pinMode(6, INPUT);
}

void loop() {

  sio = 2;
  serin = SoftwareSerial(sio, unused);
  serout = SoftwareSerial(unused, sio);
  readData();

  sio = sio + 2;
  serin = SoftwareSerial(sio, unused);
  serout = SoftwareSerial(unused, sio);
  readData();

  sio = sio + 2;
  serin = SoftwareSerial(sio, unused);
  serout = SoftwareSerial(unused, sio);
  readData();
}  

// Reset ColorPAL; see ColorPAL documentation for sequence
void reset() {
  delay(200);
  pinMode(sio, OUTPUT);
  digitalWrite(sio, LOW);
  pinMode(sio, INPUT);
  while (digitalRead(sio) != HIGH);
  pinMode(sio, OUTPUT);
  digitalWrite(sio, LOW);
  delay(80);
  pinMode(sio, INPUT);
  delay(waitDelay);
}

void readData() {
  char buffer[32];

  if (serin.available() > 0) {
    // Wait for a $ character, then read three 3 digit hex numbers
    buffer[0] = serin.read();
    if (buffer[0] == '$') {
      for(int i = 0; i < 9; i++) {
        while (serin.available() == 0);     // Wait for next input character
        buffer[i] = serin.read();
        if (buffer[i] == '$')               // Return early if $ character encountered
          return;
      }
      parseAndPrint(buffer);
      delay(10);
    }
  }
}

// Parse the hex data into integers
void parseAndPrint(char * data) {
  sscanf (data, "%3x%3x%3x", &red, &grn, &blu);
  char buffer[32];
  sprintf(buffer, "R%4.4d G%4.4d B%4.4d", red, grn, blu);
  Serial.println(buffer);
}
  • I don't think you can reinitiate SoftwareSerial several times. Try using variable like e.g. serin1, serin2, serin3 and serout1, serout2, serout3 and (only) initiate them before setup() to make it easier, try getting only one to work first. Then later add the other two. – Gerben Nov 14 '14 at 14:31
  • So looking around the SoftwareSerial library, it is impossible: "It is possible to receive on two different SoftwareSerial ports in the same sketch. You just have to take some care that you aren’t trying to receive from both simultaneously. There are many successful designs which, say, monitor a serial GPS device for a while, then later accept input from an XBee. The key is to alternate slowly between them, switching to a second device only when a transmission from the first is complete." Source – Eriol Nov 15 '14 at 13:35
  • I will try to learn how to use the AltSoftSerial (Apparently this instead for the Uno) since the author says that it can work in parallel instead, but disables a few pins. – Eriol Nov 15 '14 at 13:40
  • You could try using 2 pins, instead of one. One for the RX and the other (via a transistor) for the TX. You'd have to filter out the TX data also coming into the RX pin. – Gerben Nov 15 '14 at 15:01
  • @Gerben Could you explain to me how and what hardware I'd need to wire it using two pins? I have very limited electronics experience, to be honest. Most of this project is a learning experience. – Eriol Nov 18 '14 at 21:17
0

I'm doing something similar with you right now. I'm troubleshooting this right now so we can collaborate.

First of all, even though you have setup 3 pins, you're only telling the Arduino to read only 1 sensor because they're using the same variable (pin6 since it's the last one you set up). You have to declare each pin with a different variable then create 2 more readData() functions to read each pin as a start. But even after I set it up with that, it only read one colorpal. Reading up a little more on the Uno board, it seems that only pin 2 and 3 can do serial interrupt which we need to use to communicate with the ColorPal. I'm not 100% sure as I'm a novice still, but from what my analysis and research shows, that's the problem right now. I'll update if I find anything.

  • I'm also a novice when it comes to electronics, so we're on the same boat. I've delved a little deeper into the comms scheme, and noticed this sensor uses a 1-Wire communication scheme or "the non-inverted, open-drain protocol" mentioned, which seem to use normal GPIO with that OneWire Arduino library. But this demo code uses the SoftwareSerial library instead, which seems to have its own complications, including only receiving one stream of data at a time. The Setup part is a fair point though. – Eriol Nov 14 '14 at 14:10
  • That said, the Arduino Uno seems to have only two native UART pins (pin 0 and 1), so it seems that having three or more will have to incur at least using some other sort of pin and a library for the communication scheme. I'm looking into the aformentioned OneWire for Arduino and see if I can come up with something... – Eriol Nov 14 '14 at 14:19
0

Try using serin.listen() for each SoftwareSerial before using serin.read().

Only one pin can be read at a time and by default it's reading from the last pin initialized.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.