Go Down

Topic: Button push->Check serial val->Operation Help (Read 2244 times) previous topic - next topic

PaulS

You have a string in buffer. There is a string function, strcmp(), that compares strings. The key is to get the contents of buffer consistent, and then compare buffer to the right string (is it"OL    " or "OL" or "    OL"?).

RREVO

Code: [Select]
#define SS_RX_PIN 4

// SoftwareSerial TX line
#define SS_TX_PIN 5

// Relay 1 pin number
#define RELAY1_PIN 6

// Relay 2 pin number
#define RELAY2_PIN 7

// Relay 3 pin number
#define RELAY3_PIN 8

// E Stop LED indicator pin
#define ESTOP_LED_PIN 9

// Serial speed to/from scale
// NOTE: MUST match scale baud rate
#define SCALE_SERIAL_RATE 9600

// First weight threshold
#define WEIGHT_AMOUNT1 1263

// Second weight threshold
#define WEIGHT_AMOUNT2 2494

// Time to stay at mix stage in seconds
#define MIX_TIME 60

// --- INCLUDES ---
#include <NewSoftSerial.h>

// --- GLOBAL VARIABLES ---
// Emergency Stop status

// Process completion; when 1, adding/mixing is done.
int iProcessStatus = 1;

int startButton = 2;
int val = 0;


// --- CLASS INSTANCES ---
NewSoftSerial scaleSerial(4,5);

// --- FUNCTION PROTOTYPES ---

void setup() {
// Setup the pins.
// NOTE: These two lines are for the emergency stop button.



pinMode(START_BUTTON_PIN,INPUT);
digitalWrite(START_BUTTON_PIN,LOW);
pinMode(RELAY1_PIN,OUTPUT);
digitalWrite(RELAY1_PIN,LOW);
pinMode(RELAY2_PIN,OUTPUT);
digitalWrite(RELAY2_PIN,LOW);
pinMode(RELAY3_PIN,OUTPUT);
digitalWrite(RELAY3_PIN,LOW);
        pinMode(startButton, INPUT);
//pinMode(ESTOP_LED_PIN,OUTPUT);
//digitalWrite(ESTOP_LED_PIN,LOW);


Serial.begin(57600);
        Serial.println("Goodnight moon!");
        scaleSerial.begin(9600);
       
}


char buffer[10];
byte index;
bool ended = true;

void loop() {


//#ifndef MSTYLE_ALT

if(ended)
   {
      scaleSerial.print('b');
      ended = false;
      index = 0;
   }

   while(scaleSerial.available() > 0)
   {
      int inByte = scaleSerial.read();
      if(inByte == '\r' || inByte == '\n')
      {
         ended = true;
      }
      else if(index < 10) // Is there room?
      {
         buffer[index++] = inByte;
         buffer[index] = '\0';
      }
   }

   if(ended)
   {
      Serial.print("Scale returned: >");
      Serial.print(buffer);
      Serial.println("<");

      int weight = atoi(buffer);
      Serial.print("weight: ");
      Serial.println(weight, DEC);

      ended = false;     
   }

   delay(100);

val = digitalRead(startButton);
if (val == LOW){



int weight = atoi(buffer);
if ( weight < 1 ) {
// Less than WEIGHT_AMOUNT1
setRelays(HIGH,LOW,LOW);
} else if ( 1 < weight < 3 ) {
// Between WEIGHT_AMOUNT1 and WEIGHT_AMOUNT2
setRelays(LOW,HIGH,HIGH);
} else if ( 4 < weight) {
// Greater than WEIGHT_AMOUNT2

// Keep
// HACK: I put a mini-loop here to allow e stop to pause mixing.
for ( int i = MIX_TIME; i > 0; i-- ) {


setRelays(LOW,HIGH,LOW);

delay(1000);
}

// Done.
iProcessStatus = 1;
}


}}



// Function to read the current weight reading


// Conventient wrapper function to set all three relays on one line.
void setRelays ( int iRelay1, int iRelay2, int iRelay3 ) {
digitalWrite(RELAY1_PIN,iRelay1);
digitalWrite(RELAY2_PIN,iRelay2);
digitalWrite(RELAY3_PIN,iRelay3);
}

// Function to emergency stop/start the machine.


