Multiple Digital inputs

I am fairly new to coding and I am wondering the best way to approach reading several inputs at a time. I have an application with 9 digital inputs so I will have several digitalRead in my loop. They will be connected to sensors that are counting each time one of the 9 are triggered. I need some thing like:
digitalRead(LC1, LC2, LC3…)
if val of (LC1, LC2, LC3…) == HIGH
count++

You could use interrupts so you don’t have to poll the sensors continuously. Also, if you don’t care which input gets triggered, you might be able to connect them to a single pin and just use that.

What exactly are you trying to achieve?

It’s being used as a counter for a machine processing food, the machine has 8 lanes with 8 photoelectric sensor. The other input is a proximity sensor that will initiate the start of a new cycle. each cycle I need all 8 sensors to read whether high or low, if high there is a piece of fruit present, if low that lane is empty etc.

int LaneCount1 = D0;
int LaneCount2 = D1;
int LaneCount3 = D2;
int LaneCount4 = D3;
int LaneCount5 = D4;
int LaneCount6 = D5;
int LaneCount7 = D6;
int LaneCount8 = D7;
int CycleCount = A0;
//functions
int val = LOW; //variable for reading pin status of Prox
int val2 = 0; //variable for reading photoelectric
int counter = 0;
int currentState = 0;
int previousState = 0;

