#include <Wire.h>
// Definizioni per l'AD7746
#define I2C_ADDRESS 0x48 // 0x90 shiftato a destra
#define REGISTER_STATUS 0x00
#define REGISTER_CAP_DATA 0x01
#define REGISTER_VT_DATA 0x04
#define REGISTER_CAP_SETUP 0x07
#define REGISTER_VT_SETUP 0x08
#define REGISTER_EXC_SETUP 0x09
#define REGISTER_CONFIGURATION 0x0A
#define REGISTER_CAP_DAC_A 0x0B
#define REGISTER_CAP_DAC_B 0x0B
#define REGISTER_CAP_OFFSET 0x0D
#define REGISTER_CAP_GAIN 0x0F
#define REGISTER_VOLTAGE_GAIN 0x11
#define RESET_ADDRESS 0xBF
#define VALUE_UPPER_BOUND 16000000L
#define VALUE_LOWER_BOUND 0xFL
#define MAX_OUT_OF_RANGE_COUNT 3
#define CALIBRATION_INCREASE 1
byte calibration;
byte outOfRangeCount = 0;
unsigned long offset = 0;
// Funzione per selezionare il canale del multiplexer
void selectI2CChannel(byte channel) {
Wire.beginTransmission(0x70); // Indirizzo del TCA9548A
Wire.write(1 << channel); // Seleziona il canale
Wire.endTransmission();
}
void setup() {
Wire.begin(); // Inizializza I2C
Serial.begin(9600); // Imposta il baud rate per la seriale
Serial.println("Initializing");
// Reset del primo sensore
selectI2CChannel(0); // Seleziona il canale 0 (primo sensore)
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(RESET_ADDRESS); // Resetta il sensore
Wire.endTransmission();
delay(1); // Aspetta per il reboot
// Configurazione iniziale del primo sensore
writeRegister(REGISTER_EXC_SETUP, 1 << 3 | 1 << 1 | 1 << 0); // Eccitazione (EXC source A)
writeRegister(REGISTER_CAP_SETUP, 1 << 7); // Configura il sensore (capacitivo)
// Ottieni il valore di offset del sensore
Serial.println("Getting offset");
offset = ((unsigned long)readInteger(REGISTER_CAP_OFFSET)) << 8;
Serial.print("Factory offset: ");
Serial.println(offset);
// Calibrazione
calibrate();
Serial.println("done");
}
void loop() {
// Leggi dal primo sensore (canale 0)
selectI2CChannel(0); // Seleziona il canale 0 (primo sensore)
long value1 = readValue();
Serial.print("Sensor 1 value: ");
Serial.println(value1);
// Leggi dal secondo sensore (canale 1)
selectI2CChannel(1); // Seleziona il canale 1 (secondo sensore)
long value2 = readValue();
Serial.print("Sensor 2 value: ");
Serial.println(value2);
// Logica per gestire valori fuori intervallo
if ((value1 < VALUE_LOWER_BOUND) || (value1 > VALUE_UPPER_BOUND)) {
outOfRangeCount++;
}
if ((value2 < VALUE_LOWER_BOUND) || (value2 > VALUE_UPPER_BOUND)) {
outOfRangeCount++;
}
if (outOfRangeCount > MAX_OUT_OF_RANGE_COUNT) {
if (value1 < VALUE_LOWER_BOUND) {
calibrate(-CALIBRATION_INCREASE);
}
else {
calibrate(CALIBRATION_INCREASE);
}
outOfRangeCount = 0;
}
delay(50);
}
// Funzione per calibrare il sensore
void calibrate(byte direction) {
calibration += direction;
calibration &= 0x7f;
writeRegister(REGISTER_CAP_DAC_A, 1 << 7 | calibration);
}
// Funzione per calibrare automaticamente
void calibrate() {
calibration = 0;
Serial.println("Calibrating CapDAC A");
long value = readValue();
while (value > VALUE_UPPER_BOUND && calibration < 128) {
calibration++;
writeRegister(REGISTER_CAP_DAC_A, 1 << 7 | calibration);
value = readValue();
}
Serial.println("done");
}
// Funzione per leggere un valore dal sensore
long readValue() {
long ret = 0;
uint8_t data[3];
char status = 0;
// Attendere fino a che la conversione è completata
while (!(status & (1 << 0 | 1 << 2))) {
status = readRegister(REGISTER_STATUS);
}
unsigned long value = readLong(REGISTER_CAP_DATA);
value >>= 8;
ret = value;
return ret;
}
// Funzione per scrivere un registro
void writeRegister(unsigned char r, unsigned char v) {
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(r);
Wire.write(v);
Wire.endTransmission();
}
// Funzione per leggere un registro
unsigned char readRegister(unsigned char r) {
unsigned char v;
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(r);
Wire.endTransmission();
Wire.requestFrom(I2C_ADDRESS, 1);
while (Wire.available() == 0) {}
v = Wire.read();
return v;
}
// Funzione per leggere un valore long
unsigned long readLong(unsigned char r) {
union {
char data[4];
unsigned long value;
} byteMappedLong;
byteMappedLong.value = 0L;
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(I2C_ADDRESS, r + 4);
while (!Wire.available() == r + 4) {}
for (int i = r + 3; i >= 0; i--) {
uint8_t c = Wire.read();
if (i < 4) {
byteMappedLong.data[i] = c;
}
}
return byteMappedLong.value;
}
unsigned int readInteger(unsigned char r) {
union {
char data[2];
unsigned int value;
}
byteMappedInt;
byteMappedInt.value = 0;
Wire.beginTransmission(I2C_ADDRESS); // begin read cycle
Wire.write(0); //pointer to first cap data register
Wire.endTransmission(); // end cycle
//after this, the address pointer is set to 0 - since a stop condition has been sent
Wire.requestFrom(I2C_ADDRESS,r+2); // reads 2 bytes plus all bytes before the register
while (!Wire.available()==r+2) {
; //wait
}
for (int i=r+1; i>=0; i--) {
uint8_t c = Wire.read();
if (i<2) {
byteMappedInt.data[i]= c;
}
}
return byteMappedInt.value;
}
hello arduino community. For my thesis project I'm using arduino giga and the AD7746 (CDC) component to read the capacitance values of pressure sensors. I have created a circuit and code to read the values of a single sensor using a single AD7746 component and everything works. My goal is now to use a TCA9845A multiplexer to be able to use 4 AD7746 components, I tried to use 2 AD7746 with the MUX but by compiling the code that I published the capacitance values read from the two sensors are fixed at 0. Can anyone help me understand where the error could be? Thank you very much
Looks like you only reset and calibrated one of the AD7746 sensors in setup().
In loop(), you are calling the calibrate function without specifying which sensor needs the calibration, so that will only be done on the 2nd AD7746 since that is where you last set the multiplexer.
#include <Wire.h>
// Definizioni per l'AD7746
#define I2C_ADDRESS 0x48
#define REGISTER_STATUS 0x00
#define REGISTER_CAP_DATA 0x01
#define REGISTER_VT_DATA 0x04
#define REGISTER_CAP_SETUP 0x07
#define REGISTER_VT_SETUP 0x08
#define REGISTER_EXC_SETUP 0x09
#define REGISTER_CONFIGURATION 0x0A
#define REGISTER_CAP_DAC_A 0x0B
#define REGISTER_CAP_DAC_B 0x0B
#define REGISTER_CAP_OFFSET 0x0D
#define REGISTER_CAP_GAIN 0x0F
#define REGISTER_VOLTAGE_GAIN 0x11
#define RESET_ADDRESS 0xBF
#define VALUE_UPPER_BOUND 16000000L
#define VALUE_LOWER_BOUND 0xFL
#define MAX_OUT_OF_RANGE_COUNT 3
#define CALIBRATION_INCREASE 1
byte calibration;
byte outOfRangeCount = 0;
unsigned long offset = 0;
// Funzione per selezionare il canale del multiplexer
void selectI2CChannel(uint8_t i) {
if (i > 7) return;
Wire.beginTransmission(0x70); // Indirizzo del TCA9548A
Wire.write(1 << i); // Seleziona il canale
Wire.endTransmission();
}
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("Initializing sensors...");
// Configura i sensori sui canali 3 e 5
uint8_t channels[] = {3, 5};
for (int i = 0; i < 2; i++) {
setupSensor(channels[i]);
}
Serial.println("All sensors initialized!");
}
void loop() {
uint8_t channels[] = {3, 5}; // Canali del multiplexer
long values[2]; // Valori letti dai sensori
byte outOfRangeCount[2] = {0, 0}; // Contatori di valori fuori range
for (int i = 0; i < 2; i++) {
selectI2CChannel(channels[i]); // Seleziona il canale i-esimo
delay(2); // Delay per la stabilizzazione
long value = readValue(); // Leggi il valore dal sensore
values[i] = value; // Salva il valore nell'array
// Stampa il valore
Serial.print("Sensor value on channel ");
Serial.print(channels[i]);
Serial.print(": ");
Serial.println(value);
// Controlla se il valore è fuori intervallo
if (value < VALUE_LOWER_BOUND || value > VALUE_UPPER_BOUND) {
outOfRangeCount[i]++;
} else {
outOfRangeCount[i] = 0; // Resetta il contatore se il valore torna nei limiti
}
// Calibrazione se il valore è fuori range troppo a lungo
if (outOfRangeCount[i] > MAX_OUT_OF_RANGE_COUNT) {
if (value < VALUE_LOWER_BOUND) {
calibrate(channels[i], -CALIBRATION_INCREASE); // Calibrazione verso il basso
} else {
calibrate(channels[i], CALIBRATION_INCREASE); // Calibrazione verso l'alto
}
outOfRangeCount[i] = 0; // Resetta il contatore dopo la calibrazione
Serial.print("Sensor on channel ");
Serial.print(channels[i]);
Serial.println(" recalibrated!");
}
delay(50); // Piccola pausa prima del prossimo sensore
}
delay(500); // Pausa generale prima di ricominciare il ciclo
}
void calibrate(uint8_t channel, byte direction) {
selectI2CChannel(channel); // Seleziona il canale corretto nel multiplexer
calibration += direction;
// Assicura che il valore di calibrazione sia entro 7 bit
calibration &= 0x7F;
writeRegister(REGISTER_CAP_DAC_A, 1 << 7 | calibration);
Serial.print("Sensor on channel ");
Serial.print(channel);
Serial.println(" calibrated!");
}
void autoCalibrate(uint8_t channel) {
selectI2CChannel(channel); // Seleziona il canale corretto
calibration = 0;
Serial.print("Auto-calibrating sensor on channel ");
Serial.println(channel);
long value = readValue();
// Continua a calibrare finché il valore è fuori limite e la calibrazione è possibile
while (value > VALUE_UPPER_BOUND && calibration < 128) {
calibration++;
writeRegister(REGISTER_CAP_DAC_A, 1 << 7 | calibration);
value = readValue();
}
Serial.println("Auto-calibration done");
}
// Funzione per leggere un valore dal sensore
long readValue() {
long ret = 0;
uint8_t data[3];
char status = 0;
// Attendere fino a che la conversione è completata
while (!(status & (1 << 0 | 1 << 2))) {
status = readRegister(REGISTER_STATUS);
}
unsigned long value = readLong(REGISTER_CAP_DATA);
value >>= 8;
ret = value;
return ret;
}
// Funzione per scrivere un registro
void writeRegister(unsigned char r, unsigned char v) {
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(r);
Wire.write(v);
Wire.endTransmission();
}
// Funzione per leggere un registro
unsigned char readRegister(unsigned char r) {
unsigned char v;
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(r);
Wire.endTransmission();
Wire.requestFrom(I2C_ADDRESS, 1);
while (Wire.available() == 0) {}
v = Wire.read();
return v;
}
// Funzione per leggere un valore long
unsigned long readLong(unsigned char r) {
union {
char data[4];
unsigned long value;
} byteMappedLong;
byteMappedLong.value = 0L;
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(I2C_ADDRESS, r + 4);
while (!Wire.available() == r + 4) {}
for (int i = r + 3; i >= 0; i--) {
uint8_t c = Wire.read();
if (i < 4) {
byteMappedLong.data[i] = c;
}
}
return byteMappedLong.value;
}
unsigned int readInteger(unsigned char r) {
union {
char data[2];
unsigned int value;
}
byteMappedInt;
byteMappedInt.value = 0;
Wire.beginTransmission(I2C_ADDRESS); // begin read cycle
Wire.write(0); //pointer to first cap data register
Wire.endTransmission(); // end cycle
//after this, the address pointer is set to 0 - since a stop condition has been sent
Wire.requestFrom(I2C_ADDRESS,r+2); // reads 2 bytes plus all bytes before the register
while (!Wire.available()==r+2) {
; //wait
}
for (int i=r+1; i>=0; i--) {
uint8_t c = Wire.read();
if (i<2) {
byteMappedInt.data[i]= c;
}
}
return byteMappedInt.value;
}
void setupSensor(uint8_t channel) {
// Seleziona il canale sul multiplexer
selectI2CChannel(channel);
// Resetta il sensore AD7746
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(RESET_ADDRESS);
Wire.endTransmission();
delay(1); // Aspetta il reboot del sensore
// Configura il sensore
writeRegister(REGISTER_EXC_SETUP, 1 << 3 | 1 << 1 | 1 << 0); // Configura l’eccitazione (EXC source A)
writeRegister(REGISTER_CAP_SETUP, 1 << 7); // Abilita il canale capacitivo
// Legge l'offset di fabbrica
Serial.print("Getting offset for sensor on channel ");
Serial.println(channel);
offset = ((unsigned long)readInteger(REGISTER_CAP_OFFSET)) << 8;
Serial.print("Factory offset: ");
Serial.println(offset);
// Calibrazione del sensore
calibrate(channel, 1);
Serial.println("Calibration done");
}
I modified the code like this but it still gives me a fixed value of both sensors 0