// Sets the process state variable.
void startProcess ( void ) {
iProcessStatus = 0;


So this is what I was working with, but I clearly am nor grasping the basics here. So I set the scale to continuous mode to keep spitting numbers out, and it does indeed read it and spit them back to me. The problem is I havent set the function that runs on the button (which is the relay control) to properly work. I intend for a person just to have to press the button once and for that operation to run, but it cant because it cannot see the updated scale info and just ends the process and starts over again. What am I missing to make this a proper operation?

Also getting OL to read consistently seems off as most of the time the buffer looks like this
Code: [Select]
Scale returned: > 2<
weight: 2
Scale returned: > 2     2<
weight: 2
Scale returned: >   2<
weight: 2
Scale returned: >   2     2<
weight: 2
Scale returned: >     2<
weight: 2
Scale returned: > 2<
weight: 2
Scale returned: > 2     2<
weight: 2
Scale returned: >   2<
weight: 2
Scale returned: >   2     2<
weight: 2
Scale returned: >     2<
weight: 2
Scale returned: > 2<
weight: 2
Scale returned: > 2     2<
weight: 2
Scale returned: >   2<
weight: 2

Just imagine replacing the 2 with OL, and that is just how sporadic it is, I assume the continuous output is a bit fast... I am really not sure.

PaulS

There is a possibility that you are seeing the serial port buffer overflow. You can see if this is a possibility by printing the value returned by scaleSerial.available(). If that number consistently is small (less than 10) no overflow is occurring. If that number climbs quickly and runs around 64 or so, there is a problem.


RREVO

I think my problem is with the way the code is trying to read the serial information. I can only get valuable data that updates if I have the scale on continuous output, I believe I got the buffer set to work properly, but not sure if this will work. Any other suggestions on integrating this code with a simple pushbutton that you only have to push once and it runs through the whole process correctly with hitting that button again to pause, and then a simple interrupt I think I can figure out to act as an emergency shutoff?

thank you so much for your help thusfar, and for the delay in getting back to you. I had my brothers wedding over the weekend.
I will test that buffer check for you today.

RREVO

Code: [Select]
// scalething.pde

// --- NOTES ---
// The various relay enables/disables set an explicit state for all three
// to prevent transient bugs. Check to make sure they're turning on/off
// at the appropriate times.

// When should the scale tare the weight?

// --- DEFINES ---

// Management style
// When SET, style 1 is used, otherwise style 2
// follow the #ifdef tags in the code to see what the difference is.
// Uncomment the next line to use style 2
//#define MSTYLE_ALT

// Pin number that the START button is on
// NOTE: Must be 2 or 3
#define START_BUTTON_PIN 3

// Pin number fo Emergency Stop button
// NOTE: Must be 2 or 3
#define ESTOP_BUTTON_PIN 3

// SoftwareSerial RX line
#define SS_RX_PIN 4

// SoftwareSerial TX line
#define SS_TX_PIN 5

// Relay 1 pin number
#define RELAY1_PIN 6

// Relay 2 pin number
#define RELAY2_PIN 7

// Relay 3 pin number
#define RELAY3_PIN 8

// E Stop LED indicator pin
#define ESTOP_LED_PIN 9

// Serial speed to/from scale
// NOTE: MUST match scale baud rate
#define SCALE_SERIAL_RATE 9600

// First weight threshold
#define WEIGHT_AMOUNT1 1263

// Second weight threshold
#define WEIGHT_AMOUNT2 2494

// Time to stay at mix stage in seconds
#define MIX_TIME 60

// --- INCLUDES ---
#include <NewSoftSerial.h>

// --- GLOBAL VARIABLES ---
// Emergency Stop status

// Process completion; when 1, adding/mixing is done.
int iProcessStatus = 1;

int startButton = 2;
int val = 0;


// --- CLASS INSTANCES ---
NewSoftSerial scaleSerial(4,5);

// --- FUNCTION PROTOTYPES ---

void setup() {
// Setup the pins.
// NOTE: These two lines are for the emergency stop button.



pinMode(START_BUTTON_PIN,INPUT);
digitalWrite(START_BUTTON_PIN,LOW);
pinMode(RELAY1_PIN,OUTPUT);
digitalWrite(RELAY1_PIN,LOW);
pinMode(RELAY2_PIN,OUTPUT);
digitalWrite(RELAY2_PIN,LOW);
pinMode(RELAY3_PIN,OUTPUT);
digitalWrite(RELAY3_PIN,LOW);
        pinMode(startButton, INPUT);
//pinMode(ESTOP_LED_PIN,OUTPUT);
//digitalWrite(ESTOP_LED_PIN,LOW);


Serial.begin(57600);
        Serial.println("Goodnight moon!");
        scaleSerial.begin(9600);
       
}


char buffer[6];
byte index;
bool ended = true;

void loop() {


//#ifndef MSTYLE_ALT

if(ended)
   {
      scaleSerial.print('b');
      ended = false;
      index = 0;
   }

   while(scaleSerial.available() > 0)
   {
      int inByte = scaleSerial.read();
      if(inByte == '\r' || inByte == '\n')
      {
         ended = true;
      }
      else if(index < 6) // Is there room?
      {
         buffer[index++] = inByte;
         buffer[index] = '\0';
      }
   }

   if(ended)
   {
      Serial.print("Scale returned: >");
      Serial.print(buffer);
      Serial.println("<");

      int weight = atoi(buffer);
      Serial.print("weight: ");
      Serial.println(weight, DEC);

      ended = false;     
   }

   delay(100);

val = digitalRead(startButton);
if (val == LOW){



int weight = atoi(buffer);
if ( weight < 200 ) {
// Less than WEIGHT_AMOUNT1
setRelays(HIGH,LOW,LOW);
} else if ( 200 < weight < 400 ) {
// Between WEIGHT_AMOUNT1 and WEIGHT_AMOUNT2
setRelays(LOW,HIGH,HIGH);
} else if ( 400 < weight) {
// Greater than WEIGHT_AMOUNT2

// Keep
// HACK: I put a mini-loop here to allow e stop to pause mixing.
for ( int i = MIX_TIME; i > 0; i-- ) {


setRelays(LOW,HIGH,LOW);

delay(1000);
}

// Done.
iProcessStatus = 1;
}


}}



// Function to read the current weight reading


// Conventient wrapper function to set all three relays on one line.
void setRelays ( int iRelay1, int iRelay2, int iRelay3 ) {
digitalWrite(RELAY1_PIN,iRelay1);
digitalWrite(RELAY2_PIN,iRelay2);
digitalWrite(RELAY3_PIN,iRelay3);
}

// Function to emergency stop/start the machine.


// Sets the process state variable.
void startProcess ( void ) {
iProcessStatus = 0;
}


So here is the code again with what I am working with for the moment. I think my if/else statements are just not working, or the processing of the weight is off. I currently have to hold the button down to get it to change functions but I can't get to the third phase of the if else statement. It will go from relay1 on to relay 2 and 3 and sometimes flicker on relay 1 with 2+3 off for a second. Makes little sense to me other then the fact that the data processing is taking precedence and I need the button to run more of a process then a loop so that you press it once and it runs until completed with the data decoding going on in the background.

I am just getting lost down the rabbit hole.

PaulS

Quote
I am just getting lost down the rabbit hole.

You are trying to move on before you get one thing working. That is a recipe for disaster.

I don't see that you are using the internal pullup resistors with the switches. So, is it safe to assume that you have external pullup or pulldown resistors? (The code suggests pullup resistors are needed.)

Code: [Select]
      int weight = atoi(buffer);
      Serial.print("weight: ");
      Serial.println(weight, DEC);

      ended = false;     
   }

   delay(100);

