Quantcast
Channel: Processing Forum
Viewing all articles
Browse latest Browse all 1768

Re : serial problem in reading a string

$
0
0
For what it is worth, here is some information that hopefully will help. Keep in mind I'm just a hack. I do remember how frustrating this was at first, especially before the Ardunio IDE had a serial monitor. Maybe it always had one. It certainly is a huge help. Exit Processing and run your Ardunio IDE with the serial monitor open and set to the correct baud rate. Have the Ardunio hooked up and running. The serial monitor will show you exactly what your Ardunio code is sending. It is essential that you do this to make sure what is being sent by the Ardunio is what you expect to receive in Processing and to make sure the data comes when it is supposed to.

I've never seen the error "disabling serialEvent() ..." but it seems to me this could be resulting from outside of your code. Make sure you have the Ardunio IDE shut down before running your Processing code. I don't think they can coexist while both are looking at the serial port. Shutting down the Ardunio IDE eliminates that possibility.

What follows are three working Ardunio/Processing serial communication schemes. Each is different.

1) Ardunio sends integer values as new line string followed by the character A. Processing receives the string using the readStringUntil method on the letter A, strips the A off and uses the remainder as the data. Having the Ardunio "code" the data with the marker letter and having the Processing side only process incoming serial data coded this way ensures that the processed data is legit. 

Ardunio code: Many years old!

String arduinoUSB = "/dev/tty.usbserial-A7006Tac";
int myArd;

void setupSerial(){
  println("Available serial ports:");
  println(Serial.list());
  // Use the port corresponding to your Arduino board.  The last
  // parameter (e.g. 9600) is the speed of the communication.  It
  // has to correspond to the value passed to Serial.begin() in your
  // Arduino sketch.
  println("Looking for " +arduinoUSB);
  myArd = check4SerialDevice(arduinoUSB);
  //println(myArd + " check4");
  if (myArd != -1){
    println("Found " +arduinoUSB + " at " +myArd);
    port = new Serial(this, Serial.list()[myArd], 14400);
    port.bufferUntil(MARKER);
  }
  else{
    println("Did not find Arduino USB driver " + arduinoUSB);
  }
}


void loop(){
  // read the analog input on pin 0:
  analogValue = analogRead(0);
  if (abs(analogValue-lastValue) > analogDelta) {
    //Serial.println(analogValue);
    Serial.print(analogValue);
    Serial.print("A");
    lastValue = analogValue;
    digitalWrite(ledPin, HIGH);
  }
  if (  analogValue == 0 & lastValue != 0) {
    Serial.print(analogValue);
    Serial.print("A");
    lastValue = analogValue;
    digitalWrite(ledPin, HIGH);
  }
  if (analogValue == 1023 & lastValue != 1023){
    Serial.print(analogValue);
    Serial.print("A");
    lastValue = analogValue;
    digitalWrite(ledPin, HIGH);
  }  
  delay(10);
  digitalWrite(ledPin, LOW);

Processing code

// MARKER = 65; // the letter A used to decode the serial input sent by the Arduino

void serialEvent(Serial port) { 
  dataStr = (port.readStringUntil(MARKER));
  if (dataStr.length() >=2){
    dataStr = dataStr.substring(0, dataStr.length()-1); // strip off the last  char
    //println(dataStr);
    if (myCal != -1){  // normal condition
      potV = calibrationTable.getCalValue(float(dataStr));
    } 
    else { // abnormal, calibration table not found
      potV = map(float(dataStr),spiroMinData,spiroMaxData,0,1023)*litersPerDataVal;  
    }
    if ((dataStr != null) & (curTest < qtyTests)) { // ie stop after last test
      arypotV[curTest] = potV;
      if(arypotV[curTest] > arypotMax[curTest]){
        arypotMax[curTest] = arypotV[curTest];
      }
    }
  }
}

2) Ardunio sends coded number data groups, each followed by an "\n". The data is coded into two group types designated by a specific letter. Within each group the information pieces are separated by a | character. This data is a list of temperature sensor IDs and a list of the corresponding temperature values.  Processing receives the string using the bufferUntil method looking for the the integer 10, which is a line feed. Processing then splits the string into an array using the | character and then processes the array, being either sensor ID or sensor temperature, based upon the array's first element "code" letter.

Ardunio code:

//// temp sampler/output function
void tempSample()
{
  sensors.requestTemperatures();
  // output sensor addresses
  Serial.print("A|");
  Serial.print(int(goldTop));
  Serial.print("|");
  Serial.print(int(silverTop));
  Serial.print("|");
  Serial.print(int(silvrGndGoldVdd));
  Serial.print("|");
  Serial.print(int(redVdd));
  Serial.print("|");
  Serial.print(int(blueVdd));
  Serial.print("\n");
  // output temperatures
  Serial.print("T|");
  printTempF(goldTop);
  Serial.print("|");
  printTempF(silverTop);
  Serial.print("|");
  printTempF(silvrGndGoldVdd);
  Serial.print("|");
  printTempF(redVdd);
  Serial.print("|");
  printTempF(blueVdd);
  Serial.print("\n");
}

