How can I connect an 8x8 matrix of LDR sensors to Arduino?

Hello everyone,

I need to know how can I connect 64 LDR (8 rows x 8 columns) to an Arduino Uno. I've searched a bit and I've found the analog multiplexer 74HC4067, which has 16 channels. With 4 of these multiplexers I guess it would work. How do you connect them? Would there be any inconvenience?

Another idea is to use two 74HC4051 (8-channel multiplexer), one connected to the 8 rows (connecting each row to the negatives poles of the LDR) and another connected to the 8 columns (connecting each column to the positive ones of the LDR). Is this sunctional?

I have some MCP23017, but from what I've seen they can only be used as digital inputs. Could they be used in some way as analog inputs?

The Arduino Leonardo has more analog inputs, for a matrix of 8x8 without extra hardware.
The Arduino Uno with one or two 8-channel muxes might also work.
Without diodes there is a path via the other rows, other LDRs and other columns. That is not accurate.
I think you need diodes with every LDR, but I am not sure. Perhaps the final value can be calculated when all values are known.

Here is a project with a matrix of pressure sensors: https://reps.cc/?p=50. The schematic is half way on that page. The columns are digital signals.

Multiplexer tutorial: https://www.gammon.com.au/forum/?id=11976.

Can you tell what your project is ?
How accurate should it be ?
How fast do you want to read all 64 values ?

I would recommend an Arduino with at least 8 analog inputs, then use 8 8-to-1 analog multiplexers. If you are stuck with 16-to-1 multiplexers, then you only need four analog inputs. Typically you want to setup your circuit so it works with a voltmeter and then substitute the ADC in place of the voltmeter. The first options does this, the second does not. You may have to rework the design to make the second one work (or it may never work).

Koepel:
The Arduino Leonardo has more analog inputs, for a matrix of 8x8 without extra hardware.
The Arduino Uno with one or two 8-channel muxes might also work.
Without diodes there is a path via the other rows, other LDRs and other columns. That is not accurate.
I think you need diodes with every LDR, but I am not sure. Perhaps the final value can be calculated when all values are known.

Here is a project with a matrix of pressure sensors: https://reps.cc/?p=50. The schematic is half way on that page. The columns are digital signals.

Multiplexer tutorial: Gammon Forum : Electronics : Microprocessors : 74HC4051 multiplexer / demultiplexer.

Can you tell what your project is ?
How accurate should it be ?
How fast do you want to read all 64 values ?

Thanks for your answer.

My project is a chess robot and I want to detect if a square is occupied by a piece. It should be accurate. It doesn't need to be checking the status of the chessboard all the time, but probably every 2 seconds to know if there is a change in the position.

Is using the Arduino Uno mandatory ? You better use another Arduino board.

I did a simulation test in Tinkercad.com with an Arduino Uno and 4x4 matrix of LDR without and with diodes.

Without diodes:

With one column 5V and the other columns open.

All LDRs dark:
54, 54, 54, 54,
54, 54, 54, 54,
54, 54, 54, 54,
54, 54, 54, 54,

One LDR gets full light:
963, 88, 88, 88,
54, 54, 54, 54,
54, 54, 54, 54,
54, 54, 54, 54,

With one column 5V and the other columns 0V.

All LDRs dark:
47, 47, 47, 47,
47, 47, 47, 47,
47, 47, 47, 47,
47, 47, 47, 47,

One LDR gets full light:
960, 46, 46, 46,
3, 54, 54, 54,
3, 54, 54, 54,
3, 54, 54, 54,
(perhaps I have made a mistake here and the "54" should be "47" ?)

Then I tried to add diodes to every LDR:

With one column 5V and the other columns open.

All LDRs dark:
49, 49, 49, 49,
49, 49, 49, 49,
49, 49, 49, 49,
49, 49, 49, 49,

One LDR gets full light:
869, 49, 49, 49,
49, 49, 49, 49,
49, 49, 49, 49,
49, 49, 49, 49,

With one column 5V and the other columns 0V.

All LDRs dark:
49, 49, 49, 49,
49, 49, 49, 49,
49, 49, 49, 49,
49, 49, 49, 49,

One LDR gets full light:
869, 49, 49, 49,
49, 49, 49, 49,
49, 49, 49, 49,
49, 49, 49, 49,

That confirms that the diodes do help. Without diodes and setting the other columns LOW (0V), the change to the other LDRs is only a little. Perhaps that is good enough. Perhaps someone can make a calculation to get rid of it.

const int n = 4;   // matrix size

// columns are digital pins
const int colPins[n] = { 8, 9, 10, 11 };

// rows are analog inputs with 10k resistor to GND.
const int rowPins[n] = { A0, A1, A2, A3 };