val = digitalRead(startButton);
if (val == LOW){



int weight = atoi(buffer);

Why do you need to convert buffer to an int twice? Make weight a global or static variable, and quit trashing it it buffer contains garbage.

Code: [Select]
} else if ( 200 < weight < 400 ) {
This will compare the value of weight to 200, and then compare either true or false to 400. Both true and false are less than 400, so this test always succeeds, which is why you can't get the the third stage.

You need:
Code: [Select]
else if ( 200 < weight && weight < 400 )
Of course, the statement won't even be evaluated unless weight is greater than 200, so the first part is not required.

RREVO

Good point.

So I set the second atoi to go off to reference the weight because the code needed it to work correctly, which means I did something wrong. The coding is definitely not right, I just tried to make it work. I will plug in that change to the greater than less than statement, that makes total sense.

So essentially in short method I need: weight<200, do this; weight>200, do this; weight>400, do this;
and that should work correctly, meaning under 200 is is first operation, from 200-399 it is second operation, and from 400+ it is last operation until I tell it to stop.

PaulS

Quote
So essentially in short method I need: weight<200, do this; weight>200, do this; weight>400, do this;
and that should work correctly, meaning under 200 is is first operation, from 200-399 it is second operation, and from 400+ it is last operation until I tell it to stop.

If you want to do something if the weight is less than 200, something else if the weight is between 200 and 400 and a third thing if the weight is above 400, the simplest way is to handle the two ends first:
Code: [Select]
if(weight < 200)
  // Hmm, too light
else if(weight > 400)
  // Oof, too heavy
else
  // Just right

RREVO

So to perform relay switching on each of those functions, what is the best way to make that a process that only needs a single button push? I will toss this logic into the code and see if the holding the button method works for the appropriate weights, but I am still not sure on my I need that atoi function a second time to get that to reference the weight correctly. I must be doing something wrong, as per usual.

Edit: I also noticed a syntax change in the if ; else if; else line.
I currently have
if;
else if;
else if;

So the third variant should just be else, correct?

PaulS

Quote
So the third variant should just be else, correct?

If it's not too light and its not too heavy, it must be just right. Right?

Quote
what is the best way to make that a process that only needs a single button push?

Check for switch presses often enough. This means no delay() calls, or only minimum use of delay().

Quote
but I am still not sure on my I need that atoi function a second time to get that to reference the weight correctly.

In the last code you posted, you need two calls, because the two variables that you store the result in are local variables. One goes out of scope before the other place that you need it. Unfortunately, it is possible to change the contents of buffer between calls, and get incorrect results for the second call.

Therefore you need to change the scope of the weight variable. Either move it to the top of loop, and make it static, or make it global. In this case, I'd go with global.

RREVO



If it's not too light and its not too heavy, it must be just right. Right?

I figured out the issue I had with reading it. Silly me, if makes it give a value to it or some statement, no statement no if.

Quote

Check for switch presses often enough. This means no delay() calls, or only minimum use of delay().

Well I only need one delay to hold the middle relay (mixing motor) on for a few minutes. I am not sure how to check for switch presses. Ideally I was aiming for one press of a button and it to run through the entire operation. Meaning you press the button, checks the weight and turns on material 1, waits until certain weight hits and cuts material1 as it starts mixing motor and relay 3 which is material 2, then when it hits the final weight turn off material 2 and keep mixing for a few minutes and shutdown awaiting another button push.

Quote

In the last code you posted, you need two calls, because the two variables that you store the result in are local variables. One goes out of scope before the other place that you need it. Unfortunately, it is possible to change the contents of buffer between calls, and get incorrect results for the second call.

Therefore you need to change the scope of the weight variable. Either move it to the top of loop, and make it static, or make it global. In this case, I'd go with global.

Understandable. So I should move that from the setup to the loop and just have it at the beginning? Not sure the difference between stating it globally or making it static.

Thanks again for the help.

RREVO

I now have it going through the proper motions for each value of weight, just it still jitters and will flash on a different relay for a split second. So I am assuming that is a result of having to reference that atoi buffer function a second time. Just need to figure that out and how to make the button do exactly what I want and I am good to go.

RREVO

Will using something like this to operate the button function to set it as more of a process work in the way I was describing earlier?

Code: [Select]
#include <Button.h>//http://www.arduino.cc/playground/uploads/Code/Button.zip

const byte ledPin = 13;
Button button = Button(12,PULLUP);

void setup(){
  pinMode(ledPin,OUTPUT); //debug to led 13
}

void loop(){
  if(button.uniquePress()){//button.isPressed() will cause the code to execute as long as button is pressed
    //enter loop code here
    digitalWrite(ledPin,HIGH);
    delay(1000);
    digitalWrite(ledPin,LOW);
    delay(1000);
    //end loop code
  }
}


Also, with your help I got the code working so that it does change through all three values, but the relays still want to flicker back and forth which I assume is the way the button is set-up currently. I will try to implement the above button code and library to see if I can get it to work the way I want it to.

Go Up