Reading digital Input and entering if

Hello Arduino-Community!

Me and some friends are building an RGB-LED table with a 10x10 matrix.

I am writing a programm that adds a touch function to the table. The programm switches different channels on a multiplexer and reads the signal on an input pin. On each channel there is an IR-Sensor. If the sensor receives a signal it returns a 0 or LOW.

The fuction xOn() generates a 38kHz signal and returns the opposite value of the sensor pin, since the pin is LOW, when a signal is detected.

Now I want to go through the x-Axis and check whether it is on or not. If it is, I will go through the y-Axis and check which field is on.

I am storing the return value of xOn() into xState, because I need that value later on in the program and don't want to call that function over and over again.

When xState is true, the program should enter the if part. This however, only works if I print something on the Serial Monitor or if I delay the programm after storing xOn() in xState. When I leave out "Serial.println("Doing something");", the program always enters the if.

Do you have an idea why the program behaves like this? I don't want to use delay() or use Serial.print because the RaspberryPi is always sending information to the Arduino and delay() would cause the buffer to fill and it's also reading the Serial Monitor that tells when a field on.

Right now I am testing with a 2x2 field. I included the whole program to this post.

void loop()
{
  int ix = 0;
  boolean xState = 0;
  
  for (ix = 0; ix < 2; ix++)
  {
    xChannel(ix);
    xState = xOn();
    Serial.println("Doing something"); //For delaying program, so it can enter if? Could also use delay();
    if (xState)
    {
      Serial.println("xState was true");
    }
  }    
}

IRTouch.ino (3.39 KB)

for (int i = 0; i <= 38; i++) // 39*26ms=1014µs

I'm not sure if the extra cycle is significant, but your arithmetic is incorrect.