int ldr[n][n];

void setup()
{
  Serial.begin( 9600);
  Serial.println( "LDR Matrix sketch");
  
  for( int i=0; i<n; i++)
  {
//    pinMode( colPins[i], INPUT);
    pinMode( colPins[i], OUTPUT);
    digitalWrite( colPins[i], LOW);
  }
}

void loop()
{
  // retrieve all LDR values.
  fillLdrMatrix();
  
  // print all LDR values.
  Serial.println( "----------------");
  for( int i=0; i<n; i++)
  {
    for( int j=0; j<n; j++)
    {
      Serial.print( ldr[i][j]);
      Serial.print( ", ");
    }
    Serial.println();
  }
  
  delay( 1000);
}

void fillLdrMatrix()
{
  // One colum gets 5V, then four rows can be read.
  for( int i=0; i<n; i++)
  {
    pinMode( colPins[i], OUTPUT);
    digitalWrite( colPins[i], HIGH);
    
    for( int j=0; j<n; j++)
    {
      ldr[i][j] = analogRead( rowPins[j]);
    }
    
//    pinMode( colPins[i], INPUT);
    pinMode( colPins[i], OUTPUT);
    digitalWrite( colPins[i], LOW);
  }
}

Thanks for your comment.

Using the Arduino Uno is mandatory. I know that there are other Arduino boards, but I would like to use the Arduino Uno.

I didn't think about using diodes. Thanks for the information on how the use of diodes can affect.

What do you think about using two 74HC4051 (8-channel multiplexer), one connected to the 8 rows (connecting each row to the negatives poles of the LDR) and another connected to the 8 columns (connecting each column to the positive ones of the LDR)?

I've made a sketch with Fritzing. I don't know if this can work. Maybe my scheme is not functional or has an error. If someone could help me in the programming part it would also be helpful.

In the sketch I didn't put diodes to simplify, but in reality there should be diodes.

Sketch of LDR matrix

You only need one analog part, that is the part that measures the matrix. The other part drives the matrix.

My columns are digital output pins, which are 5V or 0V or open.
My rows go to analog inputs.

A multiplexer to use one analog input is good.

A second multiplexer to an analog pin is not okay. You have to drive the matrix with a voltage somehow.

You also need a resistor from the analog input to GND. Then you can measure the LDR.
I had 10k in each row.

The columns don't need to be open, as my numbers show. Just a digital 5V (HIGH) or 0V (LOW) is good, perhaps even better than leaving a column open.
A multiplexer can not do that.
You can use 8 digital pins of the Arduino Uno. Note that every analog pin can be used as a digital pin as well.
Or use a 3 to 8 line decoder. For example the 74HC238. Then you need three digital pins instead of 8.

I suggest one multiplexer with 3 digital pins (e.g. 3,4,5) and one analog pin (e.g. A0) and a resistor for the rows or columns. For the other part, just use 8 digital pins (e.g. 6...13) of the Arduino Uno.

Tinkercad.com does not have a 74HC4051 yet :frowning:

Ok, I've changed the sketch... Is it okay?


Link to 8x8 LDR matrix sketch

I've used a MCP23017 as a port expander for the digital outputs (columns).

What a shame there is no 74HC4051 in Tinkercad yet... :frowning:

That will work. I did not check every wire, but it seems to be allright.

The 8 resistors of 10k on the left can be replaced by a single 10k resistor from A0 to GND. The resistors can be before or after the multiplexer, the result is the same.

The I2C I/O expander requires a library. You could make a small test sketch to check if you can control the MCP23017.
As a bonus, you have 8 extra I/O pins on the MCP23017. You could use 3 of them for the multiplexer instead of pin 2,3,4 from the Arduino Uno :wink:

I've bought this analog 8-channel multiplexer, but I don't know how to connect it...

In this website, there is some useful information, but the model of 74HC4051 is different.

I want to use the analog multiplexer as an input.

I've found the piece of code that I need for my project:

/******************************************************************************
Mux_Analog_Input
SparkFun Multiplexer Analog Input Example
Jim Lindblom @ SparkFun Electronics
August 15, 2016
https://github.com/sparkfun/74HC4051_8-Channel_Mux_Breakout

This sketch demonstrates how to use the SparkFun Multiplexer
Breakout - 8 Channel (74HC4051) to read eight, separate
analog inputs, using just a single ADC channel.

Hardware Hookup:
Mux Breakout ----------- Arduino
     S0 ------------------- 2
     S1 ------------------- 3
     S2 ------------------- 4
     Z -------------------- A0
    VCC ------------------- 5V
    GND ------------------- GND
    (VEE should be connected to GND)

The multiplexers independent I/O (Y0-Y7) can each be wired
up to a potentiometer or any other analog signal-producing
component.

Development environment specifics:
Arduino 1.6.9
SparkFun Multiplexer Breakout - 8-Channel(74HC4051) v10
(https://www.sparkfun.com/products/13906)
******************************************************************************/
/////////////////////
// Pin Definitions //
/////////////////////
const int selectPins[3] = {2, 3, 4}; // S0~2, S1~3, S2~4
const int zOutput = 5; 
const int zInput = A0; // Connect common (Z) to A0 (analog input)

