TCA9548A multiplexer with Arduino
This is the first time I have setup a MUX system. And I need your help to identify where I am going wrong! Bear with me.
A non-responsive system, I get as far as a serial output up to the first sensor initiation ā which fails.
I have individually and successfully tested all sensory systems are working - separate from the MUX setup.
Attached is a GitHub package of the project scope including electrical schematics, Arduino code and pictures.
I have located the addresses of all the devices using the scanner code successfully. As you can see I have connected 3 peripheral devices ā clock, compass and pressure sensor. Along with a SD card reader using SPI communications.
I am using 10k pull up resistors to 5v bus line for both the SDA and SCL channels, with Arduino uno.
I have added the code into one repo as there is 400 lines there.
this is a smaller test system of what is to come. I plan to incorporate many more I2c devices through one arduino MEGA.
your help is much appreciated!
// clock channel identify 0x68
// The I2C address of the DS3231 is 0x68. 0x57 is the I2C address of the AT24C32 EEPROM on your ZS-042 RTC module
// Following is for an I2C Multiplexor system.
// Arduino to LCA9548A
// 10k PULL UP RESISTORS
// Using 3 Peripheral I2C channels: 1,2,3
// NOTE: SD writing - working, BMP serial monitor displaying - working, magnetic compass function serial - working
// INDIVIUDALLY TESTED AND WORKING PERIPHERALS
//
// MAGNETIC COMPASS
//
// magnetic compass x,y,z recordings serial print out + write to SD card
// SD_BMP180_Clock_QMC5583L
#include <SFE_BMP180.h>
#include <Wire.h>
#include <Regexp.h>
SFE_BMP180 pressure;
#define ALTITUDE 10 // Altitude of (Ajax, Ontario, Canada)
////////////////////
#include <Wire.h>
#include <RTC.h>
DS3231 RTC;
#include <SD.h>
#include <SPI.h>
File myFile;
int pinCS = 53; // chip select 53 mega >> 10 uno
int modeState = 1;
// to merge to main code below
String liveDirectory;
String fileNameAllocation = "dive0.txt";
int logNum = 0;
String logDirectory = "/LOG#1";
int diveNumber = 0;
int logCount = 0;
String liveFullDirectory = "";
#include <QMC5883LCompass.h>
QMC5883LCompass compass;
//#define TotalSamples 100;
///////////////////////////////////////////////////////////////////// FUNCTION CALLS
void BMP180_check();
void compassCheck();
void writeSD_compassData(int x,int y,int z,String t);
void writeSD_BMP(float temp,float absolutePressure,float computedAltitude);
void logProfileNameAllocation(); // can be created at the initiation of dive arming
void tcaSelect(uint8_t bus);
void instantiateLogNum();
void logProfileNameAllocation();
////////////////////////////////////////////////////////////////////
// TCA9548 module I2C address: 0x70 >> MULTIPLEXOR
// I2C device found at address 0x0D ! QMC5883L >> COMPASS
// I2C device found at address 0x68 ! DS3231 RTC >> CLOCK LINE
// I2C device found at address 0x77 ! BMP180 >> PRESSURE BAROMETER
#define addr1 0x68 // CLOCK device 3 (I2C bus 2)
#define addr2 0x0D // QMC device 1 (I2C bus 1)
#define addr3 0x77 // BMP device 4 (I2C bus 2)
#define TCA_Address 0x70 // address of I2C switch module
#define bus1 1 // CLOCK
#define bus2 2 // COMPASS
#define bus3 3 // BMP
void setup() {
////////////////////////////////////////////////////////////////////////// CLOCK ACTIVATE
pinMode (pinCS,OUTPUT); // cs pin needs to be in a low setting for SPI communication to work correctly
digitalWrite(pinCS, HIGH);
Serial.begin(38400); // serial boot
delay(200);
Wire.begin(); // initialize i2c comms
delay(500);
Serial.println("PROGRAM LIVE");
Serial.println("***************************************");
Serial.println();
tcaSelect(bus1); // enable I2C channel 1
delay(100);
if (RTC.begin()){
Serial.println("RTC init success");
}
else
{
// Oops, something went wrong, this is usually a connection problem,
// see the comments at the top of this sketch for the proper connections.
Serial.println("RTC init fail\n\n");
while(1); // Pause forever.
}
//////////////////////////////////////////////////////////////////////////// COMPASS ACTIVATE
tcaSelect(bus2); // enable I2C channel 2
compass.init();
Serial.println("Compass init success");
// }
// else
// {
// // Oops, something went wrong, this is usually a connection problem,
// // see the comments at the top of this sketch for the proper connections.
//
// Serial.println("Compass init fail\n\n");
// while(1); // Pause forever.
// }
compass.setCalibration(-428, 656, -2357, 0, 0, 980);
Serial.println("Compass Calibration Set");
//////////////////////////////////////////////////////////////////////////// BMP180 ACTIVATE - TEMP/PRESSURE
tcaSelect(bus3); // enable I2C channel 3
if (pressure.begin()){
Serial.println("BMP180 init success");
}
else
{
// Oops, something went wrong, this is usually a connection problem,
// see the comments at the top of this sketch for the proper connections.
Serial.println("BMP180 init fail\n\n");
while(1); // Pause forever.
}
//////////////////////////////////////////////////////////////////////////// SPI COMMS, SD INITIALIZE, CS
// pinMode(pinCS, OUTPUT);
// SD Card Initialization
if (SD.begin())
{
Serial.println("SD card is ready to use.");
} else
{
Serial.println("SD card initialization failed");
return;
}
////////////////////////////////////////////////// BOOT UP FUNCTIONS - SINGULAR
instantiateLogNum();
logProfileNameAllocation(); // call to scan card if file exists otherwise break and write file as the default setting dive0
} // END OF SETUP ***************************************************************************************************************************************************************
void loop() {
compassCheck();
BMP180_check();
delay(2000);
}
void instantiateLogNum(){
// created only at bootup, as root directory.
// traverse log folder directory until the latest can be appended
while(SD.exists(logDirectory)) // check if folder structure/ directory exists log
{
logCount++;
String logCountCastToString = String(logCount);
String logPrefix = "/LOG#";
logDirectory = logPrefix + logCountCastToString;
Serial.print(logDirectory);
}
SD.mkdir(logDirectory);
Serial.println("New Folder Log made: ");
Serial.print(logDirectory);
Serial.println();
}
// running program should save data to live set profile, LOG#1/dive1/dive0.txt >> dive1.txt >> dive2.txt
void logProfileNameAllocation(){ // using SPI comms - command should be called as the dive is armed moments before break-away.
// see if the directory exists, create it if not. construct from the live dive profile denotation
String mScast = String(modeState); // convert into string
liveDirectory = logDirectory + "/diveProfile" + mScast; // >> /LOG#1/diveProfile1
if(!SD.exists(liveDirectory)) // check if folder structure/ directory exists
{
if(SD.mkdir(liveDirectory)){
Serial.print("Directory Created: ");
Serial.print(liveDirectory);
}
}
else {
("path already exists, directory not created");
}
liveFullDirectory = liveDirectory + "/" + fileNameAllocation; // >> /LOG#1/diveProfile1/dive0.txt
while(SD.exists(liveFullDirectory)) {
diveNumber ++;
String diveNumberString = String(diveNumber);
fileNameAllocation = "dive" + diveNumberString + ".txt"; // concatanate an iteration one up from the existing global scoped variable/existing file
liveFullDirectory = liveDirectory + "/" + fileNameAllocation;
}
myFile = SD.open(liveFullDirectory, FILE_WRITE);
if (myFile) {
myFile.print("\n\n");
myFile.print("New File: ");
myFile.print(fileNameAllocation);
Serial.println();
Serial.println("***************************************");
Serial.println("Success >> New Log text printed");
myFile.close(); // close the file
}
else {
Serial.println("error opening SD file");
}
}
// **********************************************************************************************************************************************************************
void tcaSelect(uint8_t bus) {
if (bus > 7) return;
Wire.beginTransmission(TCA_Address);
Wire.write(1 << bus);
Wire.endTransmission();
Serial.print("bus live: ");
Serial.print(bus);
Serial.println();
}
void compassCheck(){
tcaSelect(bus1); // enable I2C channel 1, busline switch to clockline function call
String absoluteTime = "";
absoluteTime = absoluteTime + RTC.getHours() + ":" + RTC.getMinutes()+ ":" + RTC.getSeconds();
Serial.println();
Serial.print("Time: ");
Serial.println(absoluteTime);
tcaSelect(bus2); // enable I2C channel 2
int compass_x, compass_y, compass_z, a, b;
char myArray[3];
compass.read();
Serial.println();
compass_x = compass.getX();
compass_y = compass.getY();
compass_z = compass.getZ();
Serial.print("X: ");
Serial.print(",");
Serial.print(compass_x);
Serial.print(",");
Serial.print(" Y: ");
Serial.print(compass_y);
Serial.print(",");
Serial.print(" Z: ");
Serial.print(compass_z);
a = compass.getAzimuth();
b = compass.getBearing(a);
compass.getDirection(myArray, a);
Serial.println();
Serial.print("Azimuth: ");
Serial.print(a);
Serial.println();
Serial.print("Bearing: ");
Serial.print(b);
Serial.println();
Serial.print("Direction: ");
Serial.print(myArray[0]);
Serial.print(myArray[1]);
Serial.print(myArray[2]);
Serial.println();
/////////////////////////////////////////
writeSD_compassData(compass_x,compass_y,compass_z,absoluteTime);
}
void writeSD_compassData(int x,int y,int z,String t){
Serial.print("write to directory: ");
Serial.print(liveFullDirectory);
Serial.println();
myFile = SD.open(fileNameAllocation, FILE_WRITE);
if (myFile) {
myFile.println();
myFile.print("X: ");
myFile.print(",");
myFile.print(x);
myFile.print(",");
myFile.print(" Y: ");
myFile.print(",");
myFile.print(y);
myFile.print(" Z: ");
myFile.print(",");
myFile.print(z);
myFile.println();
myFile.print("Time: ");
myFile.print(t);
Serial.println();
Serial.println("Success >> Compass data write to card");
myFile.close(); // close the file
}
// if the file didn't open, print an error:
else {
Serial.println("error opening SD file");
}
}
void BMP180_check(){
tcaSelect(bus3); // enable I2C channel 3
char status;
double T,P,p0,J;
// Loop here getting pressure readings every 10 seconds.
// If you want sea-level-compensated pressure, as used in weather reports,
// you will need to know the altitude at which your measurements are taken.
// We're using a constant called ALTITUDE in this sketch:
Serial.println();
Serial.print("provided altitude: ");
Serial.print(ALTITUDE,0);
Serial.print(" meters, ");
Serial.print(ALTITUDE*3.28084,0);
Serial.println(" feet");
// If you want to measure altitude, and not pressure, you will instead need
// to provide a known baseline pressure. This is shown at the end of the sketch.
// You must first get a temperature measurement to perform a pressure reading.
// Start a temperature measurement:
// If request is successful, the number of ms to wait is returned.
// If request is unsuccessful, 0 is returned.
status = pressure.startTemperature();
if (status != 0)
{
// Wait for the measurement to complete:
delay(status);
// Retrieve the completed temperature measurement:
// Note that the measurement is stored in the variable T.
// Function returns 1 if successful, 0 if failure.
status = pressure.getTemperature(T);
if (status != 0)
{
// Print out the measurement:
Serial.print("temperature: ");
Serial.print(T,2);
Serial.print(" deg C, ");
Serial.print((9.0/5.0)*T+32.0,2);
Serial.println(" deg F");
// Start a pressure measurement:
// The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait).
// If request is successful, the number of ms to wait is returned.
// If request is unsuccessful, 0 is returned.
status = pressure.startPressure(3);
if (status != 0)
{
// Wait for the measurement to complete:
delay(status);
// Retrieve the completed pressure measurement:
// Note that the measurement is stored in the variable P.
// Note also that the function requires the previous temperature measurement (T).
// (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.)
// Function returns 1 if successful, 0 if failure.
status = pressure.getPressure(P,T);
if (status != 0)
{
// Print out the measurement:
Serial.print("absolute pressure: ");
Serial.print(P,2);
Serial.print(" mb, ");
Serial.print(P*0.0295333727,2);
Serial.println(" inHg");
// The pressure sensor returns abolute pressure, which varies with altitude.
// To remove the effects of altitude, use the sealevel function and your current altitude.
// This number is commonly used in weather reports.
// Parameters: P = absolute pressure in mb, ALTITUDE = current altitude in m.
// Result: p0 = sea-level compensated pressure in mb
p0 = pressure.sealevel(P,ALTITUDE); // we're at 90 meters (Boulder, CO)
Serial.print("relative (sea-level) pressure: ");
Serial.print(p0,2);
Serial.print(" mb, ");
Serial.print(p0*0.0295333727,2);
Serial.println(" inHg");
// On the other hand, if you want to determine your altitude from the pressure reading,
// use the altitude function along with a baseline pressure (sea-level or other).
// Parameters: P = absolute pressure in mb, p0 = baseline pressure in mb.
// Result: a = altitude in m.
J = pressure.altitude(P,p0);
Serial.print("computed altitude: ");
Serial.print(J,0);
Serial.print(" meters, ");
Serial.print(J*3.28084,0);
Serial.println(" feet");
}
else Serial.println("error retrieving pressure measurement\n");
}
else Serial.println("error starting pressure measurement\n");
}
else Serial.println("error retrieving temperature measurement\n");
}
else Serial.println("error starting temperature measurement\n");
writeSD_BMP(T,P,J);
}
void writeSD_BMP(float temp,float absolutePressure,float computedAltitude){
myFile = SD.open(fileNameAllocation, FILE_WRITE);
if (myFile) {
myFile.println();
myFile.print("Temperature: ");
myFile.print(temp);
myFile.print(",");
myFile.print(" Absolute Pressure: ");
myFile.print(absolutePressure);
myFile.print(",");
myFile.print(" Computed Altitude: ");
myFile.print(computedAltitude);
Serial.println();
Serial.println("Success >> BMP data write to card");
myFile.close(); // close the file
}
// if the file didn't open, print an error:
else {
Serial.println("error opening SD file");
}
}
Sketch uses 26640 bytes (10%) of program storage space. Maximum is 253952 bytes.
Global variables use 2292 bytes (27%) of dynamic memory, leaving 5900 bytes for local variables. Maximum is 8192 bytes.