processing sending serial to arduino problem

okay, so i have written some arduino code, and it works when i send the data vi the serial monitor, however when i use the processing program, it doesnt work. (i have temporarly assigned pin 13 led to light when the F value is above 0

im not experinced in processing

oh and the RX TX led´s are on

here is the arduino code:

#include <Servo.h>  // Include the servo library

char dataSelect;    // A variable used to store the char that determins, if you controll the fans or the servos
int Sdegree;        // A variable used for the degrees of the servo
int Fpwm;            // -----------||---------- PWM data for the fans
Servo myServo;      // Naming our servo myServo

void setup()
{
  Serial.begin(9600);       // Beginning serial communication
  myServo.attach(9);        // Attach our servo data line to pin 9
  pinMode(13, OUTPUT);
}

void loop()
{
  if (Serial.available())   // If there are some data to read
  {
    dataSelect = Serial.read(); // Store the first byte in dataSelect (this will be a char)
    
    //Serial.println(dataSelect, BYTE); // print the recieved char to Serial for debugging. Uncomment to activate this feature
    
    if(dataSelect == 'S')               //If we want to controll the servo, we start by sending a capital S, if we do that, it enters this case 
    {     
      Serial.println("Servo controll selected");
      while (Serial.available() == 0) //Hold the program untill other data (the degree´s) are availabl7e
      {;}
      delay(5);
      int serialAvail = Serial.available();  //Store the number of available bytes in an int
      
      if(serialAvail == 1)                   //If there is only one byte (eg. sending it a degree number from 0 to 9   
      {  
        Sdegree = Serial.read() - '0';       //Since thers only one charactor, the only conversion needed is to turn the charactor '1' into int 1 we do this by substracting '0'. Look up an ascii table to understand this better 
      }
      
      if(serialAvail == 2)
      {                                             //If there is two bytes, we need to read them one at a time, then put them up after each other
         int aDecimal1 = Serial.read() - '0';      //Read the first digit
         int aDecimal2 = Serial.read() - '0';      //Read the second digit
         Sdegree = (aDecimal1*10) + aDecimal2;   //Combine them, we do this by multiplying the first digit with ten, then adding the second digit
      }
        
      if(serialAvail ==3)                                            //same technic as above, you should be able to understand it ;)
      {
         int bDecimal1 = Serial.read() - '0';
         int bDecimal2 = Serial.read() - '0';
         int bDecimal3 = Serial.read() - '0';
          Sdegree = (bDecimal1*100)+(bDecimal2*10)+bDecimal3;
      }
      Serial.print("Degrees are: ");
      Serial.println(Sdegree);
      Serial.println();
    }
      
     else if(dataSelect == 'F')
     {      //If we want to controll the Fans, we start by sending a capital S, if we do that, it enters this case 
        Serial.println("Fan controll selected");
        while (Serial.available() == 0) //Hold the program untill other data (the PWM data) are available
        {;}
        delay(5);
        int serialAvail = Serial.available();  //Store the number of available bytes in an int
    
        if(serialAvail == 1)                   //If there is only one byte (eg. sending it a low PWM number (0 to 9)  
        {
          Fpwm = Serial.read() - '0';          //Since thers only one charactor, the only conversion needed is to turn the charactor '1' into int 1 we do this by substracting '0'. Look up an ascii table to understand this better 
        }
      
        if(serialAvail == 2)                   //If there is two bytes, we need to read them one at a time, then put them up after each other
        {      
          int aaDecimal1 = Serial.read() - '0';      //Read the first digit
          int aaDecimal2 = Serial.read() -  '0';      //Read the second digit
          Fpwm = (aaDecimal1*10) + aaDecimal2;      //Combine them, we do this by multiplying the first digit with ten, then adding the second digit
        }
        
        if(serialAvail == 3)                        //same technic as above, you should be able to understand it ;)
        {                                              
          int bbDecimal1 = Serial.read() - '0';
          int bbDecimal2 = Serial.read() - '0';
          int bbDecimal3 = Serial.read() - '0';
          Fpwm = (bbDecimal1*100)+(bbDecimal2*10) + bbDecimal3;
        }
        Serial.print("PWM data is: ");
        Serial.println(Fpwm);
        Serial.println();
        if(Fpwm > 0)
        {
          digitalWrite(13, HIGH);
        }
        else
        {
          digitalWrite(13, LOW);
        }
     }
     else
     {
       Serial.println("----------------------------");
       Serial.println("False data. Flushing buffer.");
       Serial.println("----------------------------");
       Serial.println();
       Serial.flush();
     }
    
  }
  delay(20);
}

and here is the processing (using some example code):

/**
 * ControlP5 Slider. Horizontal and vertical sliders, 
 * with and without tick marks and snap-to-tick.
 * by andreas schlegel, 2010
 */

import controlP5.*;
import processing.serial.*;

ControlP5 controlP5;
int myColor = color(0,0,0);
int knobValue = 0;
int Fan = 0;
Serial COMport;
Knob myKnobB;


void setup() {
  size(120,130);
  COMport = new Serial(this, "COM3", 9600);
  controlP5 = new ControlP5(this);
  // add a vertical slider
  controlP5.addSlider("Fan",0,200,0,10,10,10,100);
  myKnobB = controlP5.addKnob("knobValue",0,179,0,60,65,50);  
}

void draw() {
  background(0);
  COMport.write('S');
  COMport.write(knobValue);
  COMport.write('\r');
  COMport.write('F');
  COMport.write(Fan);
  COMport.write('\r'); 
}

void slider(float theColor) {
  myColor = color(theColor);
  println("a slider event. setting background to "+theColor);
}

it doesnt work.

can anyone help me with the code?

it doesnt work

Have you tried offering a pay rise? Pension scheme?

What does it do that it isn't supposed to, and what doesn't it do that it is supposed to?

Serial.available() returns the number of bytes available at a given instance. If you send "S180" to the Arduino, the 'S' will arrive. Then, from the Arduino's perspective, eons later the '1'. Then, after a few more eons, the '8' will arrive. Then, after another eternity, the '0' will arrive.

You are expecting them to arrive nearly instantaneously, so you can send S8, S78, or S178.

This is not a realistic expectation. So, get over it, and add an end of packet marker. Once you know that the serial stream starts with 'S', read until you get an end of packet marker, then process the string read. Maybe use atoi().

eey :smiley:

so the source of my problem was my processing code, the fact that it send out data all the time, meant that the arduino couldnt keep up, so i added this:

 if(fanLast != Fan)
  {
      port.write('F');
      delay(5);
      port.write(Fan);
      delay(5);
      fanLast = Fan;
      println(Fan);
  }

and something similare for the knobValue

the entire code is:

proscessing:

import controlP5.*;
import processing.serial.*;

ControlP5 controlP5;
int fanLast;
int knobLast;
int myColor = color(0,0,0);
int knobValue = 0;
int Fan = 0;
Serial port;
Knob myKnob;


void setup() {
  size(150,130);
  port = new Serial(this, "COM3", 9600);
  controlP5 = new ControlP5(this);
  // add a vertical slider
  controlP5.addSlider("Fan",0,255,0,10,10,10,100);
  myKnob = controlP5.addKnob("knobValue",0,179,0,60,65,50);  
}

void draw() {
  background(0);
  if(fanLast != Fan)
  {
      port.write('F');
      delay(5);
      port.write(Fan);
      delay(5);
      fanLast = Fan;
      println(Fan);
  }
  if(knobLast != knobValue)
  {
      port.write('S');
      delay(5);
      port.write(knobValue);
      delay(5);
      knobLast = knobValue;
      println(knobValue);
  }
}

Arduino:

#include <Servo.h>  // Include the servo library

char dataSelect;    // A variable used to store the char that determins, if you controll the fans or the servos
int Sdegree;        // A variable used for the degrees of the servo
int Fpwm;            // -----------||---------- PWM data for the fans
Servo myServo;      // Naming our servo myServo

void setup()
{
  Serial.begin(9600);       // Beginning serial communication
  myServo.attach(9);        // Attach our servo data line to pin 9
  pinMode(13, OUTPUT);
  Serial.flush();
}

void loop()
{
  if (Serial.available() > 0)   // If there are some data to read

  {
    dataSelect = Serial.read(); // Store the first byte in dataSelect (this will be a char)
    
    //Serial.println(dataSelect, BYTE); // print the recieved char to Serial for debugging. Uncomment to activate this feature
    
    if(dataSelect == 'S')               //If we want to controll the servo, we start by sending a capital S, if we do that, it enters this case 
    {     
      while (Serial.available() == 0) //Hold the program untill other data (the degree´s) are availabl7e
      {;}
      int serialAvail = Serial.available();  //Store the number of available bytes in an int
      
      if(serialAvail == 1)                   //If there is only one byte (eg. sending it a degree number from 0 to 9   
      {  
        Sdegree = Serial.read();       //Since thers only one charactor, the only conversion needed is to turn the charactor '1' into int 1 we do this by substracting '0'. Look up an ascii table to understand this better 
      }
      
      if(serialAvail == 2)
      {                                             //If there is two bytes, we need to read them one at a time, then put them up after each other
         int aDecimal1 = Serial.read();      //Read the first digit
         int aDecimal2 = Serial.read();      //Read the second digit
         Sdegree = (aDecimal1*10) + aDecimal2;   //Combine them, we do this by multiplying the first digit with ten, then adding the second digit
      }
        
      if(serialAvail ==3)                                            //same technic as above, you should be able to understand it ;)
      {
         int bDecimal1 = Serial.read();
         int bDecimal2 = Serial.read();
         int bDecimal3 = Serial.read();
         Sdegree = (bDecimal1*100)+(bDecimal2*10)+bDecimal3;
      }
      if(Sdegree > 0)
        {
          digitalWrite(13, HIGH);
        }
        else
        {
          digitalWrite(13, LOW);
        }
    }
      
     else if(dataSelect == 'F')
     {      //If we want to controll the Fans, we start by sending a capital S, if we do that, it enters this case 
        while (Serial.available() == 0) //Hold the program untill other data (the PWM data) are available
        {;}
        int serialAvail = Serial.available();  //Store the number of available bytes in an int
    
        if(serialAvail == 1)                   //If there is only one byte (eg. sending it a low PWM number (0 to 9)  
        {
          Fpwm = Serial.read();          //Since thers only one charactor, the only conversion needed is to turn the charactor '1' into int 1 we do this by substracting '0'. Look up an ascii table to understand this better 
        }
      
        if(serialAvail == 2)                   //If there is two bytes, we need to read them one at a time, then put them up after each other
        {      
          int aaDecimal1 = Serial.read();      //Read the first digit
          int aaDecimal2 = Serial.read();      //Read the second digit
          Fpwm = (aaDecimal1*10) + aaDecimal2;      //Combine them, we do this by multiplying the first digit with ten, then adding the second digit
        }
        
        if(serialAvail == 3)                        //same technic as above, you should be able to understand it ;)
        {                                              
          int bbDecimal1 = Serial.read();
          int bbDecimal2 = Serial.read();
          int bbDecimal3 = Serial.read();
          Fpwm = (bbDecimal1*100)+(bbDecimal2*10) + bbDecimal3;
        }
        if(Fpwm > 0)
        {
          digitalWrite(13, HIGH);
        }
        else
        {
          digitalWrite(13, LOW);
        }        
     }
     else
     {
       Serial.flush();
     }
    
  }
}

feel free to use it :smiley:

Adding delay() is the wrong answer. How long to fart around doing nothing depends on far too many factors to be anything other than a band-aid solution. Sending the data properly is a far better solution.

how would you go around using an end of packet marker?

i know that in processing you can do readStringUntil() but what is the arduino code for that?

main reason why i didnt use end of packet marker, is because i didnt know how

also the code (processing) is altered to include a dropdown list to select the comport (so now the previous code doesnt work :frowning: )

the new processing code is:

import controlP5.*;
import processing.serial.*;

ControlP5 controlP5;
int fanLast;
int knobLast;
int myColor = color(0,0,0);
int knobValue = 0;
int Fan = 0;
float S;
int Ss;
String[] comList;
boolean serialSet;
boolean Comselected = false;
boolean customDone = false;
String comSelecT;
Serial port;
Knob myKnob;
DropdownList p1;


void setup() {
  size(240,130);
  controlP5 = new ControlP5(this);
  // add a vertical slider
  controlP5.addSlider("Fan",0,255,0,10,10,10,100);
  myKnob = controlP5.addKnob("knobValue",0,179,0,60,65,50);
  p1 = controlP5.addDropdownList("list-1",130,25,100,90);
  customize(p1); 
}

void controlEvent(ControlEvent theEvent) {
  if (theEvent.isGroup()) 
  {
    // check if the Event was triggered from a ControlGroup
    S = theEvent.group().value();
    Ss = int(S);
    Comselected = true;
  }
}

void customize(DropdownList ddl) {
  ddl.setBackgroundColor(color(200));
  ddl.setItemHeight(20);
  ddl.setBarHeight(15);
  ddl.captionLabel().set("Select COM port");
  ddl.captionLabel().style().marginTop = 3;
  ddl.captionLabel().style().marginLeft = 3;
  ddl.valueLabel().style().marginTop = 3;
  comList = port.list();
  String comlist = join(comList, ",");
  int size1 = comlist.length() / 3;
  println(size1);
  for(int i=0; i< size1; i++)
  {
    ddl.addItem(comList[i],i);
  }
  ddl.setColorBackground(color(60));
  ddl.setColorActive(color(255,128));
  println(port.list());
}

void startSerial(String[] theport)
{
  println(theport);
  println(Ss);
  port = new Serial(this, theport[Ss], 9600);
  serialSet = true;
}


void draw() {
  while(Comselected == true && serialSet == false)
  {
  startSerial(comList);
  }
  background(0);
  if(fanLast != Fan && serialSet == true)
  {
      port.write('F');
      delay(5);
      port.write(Fan);
      delay(5);
      fanLast = Fan;
      println(Fan);
  if(knobLast != knobValue && serialSet == true)
  {
      port.write('S');
      delay(5);
      port.write(knobValue);
      delay(5);
      knobLast = knobValue;
      println(knobValue);
  }
}
}

i know that in processing you can do readStringUntil() but what is the arduino code for that?

There isn't a single function for the Arduino to do that. It is not hard to emulate it, though.

bool ended = false;
const char eop = '>';
char buffer[24]; // Or whatever size you think appropriate
int index = 0;

void loop()
{
   while(Serial.available() > 0)
   {
     int inByte = Serial.read();
     if(inByte == eop)
     {
        ended = true;
        break;
     }
     buffer[index++] = inByte;
     buffer[index] = '\0';
   }

   if(ended)
   {
      // Do something with buffer

      ended = false;
      index = 0;
      buffer[index] = '\0';
   }
}

how would you go around using an end of packet marker?

Simple but not perfect end of packet code.

// zoomkat 7-18-11 serial I/O string test
// type a string in serial monitor followed by a ,
// then send or enter
// for IDE 0019 and later

String readString;

void setup() {
  Serial.begin(9600);
  Serial.println("serial test 0021 delimit"); // so I can keep track of what is loaded
}

void loop() {

  if (Serial.available()) {
    char c = Serial.read();

    if (c == ',')
    {
      Serial.println(readString);
      readString="";
    }
    readString += c; 
  }
}

okay so i have given up on the EOP addition for now.

reason why is that i dont understand Pauls code, and Zoomkat´s isnt working :(. so now im waiting 20 ms in my processing sketch between each data send for now. (my arduino code gets confused when there is more that 3 characters available. now its working nicely, and those 20 ms of waiting time is time that i have to spare.)

its for controlling fanspeed via pwm and servos via the library, so 20 ms delay isnt that big of a deal.

the only thing i now have a hard time determing, is wether to use a mosfet for controlling the fans, or a bipolar, i would say a mosfet is what i need since they are voltage controlled, but i need a mosfet that will be fully on at 5v. (its driving 2 12cm pc fan´s)

how would i know which one to chose? also, since mosfets arent current driven, a 5k resistor on the gate would work, wouldn´t it?

while waiting ill google away :)

oh and thanks a million for the help. It lead me to my problem (and the bandage fix i use) :D

after googleing a bit, i found this:

http://search.digikey.com/scripts/DkSearch/dksus.dll?Detail&name=NTD5867NL-1GOS-ND

it seems to be apropriate. Doesn´t it?

and reading a bit up on Mosfets, there shouldnt be any resistor. XD

reason why is that i dont understand Pauls code, and Zoomkat´s isnt working smiley-sad. so now im waiting 20 ms in my processing sketch between each data send for now. (my arduino code gets confused when there is more that 3 characters available. now its working nicely, and those 20 ms of waiting time is time that i have to spare.)

Sometime, though, you won't have the luxury of twiddling your thumbs for an eternity. What is there about the code that you don't understand? Understanding it will benefit you in lots of ways in the future.

It creates a flag, initially set to false, that indicates whether an EOP has arrived. It defines the character that is the EOP, and an array to hold the data up to the EOP.

It reads all available data from the serial port, on each pass through loop, until there is no more serial data OR until the EOP arrives.

Serial data that is not the EOP is added to the array, with the entry position incremented. A NULL is added each time a character is. This enables the buffer to be passed to any function that expects NULL terminated arrays of chars, such as strtok, strcmp, atoi, etc.

If the data read from the serial port IS the EOP, it quits reading from the serial port, after setting the flag to true.

When there is no more serial data, or the EOP was received, it determines which condition is true (no more data or EOP received) based on the flag. If the packet is complete (the flag is true), the data is processed (by code you need to add), and the buffer is cleared, the index is reset, and the flag is cleared.

If you need more details, let me know.

well the thing is, i dont really see how to implement it in my code, since its relying on: if(Serial.available == 1 , 2 or 3) and this will screw up if i have send more that one packet of data.

secondly i dont know what buffer is, and i dont know what buffer[index] = '\0'; mainly the '\0' :/

well the thing is, i dont really see how to implement it in my code, since its relying on: if(Serial.available == 1 , 2 or 3)

Your code shouldn't rely on a specific number of characters. Serial data delivery is NOT guaranteed.

secondly i dont know what buffer is

char buffer[24]; defines a block of memory, commonly referred to as a buffer, that can hold 24 characters.

buffer[index] = '\0';

This puts a NULL character in the position specified by index. A NULL is a 0, which is escaped, to prevent misunderstanding (the ), enclosed in single quotes, to define that it is one character long.

The short summary:

Invert the specification - send the command character last. Do away with the buffer, you’re only accumulating a number.

The little example fragments - some assembly for a complete program required :slight_smile:

On the sending side use

  COMport.write(knobValue);
  COMport.write('S');
  :
  COMport.write(Fan);
  COMport.write('F');

Not that we do need the ‘\r’ … (which, by the way, was that famous EOP marker you all were discussing)

On the receiving side use a variable to hold the “current” number and character

unsigned int NewVal=0 ;  char NewChr ;

In your main loop somewhere you have code that checks for serial input and it accumulates the number. NOTE: this code is nonblocking. It will carry on doing the other things in your loop while the data accumulates.

 if ( Serial.available()>0 )  {
   NewChr = Serial.read() ;
   if ( '0' <= NewChr && NewChr <= '9' ) // then we have a digit, accumulate it
     NewVal = NewVal*10 + NewChr-'0' ; // shift previous digit up, add new
   else // we have command character
     if ( NewChr='S' ) {
       SVal = NewVal ; // you can do a analogWrite or whatever with you new Sval
       NewVal = 0 ;
     }
    else // we still have a command char, but it wasnt the S
     if ( NewChr='F' ) {
       FVal = NewVal ; // you can do a analogWrite or whatever with you new Fval
       NewVal = 0 ;
     }
    else NewVal = 0 ; // some junk character - lets reset the input.
   } // done all serial input

This code assumes several things. There will always be sent an integer (in ASCII) followed by a single non-digit command character. It will only do one character per pass through the loop (which in most cases is many times faster than needed) If the number is too large it will be junk.

No delay, no buffer overflow, no problems.

Oh, I really should make a library of this. (If the two line button debounce code is worthy of a library…) But a slightly general purpose library will take more (needless) code, require documentation and …