Need to run program twice to make it work (Newline vs No Line Ending)

Hey,

this is my very first post in this forum, I hope I don’t mess this up.

Short summary of my project and what already works:

  • I want a user to provide an input (number) to the serial monitor.
  • For this I was basically following: Robin2’s amazing post for retrieving a single digit (i.e., Example 4).
  • I also attached some IR breakbeam sensor.
  • I can count the number of times the sensor is broken up unto the provided user input number

The problem is; I need to do this operation twice, if I set the line ending to Newline. If I set it to No Line Ending then it works. However, No Line Ending works only for the first digit that is provided. Subsequent inputs are not recognized.

What is the issue here for Newline?

Thank you!

// =============================================
// IR PART
// =============================================
// IR Breakbeam Sensor Definitions
#define SENSORPIN 4
 
// IR breakbeam sensor state variables
int currentSensorState = 0, lastSensorState = 0; // either LOW or HIGH (i.e., 0 or 1. NB: LOW means beam is broken, HIGH means unbroken)

// IR counter
int counter = 0;
bool isCounting = false;


// =============================================
// SERIAL INPUT PART
// =============================================
char receivedChars[32];
bool newData = false;
int dataNumber = 0; 

 
void setup() {    
  // initialize the sensor pin as an input:
  pinMode(SENSORPIN, INPUT);     
  digitalWrite(SENSORPIN, HIGH);
  
  Serial.begin(9600);
  Serial.println("Arduino Ready");
}
 
void loop(){

  // check & receive new user input, newline should be used as EOL (LF)
  if (Serial.available() > 0) {
      // get serial input
      recvWithEndMarker();
      // cast input to int
      dataNumber = atoi(receivedChars);

      // enable counting mode
      isCounting = true;

      newData = false;
  }
  


  while (isCounting) {

    // --------------------------------------------------------------------------------------------------
    // Sensor Algorithm
    // --------------------------------------------------------------------------------------------------
    // read the current sensor state
    currentSensorState = digitalRead(SENSORPIN);
    // if there is a diff in currentSensorState and lastSensorState
    if (currentSensorState == HIGH && lastSensorState == LOW) {
      Serial.println("Unbroken");
    } 
    if (currentSensorState == LOW && lastSensorState == HIGH) {
      Serial.println("Broken");
      
      // if beam is broken we can assume that an object is blocking it, so incrementing the counter
      counter += 1;
    }
    // --------------------------------------------------------------------------------------------------
  
    Serial.println(counter);
    
    // synchronize states (this should be at the end)
    lastSensorState = currentSensorState;

    // reset isCounting when reached the counter
    if (dataNumber == counter) {
      Serial.println("Done Counting");
      isCounting = false;
      // reset counter to 0 to prepare for next runs
      counter = 0;
    }
  }
}



void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;
 
  rc = Serial.read();

  if (rc != endMarker) {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= 32) {
          ndx = 32 - 1;
      }
  }
  else {
      receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;
      newData = true;
  }
}

And then your hit 'post' and had to wait 5 minutes to tell us the rest of the story.

char receivedChars[32];

You should use a constant (or #define) for the size of the array so that when you decide to modify it, these values

if (ndx >= 32) {
          ndx = 32 - 1;
      }

change automatically as well.

I know I would mess it up! Sorry for that!

I purposely stripped out the part:

const byte numChars = 32;

from the example, as I will never ever change this.

The endmarker is specified here char endMarker = '\n';So the code should work with 'newline' as a line ending only. But you must have deviated from the original code by Robin here:

if (Serial.available() > 0) {
      // get serial input
      recvWithEndMarker();
      // cast input to int
      dataNumber = atoi(receivedChars);

      // enable counting mode
      isCounting = true;

      newData = false;
  }

The casting of the receivedChars in to dataNumber should only occur if (newData == true) And the same goes for the setting of isCounting, and the resetting of newData to false.
It would be better to have your whole counting routine in a separate function, and as far as i can tell if  (isCounting) { should suffice. (leaving the option of altering the dataNumber while counting, though then you should test it with a >= not just ==)

I recorded the issue maybe this is easier to follow...I recorded the issue maybe this is easier to follow...

Nope !

I haven't worked with arduino for a while but I don't understand this

  pinMode(SENSORPIN, INPUT);     
  digitalWrite(SENSORPIN, HIGH)

Thanks Deva_Rishi, I had something to do with the newdata chunk. For the sake of solving this issue, here is some working code for counting to a number by user provided input:
arduino-dispenser/arduino-dispenser.ino at 12c2708a1c494f8519f343c02c3fcd5da6ace59c · ccp-eva/arduino-dispenser (github.com)

kubajz22:
I haven't worked with arduino for a while but I don't understand this

  pinMode(SENSORPIN, INPUT);

digitalWrite(SENSORPIN, HIGH)

It's old way of enabling the internal pullup; nowadays most use pinMode(SENSORPIN, INPUT_PULLUP).

sterretje:
It's old way of enabling the internal pullup; nowadays most use pinMode(SENSORPIN, INPUT_PULLUP).

Ahh. This came with some Adafruit Examples. So

pinMode(SENSORPIN, INPUT_PULLUP);

replaces:

digitalWrite(SENSORPIN, HIGH);

?

pinMode(SENSORPIN, INPUT_PULLUP);

replaces:

  pinMode(SENSORPIN, INPUT);
  digitalWrite(SENSORPIN, HIGH)

Thank you guys!

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.