Sensor Counting Problem

Hey all, I have a project that involves typing in a number and items going through a photoelectric sensor so that it counts down on a display. The items are in a spaced out nicely. When in operation, the number on the LED display will randomly jump down two numbers (ex. 65-63). I thought it could be vibrations but it is such a quick change, I’m wondering if it’s a math problem, like maybe some floating decimals.

Below is the code. The first is for the display, the second is for the separate arduino for the sensor and keypad (connected by RX-TX).

char buffer;
int meow;

#include <Keypad.h>
#include <DMD.h> // for DMD
#include <SPI.h> // SPI.h must be included as DMD is written by SPI (the IDE complains otherwise)
#include <TimerOne.h> 
#include "SystemFont5x7.h"
#include "Arial_black_16.h"
#define DISPLAYS_ACROSS 1 // change to 2 for two screens, etc. 
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);

void ScanDMD() // necessary interrupt handler for refresh scanning of DMD
{ 
  dmd.scanDisplayBySPI();
}

void setup() {
  Timer1.initialize( 5000 );           //period in microseconds to call ScanDMD. Anything longer than 5000 (5ms) and you can see flicker.
   Timer1.attachInterrupt( ScanDMD );   //attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI()  
   dmd.clearScreen( true );
Serial.begin(9600);

}

void loop() {
if(Serial.available()){
  char buffer[Serial.available()];
  Serial.readBytesUntil('n',buffer,Serial.available());
  meow = atof(buffer);
  dmd.clearScreen( true);
  Serial.println(meow);
  
  String counterAsString = String(meow);
  char stringBuffer[6];
  counterAsString.toCharArray(stringBuffer, 6);
  dmd.selectFont( Arial_Black_16 );
  dmd.drawString(3,1,stringBuffer, strlen(stringBuffer), GRAPHICS_NORMAL);
}
delay(100);
  
}
#include <Keypad.h>

int pirPin = 10; //Sensor code
int counter = 0;//Sensor code
int laststate = HIGH; //Sensor code
int num = 0;

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
//byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
//byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad
byte rowPins[ROWS] = {5, 6, 7, 8}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {2, 3, 4}; //connect to the column pinouts of the keypad
Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup(){
  Serial.begin(9600);
  pinMode(pirPin,INPUT_PULLUP); //Sensor code
}

void loop()
{
  int v1 = GetNumber();
  Serial.println(v1);
  while (v1 > 0 )
  {
  int state = digitalRead(pirPin);
  if (laststate == LOW && state == HIGH) // only count on a LOW-> HIGH transition
  {
     v1--;
     Serial.println(v1);
  }
  laststate = state;  // remember last state
}
return;
}


int GetNumber()
{
   char key = kpd.getKey();
   while(key != '#')
   {
      switch (key)
      {            
         case '0': case '1': case '2': case '3': case '4':
         case '5': case '6': case '7': case '8': case '9':
            //Serial.println(key);
            num = num * 10 + (key - '0');
            Serial.println(num);
            break;

         case '*':
            num = 0;
            Serial.println(num);
            break;
      }

      key = kpd.getKey();
   }
   return num;
}

Can you explain what the second sketch (the keypad / PIR one) is supposed to do.

I don't understand why you are setting v1 or what it represents. It seems a strange way to count things.

Maybe you should explicitly reset lastState before you start the countdown - otherwise it may have a hangover from the previous count.

...R