void setup() 
{
  Serial.begin(9600); // Initialize the serial port
  // Set up the select pins as outputs:
  for (int i=0; i<3; i++)
  {
    pinMode(selectPins[i], OUTPUT);
    digitalWrite(selectPins[i], HIGH);
  }
  pinMode(zInput, INPUT); // Set up Z as an input

  // Print the header:
  Serial.println("Y0\tY1\tY2\tY3\tY4\tY5\tY6\tY7");
  Serial.println("---\t---\t---\t---\t---\t---\t---\t---");
}

void loop() 
{
  // Loop through all eight pins.
  for (byte pin=0; pin<=7; pin++)
  {
    selectMuxPin(pin); // Select one at a time
    int inputValue = analogRead(A0); // and read Z
    Serial.print(String(inputValue) + "\t");
  }
  Serial.println();
  delay(1000);
}

// The selectMuxPin function sets the S0, S1, and S2 pins
// accordingly, given a pin from 0-7.
void selectMuxPin(byte pin)
{
  for (int i=0; i<3; i++)
  {
    if (pin & (1<<i))
      digitalWrite(selectPins[i], HIGH);
    else
      digitalWrite(selectPins[i], LOW);
  }
}

I've tried connecting the multiplexer as described in the comments of the code, but the values I get are inaccurate. Does anyone know what I should do?

This is a forum. When you say that the value are inaccurate, that is not enough information for us. Please be more detailed.

It should work. Do you have a resistor(s) to GND and you power the rows (or columns) with 5V ?
Try a delay between selectMuxPin() and analogRead(). For example delay(10)

You could set the multiplexer to a certain LDR and measure with a multimeter if the voltage from the LDR is the same as at the analog input of the Arduino.

When you use the funtion analogRead() (and nothing else for that pin), then you don't have to use pinMode( ..., INPUT). It is not wrong at all, but as you can see in the official example, just analogRead() is okay: analogRead() - Arduino Reference

There might be some noise from the select lines. If your values change by about 10, that would be normal. Such small things can be solved by a few delays in the sketch, perhaps a decoupling capacitor for the VCC and GND, and maybe using the average of a number of samples.

Now, I've only connected 1 LDR to Y0 pin of the multiplexer to simplify the sketch. I've also added a delay(10) between selectMuxPin() and analogRead(). This are the very inacurate values I get:

The LDR is connected to GND with a resistor. The measure of the voltage of the LDR is around 3.3V-3.4V. But the A0 analog input pin voltage is very irregular as you can see in the image...

Y2,Y3,Y4,Y5,Y6 and Y7 are getting random values when there's nothing connected to them...

I've found this sketch, which is what I need, but it uses another model of 74HC4051:

There seems to be some kind of wave in the values. That probably means that the inputs are open and you a measuring the 50 Hz or 60 Hz mains noise. Something is wrong with your circuit, you are not measuring the LDR.

What you mean that it uses another model of 74HC4051 ?

That's the model I am using:

That's the model used in the example:

I've made a scheme of what I'm testing actually...

I've tried connecting VEE to GD· but it still doesn't work.

You need to ground /E to enable the chip.

Read it's datasheet - always a good idea.

Allan

I have connected E to GND and it still does not work...

Then either you have a wiring mistake or have faulty software or have blown up the chip.

A look at your code would be useful.

Allan

edit : both VEE and /E must be grounded. \edit

The code that I am currently using is this:

const byte sensor = A0;

const byte s0 = 2;
const byte s1 = 3;
const byte s2 = 4;

void setup ()
{
  Serial.begin (9600);
  Serial.println ("Starting multiplexer test ...");
  pinMode (s0, OUTPUT);
  pinMode (s1, OUTPUT);
  pinMode (s2, OUTPUT);
} 

int readSensor(){
  // I read the Y0 pin of the multiplexer.
  digitalWrite (s0, LOW);
  digitalWrite (s1, LOW);
  digitalWrite (s2, LOW);
  
  return analogRead(sensor);
}
  
void loop (){
  Serial.print ("Sensor value is: ");
  Serial.println (readSensor());
  delay (1000);
}

I attach the current scheme...