void printTempF(DeviceAddress deviceAddress)
{
  float tempF = sensors.getTempF(deviceAddress);
  if (tempF == NULL) { 
    Serial.print("Error getting temperature");
  } else {
    Serial.print(tempF);
  }
}

Processing code:

// This runs whenever a serial event occurs as defined in setup
//
// Prev defined: int lf = 10; // linefeed
// p = new Serial(this, serialPortName, 9600);
// p.bufferUntil(lf);

void serialEvent(Serial p){ 
  inString = p.readString();
  // the adrunino temp reader program is set to code data in groups
  // all divded by the | character and followed by lf. Since we have
  // Serial to buffer until lf the data shows up in code groups startng
  // with a signature letter and then the data separated by |. So we
  // first split according to | and then examine the first item to detect
  // the data code.

  String[] dataStr = split(inString,"|");  // split into an array
  //println("head: " + dataStr[0]);
  // Now check the code group.

  if (dataStr[0].equals("A") == true){
    //println("found A: " + dataStr[0]);
    addrString = dataStr;
  }

  if (dataStr[0].equals("T") == true){
    //println("found T: " + dataStr[0]);
    tempString = dataStr;
    for (int i = 0; i < qtySensr; i = i+1){  
      Sensors[i].storeCurrent(i+1);
    }
  }
}

3) Ardunio sends status messages as strings as if printing to a console. Processing uses readStringUntil('\n') to read the string. It then fills an array with the string lines. Each array element is a string line. These are continuously drawn to the display and scrolled as new message come in.

Ardunio code: There are many different message types . These are some. This code was initially made to write to the Adrunio IDE serial monitor and not changed in any way to accomodate how the Processing side needed.  

// reportStatus - prints out status line
void reportStatus(){
  byte _nextIndx;
  _nextIndx = nextSchdIndx(currentSchdIndx);
  reportTime();
  Serial.print("\nSchd ");
  Serial.print(currentSchdIndx);
  Serial.print(" start ");
  Serial.print(schdPeriod_arr[currentSchdIndx].hrs_S);
  Serial.print(":");
  Serial.print(schdPeriod_arr[currentSchdIndx].min_S);
  Serial.print(", end ");
  Serial.print(schdPeriod_arr[_nextIndx].hrs_S);
  Serial.print(":");
  Serial.print(schdPeriod_arr[_nextIndx].min_S);
  Serial.print(", mode ");  
  if (schedModeOverRide == 0) {
    Serial.print(cycleMode);
  } else {
    Serial.print("overriden to ");
    Serial.print(cycleMode);
  }
  Serial.print(", inhibited ");
  Serial.print(noPumping);
  if (feeding == 1) {
    Serial.print(" by feeding");
  } else {
    if (noPumping == 1) {
      Serial.print(" by POFF");
    }
  }
  Serial.print(", main cycle period ");
  Serial.print(millisToSec(cycleMode_arr[cycleObj].cyclePeriod));
  Serial.print(" sec, active timers ");
  Serial.print(tpumps.getNumTimers());
  Serial.println();
}

// reportTime - prints out current RTC data and time
void reportTime(){
  DateTime now = RTC.now();
  Serial.print("\nTime is: ");
  Serial.print(now.year());
  Serial.print("/");
  Serial.print(now.month());
  Serial.print("/");
  Serial.print(now.day());
  Serial.print(" ");
  Serial.print(now.hour());
  Serial.print(":");
  Serial.print(now.minute());
  Serial.print(":"); 
  Serial.print(now.second());
  
}

// reportSchedule - prints out the current daily schedule
void reportSchedule(){
  Serial.print("\nDaily Schedule");
  for (byte indx = 0; indx <= maxSchdIndx; indx++){
      Serial.print("\nSchd ");
      padding (indx,2);
      Serial.print(" starts ");
      padding (schdPeriod_arr[indx].hrs_S,2);
      Serial.print(":");
      padding (schdPeriod_arr[indx].min_S,2);
      Serial.print(", cycle mode ");
      Serial.print(schdPeriod_arr[indx].pmode);
  }  
  Serial.println();
}

void padding( int number, byte width ) {
  int currentMax = 10;
  for (byte i=1; i<width; i++){
    if (number < currentMax) {
      Serial.print("0");
    }
    currentMax *= 10;
  } 
  Serial.print(number);
}

Processing code: The event code is very basic. The nextLine() function is included here to avoid confusion. It has nothing to do with the serial event. It is just the mechanism being used to place the new incoming string into the correct location in the lines[] array. Its action happens to also create the text scrolling effect.


The serial setup was using: myPort.bufferUntil('\n');

void serialEvent(Serial myPort)
{
 newmsg = (myPort.readStringUntil('\n')); 
 lines[nextLine()] = newmsg;
}

int nextLine() {
  for (int i = 0; i < maxLines; i++){
   if (lines[i] == "") {
      return i;
   }
  }
  for (int i = 0; i < maxLines-1; i++){
   lines[i] = lines[i+1];
  }
  return maxLines-1;
}

Maybe these examples can help.




Viewing all articles
Browse latest Browse all 1768

Trending Articles