void setup(){
//we are going to tell our device that D0-D7 and A0 are going to be inputs
  pinMode(LaneCount1, INPUT);
  pinMode(LaneCount2, INPUT);
  pinMode(LaneCount3, INPUT);
  pinMode(LaneCount4, INPUT);
  pinMode(LaneCount5, INPUT);
  pinMode(LaneCount6, INPUT);
  pinMode(LaneCount7, INPUT);
  pinMode(LaneCount8, INPUT);
  pinMode(CycleCount, INPUT);

It depends on what exactly the process should look like. If you want a simple count of all the pieces of food that have gone through the machine (regardless of what lane they were in), then a single interrupt should work. Each time a sensor is triggered, you increase the value of your counter.
If you want to know the amount per lane, then you’d need separate interrupts, each with their own counter.
For the interrupts, you can have a look over here: https://docs.particle.io/reference/firmware/photon/#interrupts

While you don’t have to use interrupts, and polling should work as well, it’s generally nicer to listen to events, rather than having to ask “has something happened already?” the entire time, which is what polling does.

That said, polling might work just fine for this application. I’ll assume you need to wait until all lanes are filled before starting a new cycle?

A general tip (which I’m sure @ScruffR would tell you if I don’t), is that you should look to compact/re-use pieces of code you’re using multiple times. Creating all those variables, or setting all the pins, could be done inside an for loop, iterating through an array of the pins.

Take a look into these things, and let us know if you need further help.

2 Likes

Ok thank you so much, since i’m just trying to get a count for the over all machine the interrupts look like a good solution.

1 Like

@Moors7 and @dtuttoil, interrupts may not be the best approach. This is due to two conditions:

  1. The lane detectors are asynchronous and could trip at the same time, or not
  2. The Photon does not have 8 independent interrupt pins. All have EXTI lines that are shared so only one can work at a time. This reduces the total independent pins to 4.

As such, to prevent missed interrupts, it may be better to sample the sensors in a timer (say every 1ms) or in loop(). You can maintain an array of pin values and simply monitor the transitions from LOW to HIGH to increment your counters. If I think like @ScruffR, I would make a simple array of structures where the pin state and the product count for each lane is maintained. :wink:

2 Likes

Well I added the Proximity sensor to my design so I would have the ability to tell the photoeyes to look at a certain time. A lot of our machines run at different speeds so there isn’t a way to use a set value of time, i.e. every 1 ms take a sample. I was trying to approach it as an if statement.
void loop() {
val = digitalRead(ProxSens);
if val == HIGH
Then gather a count from my 8 photoeye sensors, anytime the prox is high there should be fruit in the pockets

@peekay123, the 1ms sampling time was just one possible approach. It is very dependent on speed at which the sensors are tripped.

If will need to consider that you are considering that you can only count the fruit once, so you will need to monitor when the sensor returns to "empty" before allowing it to trigger again. For this, you should create a small state machine which says "if the sensor was LOW and now it is HIGH, there is a fruit in the pocket so count it". Then "if the sensor was HIGH and is now HIGH do nothing" and "if the sensor was HIGH and now is LOW, get set for next fruit".

Is it safe to assume there can only be ONE fruit within a pocket?

Like @peekay123 said there are more than one way to skin a cat, but this is what he is talking about.
Keep in mind that this solution wont work for multiple inputs because after you trigger on the one, you will be stuck there until its changes state back thus missing the rest. So you need to get creative here.
You might want to look into Timers. With them you can have a function fire at a specific time to check an input.
https://docs.particle.io/reference/firmware/photon/#software-timers

void loop() 
{

	// Is prox sensor high? 
	if( digitalRead(ProxSens) )
	{
		// Add an apple
		apples++;
		
		// Now stay here while the signal is low
		// So we dont keep adding apples
		while( !digitalRead(ProxSens) )
			delay(1);
			
	}

}
1 Like

@seulater you have the right idea but using an FSM, you can create a non-blocking way to look for the change of state. By sampling each pin into an array of structures which holds the pin number, the pin previous state and the event count, it would be straight forward to go through the array, reading each pin, comparing the current and previous pin states and acting accordingly for each pin.

1 Like

@peekay123, Yup that is exactly how I have done it in the past, just was getting her a little more up to speed in smaller steps first :wink:

1 Like

I'm not convinced that's actually true. I'd have to look into this a bit deeper, but I'm pretty sure there are more than just 4 EXTI lines.
I'd say there are 11 independent EXTI interrupts.

https://docs.particle.io/reference/firmware/photon/#interrupts

With 18 GPIO pins minus these two and the shared lines for five other pins that leaves you with 11.

@ScruffR,

Also please note following are the pins for which EXTI lines are shared so only one can work at a time:
D1, A4
D2, A0, A3
D3, DAC
D4, A1

The interrupts share an EXTI line so they are not truly independent. The implication is that simultaneous interrupts on the pins may not be seen as two interrupts. The interrupt status register may show both being triggered and if I recall, the HAL interrupt handler will cycle through the register and call the ISR for each “active” bit in the status register. This is why there is a 5-8us latency overhead on these interrupts.

However, you are correct that other pins such as WKP, RX, TX, etc. could be used as well so I stand corrected and there should be 8 pins available for the task.

I’m still standing with 11.
18 pins (D0~D7, A0~A7, RX, TX) minus D0, A5, A4, A0, A3, DAC/A6, A1 leaves me with 11 not 8.
D1, D2, D3, D4 should still be counted as independent as long none of the “connected” pins are used for interrupts.

2 Likes

Yes it is safe to assume that there will only be one piece of fruit in the pocket at a time

1 Like

Ok I tried to approach this as if it were in Matlab, I am use to the Matlab platform. I know I can’t index the same in the particle platform. I am trying to simplify this so it’s taking just cycle count and total count for all lanes in one go. Can anyone give me a suggestion on how to index these variables?

//photoelectric counter


int LaneCount(1) = D7;
int LaneCount(2) = D7;
int LaneCount(3) = D7;
int LaneCount(4) = D7;
int LaneCount(5) = D7;
int LaneCount(6) = D7;
int LaneCount(7) = D7;
int LaneCount(8) = D7;
int CycleCount = A0;
int val = 0; //variable for reading pin status
int LC = 0; //counter variable for dectection

void setup() {
  pinMode(LaneCount(1), INPUT);
  pinMode(LaneCount(2), INPUT);
  pinMode(LaneCount(3), INPUT);
  pinMode(LaneCount(4), INPUT);
  pinMode(LaneCount(5), INPUT);
  pinMode(LaneCount(6), INPUT);
  pinMode(LaneCount(7), INPUT);
  pinMode(LaneCount(8), INPUT);
  pinMode(CycleCount, INPUT);
  
  Serial.begin(9600);
}

void loop() {
  val = digitalRead(CycleCount);
  if (val == HIGH) {
    Cycle = Cycle+1
    digitalRead(LaneCount(1));
    digitalRead(LaneCount(2));
    digitalRead(LaneCount(3));
    digitalRead(LaneCount(4));
    digitalRead(LaneCount(5));
    digitalRead(LaneCount(6));
    digitalRead(LaneCount(7));
    digitalRead(LaneCount(8));
    for (i = 1; i < 9; i++)1{
      if (LaneCount(i)==HIGH) {
        LC(i)=LC(i)+1
      }
    }
    
    Particle.publish("fruit_detect", String(LC(i))); //publish event and count
  }
}

In C/C++ arrays are created like this

int laneCount[8];

the index starts with 0 and goes to item count-1.

For the pinMode() setup you’d do this

  for (int i = 0; i < 8; i++)
    pinMode(laneCount[i], INPUT);

If you want to be flexible with the number of items in the array you could do this

int laneCount[] = { D0, D1, D2, D3, D4 };  // add as many pins you want without having to change the code bellow
int numLanes = sizeof(laneCount) / sizeof(laneCount[0]);
...
  for (int i = 0; i < numLanes; i++) 
    pinMode(laneCount[i], INPUT);
4 Likes

Ok so I have gotten my code to the point that I am getting the correct readings from my Prox sensor but I can’t get a count from my Photoeyes. Right now I only have one photoeye wired in on D7 so ideally I should be seeing my data publish every 5 cycle counts with a count for me triggering the Photoeye in D7. Something along the lines of “fruit_detect 5,0,0,0,0,0,0,0,5”. However, no matter how many times I trigger the photoeye I keep getting the following results, any ideas on what’s causing the 0, 1, 2, 3, 4, 5, 6, 7 to populate instead of actually reading my input?

    //photoelectric counter
    const int NumberOfLanes = 8;
    int LaneSensor[] = { D0, D1, D2, D3, D4, D5, D6, D7 };
    int ProxSensor = A0;
    int Cycle = 0;
    int val = 0; //variable for reading pin status
    int LaneCount[NumberOfLanes]; //counter variable for dectection
    int CycleSensorDebounce = 0;

    void setup()
    {
      for (int i = 0; i < NumberOfLanes; i++)
      {
        pinMode(LaneSensor[i], INPUT_PULLDOWN);
      }
      pinMode(ProxSensor, INPUT_PULLDOWN);

      Serial.begin(9600);
      initializeLaneCount();
    }

    void initializeLaneCount()
    {
     for (int i = 0; i < NumberOfLanes; i++)
      {
        LaneCount[i] = 0;
      }
      Cycle = 0;
    }

    String PublishLaneCount()
    {
      String StringReturn = String(Cycle);
      for (int i = 0; i < NumberOfLanes; i++)
      {
        StringReturn += " ," + String(LaneSensor[i]);
      }
      return StringReturn;
    }

    void loop()
    {
      val = digitalRead(ProxSensor);
      if (val == 0)
      {
        CycleSensorDebounce = 0;
      }
      else
      {
        if (5 >= CycleSensorDebounce);
        {
         CycleSensorDebounce++;
          if (5 == CycleSensorDebounce)
          {
            Cycle++;
            for (int i = 0; i < NumberOfLanes; i++)
            {
              val = digitalRead(LaneSensor[i]);
              if (val == 1)
              {
                LaneCount[i] = LaneCount[i] + 1;
              }
            }
            if (Cycle%5 == 0)
            {
              Particle.publish("fruit_detect", PublishLaneCount()); //publish event and counter
            }
          }
        }
      }
    }

In your PublishLaneCount function you are making a string of the LaneSensor array which above you declared to be the pins that the sensors are connected to, which happen to be integer values. You need to add a digitalRead(LaneSensor[i]) some where. All that String construction and concatenation can cause memory problems on small micros like this, so a global char array might be better in the long run, but this will be OK to get started.

2 Likes

I have a digitalRead(LaneSensor[i])