Hello, I am a new user on this forum and very new to Arduino and I2C.
Project description:
I am building a proximity sensor array using Sparkfun VCNL4000 Infrared Proximity Breakout boards (8 in total) all of which are connected to a PCA9548A I2C multiplexer and an Arduino Uno. I have built the multiplexer board and Arduino Uno board myself and because of this I understand and accept that I may have messed up the hardware side of this project. Because of this I will provide a schematic and board layout of everything I have done, and reference all my sources of code.
My Arduino board works just fine and can run and collect data from a single VCNL4000 sensor board without any trouble. The problem starts when I try to connect a single sensor through the multiplexer board.
Some background information on my boards.
My custom Arduino does not have a usb interface and runs only on LDO regulated 3.3v (max current draw is 0.5A). So i program using the ISP pinheader and can only debug using analog output pins for things like LEDs (and of course my brain, what ever that’s worth :P).
Because of these limitations the multiplexer and sensors all run off only 3.3v.
Here is the current code I am trying to use. With thanks to Jim Lindblom and Kerry D. Wong for the sample code and assistance.
Hardware:
This code was developed using the SparkFun breakout board:
http://www.sparkfun.com/products/10901
Connections are:
VCNL4000 Breakout ---------------- Arduino
3.3V ----------------------- 3.3V
GND ------------------------ GND
SCL ------------------------ A5
SDA ------------------------ A4
IR+ ------------------------ 5V (3.3V is fine too)
*/
#include <Wire.h>
#define PCA9548ADDR 0x74 //1110100-
#define STOP 0x00 //0000 0000
#define CHANNEL_0 0x01 //0000 0001
#define CHANNEL_1 0x02 //0000 0010
#define CHANNEL_2 0x04 //0000 0100
#define CHANNEL_3 0x08 //0000 1000
#define CHANNEL_4 0x10 //0001 0000
#define CHANNEL_5 0x20 //0010 0000
#define CHANNEL_6 0x40 //0100 0000
#define CHANNEL_7 0x80 //0100 0000
#define VCNL4000_ADDRESS 0x13 // 0x26 write, 0x27 read
// VCNL4000 Register Map
#define COMMAND_0 0x80 // starts measurments, relays data ready info
#define PRODUCT_ID 0x81 // product ID/revision ID, should read 0x11
#define IR_CURRENT 0x83 // sets IR current in steps of 10mA 0-200mA
#define AMBIENT_PARAMETER 0x84 // Configures ambient light measures
#define AMBIENT_RESULT_MSB 0x85 // high byte of ambient light measure
#define AMBIENT_RESULT_LSB 0x86 // low byte of ambient light measure
#define PROXIMITY_RESULT_MSB 0x87 // High byte of proximity measure
#define PROXIMITY_RESULT_LSB 0x88 // low byte of proximity measure
#define PROXIMITY_FREQ 0x89 // Proximity IR test signal freq, 0-3
#define PROXIMITY_MOD 0x8A // proximity modulator timing
int ambientValue, proximityValue;
int led1 = A3;
bool blink = false;
void setup()
{
ambientValue = proximityValue = 0;
pinMode(led1, OUTPUT);
multiplexer_init();
selectI2CChannels(CHANNEL_0); //select channel 0
Wire.begin(); // initialize I2C stuff
/* Test that the device is working correctly */
byte temp = readByte(PRODUCT_ID);
if (temp != 0x11) // Product ID Should be 0x11
{
blink = true;
}
else
{
blink = false;
/* Now some VNCL400 initialization stuff
Feel free to play with any of these values, but check the datasheet first!*/
writeByte(AMBIENT_PARAMETER, 0x0F); // Single conversion mode, 128 averages
writeByte(IR_CURRENT, 20); // Set IR current to 200mA
writeByte(PROXIMITY_FREQ, 2); // 781.25 kHz
writeByte(PROXIMITY_MOD, 0x81); // 129, recommended by Vishay
}
}
void loop()
{
if(blink)
{
digitalWrite(led1, HIGH);
delay(1000);
digitalWrite(led1, LOW);
delay(1000);
}
else
{
ambientValue = readAmbient();
proximityValue = readProximity();
if(proximityValue > 0)
{
digitalWrite(led1, HIGH);
}
else
{
digitalWrite(led1, LOW);
}
// delay(100); // You may want to uncomment this for visibility
}
}
// readProximity() returns a 16-bit value from the VCNL4000's proximity data registers
unsigned int readProximity()
{
unsigned int data;
byte temp;
temp = readByte(COMMAND_0);
writeByte(COMMAND_0, temp | 0x08); // command the sensor to perform a proximity measure
while(!(readByte(COMMAND_0)&0x20)); // Wait for the proximity data ready bit to be set
data = readByte(PROXIMITY_RESULT_MSB) << 8;
data |= readByte(PROXIMITY_RESULT_LSB);
return data;
}
// readAmbient() returns a 16-bit value from the VCNL4000's ambient light data registers
unsigned int readAmbient()
{
unsigned int data;
byte temp;
temp = readByte(COMMAND_0);
writeByte(COMMAND_0, temp | 0x10); // command the sensor to perform ambient measure
while(!(readByte(COMMAND_0)&0x40)); // wait for the proximity data ready bit to be set
data = readByte(AMBIENT_RESULT_MSB) << 8;
data |= readByte(AMBIENT_RESULT_LSB);
return data;
}
// writeByte(address, data) writes a single byte of data to address
void writeByte(byte address, byte data)
{
Wire.beginTransmission(VCNL4000_ADDRESS);
Wire.write(address);
Wire.write(data);
Wire.endTransmission();
}
// readByte(address) reads a single byte of data from address
byte readByte(byte address)
{
byte data;
Wire.beginTransmission(VCNL4000_ADDRESS);
Wire.write(address);
Wire.endTransmission();
Wire.requestFrom(VCNL4000_ADDRESS, 1);
while(!Wire.available());
data = Wire.read();
return data;
}
void selectI2CChannels(int channels)
{
Wire.beginTransmission(PCA9548ADDR);
Wire.write(channels);
Wire.endTransmission();
}
void multiplexer_init()
{
pinMode(A0, OUTPUT);
pinMode(A1, OUTPUT);
pinMode(A2, OUTPUT);
digitalWrite(A0, LOW);
digitalWrite(A1, LOW);
digitalWrite(A2, HIGH);
}
Ok big block of code so ill try to explain what I was trying to accomplish.
All I want to have working right now is a single sensor that turns on and off an LED when i get real close to the sensor board.
Setup()
So first thing I did was initialize an unused analog pin to be my output. Then I set the A0 and A1 pins to logic LOW and A2 pin to logic HIGH ( I did this because the address for the multiplexer is 0x74 and looking at the data sheet that would make the A2 = 1 , A1 = 0 , A0 = 0 ? I’m not sure how those pins control this chip entirely so I’m probably totally wrong about how this works and could use clarification on this)
next I used selectI2CChannels(CHANNEL_0) to pick out the channel that has the sensor or it.
Next I begin attempting to communicate with the sensor because as far as I understand these components once the channel is selected I should be able to talk with a recognized device on I2C as if the MUX is transparent.
Problems:
The code gets hung up at the product ID reading part. I’ve run a few tests where I’ve commented out various parts to get any output at all on the LED. I don’t think I am communicating over the I2C line correctly with the MUX, how exactly I’ve gone wrong I don’t know (debugging is hard without serial out )
I am a college student and as such I don’t have this project directly in front of me as I type this from home. I will be at my college within the next 24 hours for pretty much the whole day and will have the circuits and everything in front of me to respond to you fine folk here and answer more questions and hopefully get feedback.
I hope this is enough information to at least begin the process of getting assistance, thank you to anyone who wishes to help.
References:
http://dlnmh9ip6v2uc.cloudfront.net/datasheets/BreakoutBoards/VCNL4000_Example.pde
http://www.kerrywong.com/2012/10/08/i2c-multiplexer-shield-testing/
http://www.nxp.com/documents/data_sheet/PCA9548A.pdf
UPDATE:
So spent the day troubleshooting my MUX board and i found a few errors, but im still not convinced my code is correct.
board faults:
-reset was being pulled low (OMG im stupid )
-SDA and SCL are reversed on the pinheader so no communication between shield and microcontroller lol really big problem there
-useless resistor (did i mention i’m not working alone on this project lol my partners contribution to the board layout)
I will be testing these corrections tomorrow at school, and will continue to update this post with my findings and progress. Even if no one helps or sees this post it will be here to showcase how to use these components.