GetNumber is the function (at the bottom) for the keypad where it makes a single number from a multiple digit integer (if * is pressed, then it resets to '0'/ if # is pressed then it exits the function). In the loop, I call that function after # is pressed and arbitrarily called the number v1 (nice and short). I print the number on the LED screen. While greater than 0, v1 counts down when the state of the sensor (hooked up to a digital pin) turns from a low to a high position (something passes through it) and prints it. This goes until v1 reaches 0 and you can input on the keypad again.

The items are in a spaced out nicely. When in operation, the number on the LED display will randomly jump down two numbers (ex. 65-63). I thought it could be vibrations but it is such a quick change, I'm wondering if it's a math problem, like maybe some floating decimals.

I've seen the exact same thing when working with high speed counters / FPGAs. Its why gray scale counters were invented, so only one bit switches at a time. Counting down from 64 to 63 involves 7 bits simultaneousy switching states. Oh well, its 2 different worlds - parallel execution (FPGA) vs sequential execution (MCU).

I agree about the possible math problems.

Some Comments/Questions:

  1. Can't see where negative numbers are required or dealt with. Generally, unsigned variables are used for counting.

  2. delay(100); Avoid using delay as this stops the MCU from processing for the delay period - see BWOD example for an alternative method.

  3. Use an external pullup (10K max). The internal pullup would be in the neighborhood of 50K and be more prone to noise with slower rise time. Check the photoelectric sensor's datasheet to find the max. sink current - probably a 2.2K pullup could be used for an even stronger signal.

Some questions: You are attaching an interrupt to ScanDMD ... why would this have priority over counting the sensor pulses? How long does the ScanDMD interrupt take? Can it's baud rate and the serial print baud rate be increased?

jsmiller12009:
GetNumber is the function (at the bottom) for the keypad where it makes a single number from a multiple digit integer (if * is pressed, then it resets to '0'/ if # is pressed then it exits the function). In the loop, I call that function after # is pressed and arbitrarily called the number v1 (nice and short). I print the number on the LED screen. While greater than 0, v1 counts down when the state of the sensor (hooked up to a digital pin) turns from a low to a high position (something passes through it) and prints it. This goes until v1 reaches 0 and you can input on the keypad again.

I'm not sure that is really the answer to what was in my mind.

It seems like you enter a number (any old number?) on the keypad and count down from that. Why?

You haven't dealt with my other comments.

...R

Example of use would be needing exactly 123 equal sizes boxes on a conveyor belt to a chute for delivery, and counting down from 123 boxes that pass through the sensor.

Thought that was a thorough explanation of what the sketch does. I don't really understand how else to answer your v1 question.

dlloyd:
Some Comments/Questions:

  1. Can't see where negative numbers are required or dealt with. Generally, unsigned variables are used for counting.

  2. delay(100); Avoid using delay as this stops the MCU from processing for the delay period - see BWOD example for an alternative method.

  3. Use an external pullup (10K max). The internal pullup would be in the neighborhood of 50K and be more prone to noise with slower rise time. Check the photoelectric sensor's datasheet to find the max. sink current - probably a 2.2K pullup could be used for an even stronger signal.

Some questions: You are attaching an interrupt to ScanDMD ... why would this have priority over counting the sensor pulses? How long does the ScanDMD interrupt take? Can it's baud rate and the serial print baud rate be increased?

My apologies, I failed to mention my novice-level programming abilities.

  1. If you're asking how it's counting down, it just increments down from v1.

  2. Is this the best thread to scan through for info on BWoD?
    http://forum.arduino.cc/index.php?topic=223286.0

  3. Does that involve throwing a resistor in series with the voltage wire of the sensor?

As for the ScanDMD, that was code straight from the display's website that basically states it as mandatory

My apologies, I failed to mention my novice-level programming abilities.

A novice here too.

  1. If you're asking how it's counting down, it just increments down from v1.

I would consider using "unsigned" when declaring variables used for counting or timing. This can prevent issues when "sign" bit is not considered (or required) in your code.
Some suggested data types:

unsigned int pirPin = 10; //Sensor code
unsigned long counter = 0;//Sensor code
boolean laststate = HIGH; //Sensor code
unsigned long num = 0;
...
unsigned long v1 = GetNumber();
...
boolean state = digitalRead(pirPin); 
...
unsigned long GetNumber()
  1. Is this the best thread to scan through for info on BWoD?
    http://forum.arduino.cc/index.php?topic=223286.0

An excellent thread, also this link.

  1. Does that involve throwing a resistor in series with the voltage wire of the sensor?

No, if your Arduino has 5V logic levels, then one end connected to 5V and the other to the input pin.
Then use: pinMode(pirPin,INPUT); //Sensor code

Note: The ScanDMD display looks like it's power hungry ... you may need to use a separate power source if not already doing so.

jsmiller12009:
Example of use would be needing exactly 123 equal sizes boxes on a conveyor belt to a chute for delivery, and counting down from 123 boxes that pass through the sensor.

That helps to make sense of what is going on. I presume your getNumber() function works properly so the problem has to be in this code

void loop()
{
  int v1 = GetNumber();
  Serial.println(v1);
  laststate = HIGH;        // <--------- would it help to add this line
                                            //                      I mentioned it earlier but you did not comment on it
  while (v1 > 0 )
  {
	  int state = digitalRead(pirPin);
	  if (laststate == LOW && state == HIGH) // only count on a LOW-> HIGH transition
	  {
		 v1--;
		 Serial.println(v1);
	  }
	  laststate = state;  // remember last state
  }
return;  //  <----------------- this is unnecessary
}

Look at the 2 comments I have added.

Can you identify where in the sequence the counting goes wrong, or can it happen anywhere?

If it is happening anywhere then I suggest you write a separate short sketch to test your detector. It would simply count indefinitely and show the values on the Serial Monitor.

…R

Robin2:
Look at the 2 comments I have added.

Can you identify where in the sequence the counting goes wrong, or can it happen anywhere?

If it is happening anywhere then I suggest you write a separate short sketch to test your detector. It would simply count indefinitely and show the values on the Serial Monitor.

...R

I could definitely try resetting lastState to high after each count. But I think the return is necessary to be able to use the keypad when count reaches 0 without resetting the arduino altogether. I can awful at explanations: like stated it would increment down 123 boxes, and then maybe shortly afterwards it would need to do the same with 134 boxes. The errors though, they happen for each set, including the first one after the arduino is fired up for the first time that night, and happen in a random order (actual example- on a 84 box set: 72-70, 58-56, 38-36, 32-30, 27-25, 21-19, 15-13, 10-8, 5-3)

dlloyd:
I would consider using "unsigned" when declaring variables used for counting or timing. This can prevent issues when "sign" bit is not considered (or required) in your code.
Some suggested data types:

unsigned int pirPin = 10; //Sensor code

unsigned long counter = 0;//Sensor code
boolean laststate = HIGH; //Sensor code
unsigned long num = 0;
...
unsigned long v1 = GetNumber();
...
boolean state = digitalRead(pirPin);
...
unsigned long GetNumber()




http://forum.arduino.cc/index.php?topic=223286.0

An excellent thread, also this link.

No, if your Arduino has 5V logic levels, then one end connected to 5V and the other to the input pin.
Then use: pinMode(pirPin,INPUT); //Sensor code

Note: The ScanDMD display looks like it's power hungry ... you may need to use a separate power source if not already doing so.
[/quote]

Thanks, I will definitely try these suggestions, but a quick question as to the one you might think is causing the biggest problem to my count

Thanks, I will definitely try these suggestions, but a quick question as to the one you might think is causing the biggest problem to my count

I would create a short test sketch as Robin2 suggested, then take it from there.
All I can guarantee, is that it will be the last thing you try that will solve the problem :wink:

jsmiller12009:
(actual example- on a 84 box set: 72-70, 58-56, 38-36, 32-30, 27-25, 21-19, 15-13, 10-8, 5-3)

Am I correct to assume all these errors occurred in a single countdown from 84?

It looks like there may be a pattern in those numbers.

Do you get the same data everytime you try to count down from 84?

Edit to add ...

I don't have a PIR sensor so I just made a short sketch with the code from Reply #8. Instead of int v1 = GetNumber(); I just had int v1 = 12; (also tried 84) and it counts down properly.

Then I looked again at the code ...
There are 2 successive lines (from your original code)

v1--;
Serial.println(v1);

With those two lines it should be IMPOSSIBLE to skip numbers unless something very strange is happening. If the PIR was misbehaving you might not be counting the correct number of boxes but there would be NO MISSING NUMBERS on your serial monitor.

So start looking for the solution elsewhere. I don't know if this sort of problem could happen if the Arduino browns-out - perhaps because too much current is drawn from the 5v pin. A faulty USB connection might be another possibility - some data simply is not being received by your PC.

Also, though less important

But I think the return is necessary

. I said earlier it is NOT necessary. Every function automatically returns when it finishes.

...R

Pullup resistor on sensor input (use anything from 1K to 10K):

If the pullup doesn't work, you could try disconnecting your display, then edit your code to view the sensor count in the serial monitor to see if the problem goes away.

EDIT: Another thing to check is grounding. To avoid ground loops, use separate ground wires attached to a common point. Avoid using jumpers from one ground terminal to another (avoid ground connections in series).

1 Like

dlloyd:
Pullup resistor on sensor input (use anything from 1K to 10K):

...SNIP...

The symptons that the OP has reported CANNOT be caused by inadequate pullup resistors or ground loops.

Both of those issues could cause the Arduino to count the boxes wrongly, but that is not the reported problem The reported problem is that the countdown is missing values.

...R

1 Like

The symptons that the OP has reported CANNOT be caused by inadequate pullup resistors or ground loops.

Both of those issues could cause the Arduino to count the boxes wrongly, but that is not the reported problem The reported problem is that the countdown is missing values.

Sure enough, there is probably one main cause to the problem, but if there are are a few things that could be done to improve the circuit, or a few easy tests to try, why not?

Scenario (just a guess of course):

The grounding uses a series of jumpers, the display is power hungry, the sensor is using a weak internal pullup (prone to noise). As it stands, the count skips certain values.

Well, I propose that the noise on the system and current draw from the display is also repetitive and related to the count value. Just looking at one character, how many pixel LEDs are fired to display "0" as opposed to "1"? I propose that the Arduino's supply voltage could have noise, dips and sags due to periodic overloading.

If the sensor is open-drain or open-collector type, it's signal would easily be influenced by the repetitive nature of the load noise, power supply fluctuations, etc. This weak signal may not be the actual CAUSE of the problem, but a strong signal here would be beneficial with improved rise time, voltage levels and noise immunity.

To me, disconnecting the display (and removing it's code) as a test to see if the problem goes away, improving the sensor signal and eliminating ground loops are valid things to try. Also, using a separate supply for the display (if not already done) would be advisable (IMHO).

1 Like