int xChannel (int iNumber) // Select x-Axis on Multiplexe
{
  
  int ib0 = bitRead(iNumber, 0);
  int ib1 = bitRead(iNumber, 1);
  int ib2 = bitRead(iNumber, 2);
  int ib3 = bitRead(iNumber, 3);

I can't see the point of zeroing a variable, then immediately overwriting it.

nt ixField = 2;
int iyField = 2;

//String sMessage; //Will be sent to Python

//Field as 2D-Array with x, y-Axis , starts at 0.
boolean bField[1][1];

OOps.
Never write to memory you don't own.

And please, don't post snippets that don't compile

While we're on the subject of things never to do, never write a function that is supposed to return a value that does not include a return statement.

int xChannel (int iNumber) // Select x-Axis on Multiplexe
{
  int ib0 = 0, ib1=0, ib2=0, ib3=0; // Write iNumber as Bits 
  ib0 = bitRead(iNumber, 0);
  ib1 = bitRead(iNumber, 1);
  ib2 = bitRead(iNumber, 2);
  ib3 = bitRead(iNumber, 3);
  
  // Enable the Pins that store a 1
  digitalWrite(xA, ib0);
  digitalWrite(xB, ib1);
  digitalWrite(xC, ib2);
  digitalWrite(xD, ib3);
}

Since bitRead() returns either 0 or 1, is there some reason you need 8 bytes to store 4 bits? Is there some reason this function isn't a void function? Is there some reason to store the bits anywhere?

Hello,

thanks for the replies.

AWOL:

i

nt ixField = 2;
int iyField = 2;

//String sMessage; //Will be sent to Python

//Field as 2D-Array with x, y-Axis , starts at 0.
boolean bField[1][1];



OOps.
Never write to memory you don't own.

And please, don't post snippets that don't compile

What do you mean with memory I don't own?
I am declaring the Field globally so every function can access the information of whether a field is on or off.

I changed the xChannel and yChannel function to a void and wrote the bitRead() directly to the output pin without storing its value.

The program still enters the if.

What do you mean with memory I don't own?

I mean memory that you haven't declared you are going to use.
boolean bField[1][1];and boolean bColumn[1];
Then later

void FieldZero() //Set entire field and column to 0.
{
  for (int i = 0; i < ixField; i++)
    {
      bColumn[i] = 0;
      for (int j = 0; j < iyField; j++)
      {
        bField[i][j] = 0;
      }
    }
}

where

//Size of Field
int ixField = 2;
int iyField = 2;

But declaring an Array like this

boolean bColumn[1];

creates an array that can store 2 elements, right?
For example:

bColumn[0] = 1;
bColumn[1] = 0;

When setting the field to 0, I am using a for loop, that runs until i < ixField. ixField is 2, so it should only run twice, until i=1.

for (int i = 0; i < ixField; i++)

boolean bColumn[1];
creates an array that can store 2 elements, right?

Wrong.

I changed

That means you need to re-post your code.

So creating an array like this would be valid?

boolean bColumn[2];

for (int i = 1; i<=2; i++)
{
  bColumn[i] = 0;
}

I changed the array size to 2 and in the FieldZero() function I start the counter at 1 and count until i<=ixField.

The xChannel() and yChannel() functions now look like this:

void xChannel (int iNumber) // Select x-Axis on Multiplexer
{

  digitalWrite(xA, bitRead(iNumber, 0));
  digitalWrite(xB, bitRead(iNumber, 1));
  digitalWrite(xC, bitRead(iNumber, 2));
  digitalWrite(xD, bitRead(iNumber, 3));
}

I included the sketch to this post.

IRTouch2.ino (3.11 KB)

start the counter at 1 and count until i<=ixField.

Which is still accessing memory you don't own.
The correct form is i < ixField

A "for" loop is "while", not "until", <= 2 includes 2, so is incorrect.

I changed the array size to 2

And still write to positions 1 and 2 of 1. Array indices start at 0.

Ok, now it's like this:

//Size of Field
int ixField = 2;
int iyField = 2;

boolean bField[2][2];
//Saves if element of Column is 1
boolean bColumn[2];

void FieldZero() //Set entire field and column to 0.
{
  for (int i = 0; i < ixField; i++)
    {
      bColumn[i] = 0;
      for (int j = 0; j < iyField; j++)
      {
        bField[i][j] = 0;
      }
    }
}

IRTouch3.ino (3.1 KB)

const int ixField = 2;
const int iyField = 2;

boolean bField[iyField][ixField]; //or maybe vice versa

Is much easier to keep track of things and keeps code consistent.

I just had another look at your "Pulse()" function.
I think you should too.

I replaced the if {...} else {...} part with a toggle in the Pulse() function.

      ledState=!ledState;

instead of:

      if (ledState == LOW)
        ledState = HIGH;
      else
        ledState = LOW;

Is there another problem with the function?
After 13 µs have passed, it changes the LED status. This is supposed to create a 38kHz signal.

Also I define the length of the arrays like you suggested with ixField and iyField.

IRTouch4.ino (3.08 KB)

Is there another problem with the function?

Yes, the "for" loop.
Walk through it in your head, or with a pencil and paper.
Let's say "i" is zero and current minus previous is greater than "interval".
So, do all the time storing, LED state flipping and digital writing, and go back to your "for".

The remaining 38 iterations aren't going to take very long at all.

When the programm is entering the Pulse() function, current minus previous is probably greater than interval, so it will switch the LED. This happens in the first run of the for loop.

Then I guess, the for loop increases i without entering the if part, because current minus previous is not greater than interval. So the LED is not turned on and off 39 times? I also thought of this earlier, but I copied most parts of it from the internet and replaced the delay() parts with current and previous from the example library.

But actually, running Pulse by calling SendDelayedPulse and reading the input pin afterwards works. When there is an obstacle like a hand that reflects the IR Signal, the input pin is LOW, as it should be..

Are there any ideas about why the if-part (line 70) only works properly when there is a Serial.print() or delay(). Without, the programm always enters the if, no matter what xState is.

IRTouch4.ino (3.08 KB)

  int ix;
  
  for (ix = 0; ix < 2; ix++)

Why is ix declared outside of the for statement?

Why are you mixing millis() and micros() calls in SendDelayedPulse() and Pulse()?

In Pulse(), it is NOT waiting between iteration of the for loop.

Some comments in the code explaining what you expect the code to do would be useful. What IS Pulse() supposed to do?

Pulse() generates a 38kHz square Wave for the infrared LED, because the IR Sensor reacts to this frequency.
To create that 38kHz, I am toggling the IR LED every 13µs, which is half of one period.

Millis() in SendDelayedPulse is needed by the IR Sensor. Because it needs time to reset, I think. When I leave it out, the Sensor is always returning that it's receiving a signal, even if there is no signal.

I now declare ix in the for loop.

To create that 38kHz, I am toggling the IR LED every 13µs, which is half of one period.

You have proof of this?
I thought we'd discounted that argument?