I currently connected 5 sensor via a multiplexer (I must connect them to a multiplexer because they are I2C devices but they cannot been allocate more then 2 addresses so I use a multiplexer to solve the addressing problem).
However the sample rate is a shame , it is about 6.5Hz . I wish I could improve the sample rate by using some tricks. In my loop() function, multiplexer will loop through channel 0-4 , and read each of these channel's sensor value and print it by using Serial.print()
Is there any tricks I could use to improve my sampling rate faster ? Thanks...
Here is my multiplexer class :
class MUX {
public:
//mux control pins:
int s0 = 22;
int s1 = 24;
int s2 = 26;
int s3 = 28;
//SIG pin (not necessary WHEN sig is connect to 5V)
//int SIG_pin = 0;
//array to store channel :: muxChannel[channel numbers ][4 digit channel representation]
int muxChannel[16][4] = {
{0, 0, 0, 0}, //channel 0
{1, 0, 0, 0}, //channel 1
{0, 1, 0, 0}, //channel 2
{1, 1, 0, 0}, //channel 3
{0, 0, 1, 0}, //channel 4
{1, 0, 1, 0}, //channel 5
{0, 1, 1, 0}, //channel 6
{1, 1, 1, 0}, //channel 7
{0, 0, 0, 1}, //channel 8
{1, 0, 0, 1}, //channel 9
{0, 1, 0, 1}, //channel 10
{1, 1, 0, 1}, //channel 11
{0, 0, 1, 1}, //channel 12
{1, 0, 1, 1}, //channel 13
{0, 1, 1, 1}, //channel 14
{1, 1, 1, 1} //channel 15
};
void setupMux() {
pinMode(s0, OUTPUT);
pinMode(s1, OUTPUT);
pinMode(s2, OUTPUT);
pinMode(s3, OUTPUT);
digitalWrite(s0, LOW);
digitalWrite(s1, LOW);
digitalWrite(s2, LOW);
digitalWrite(s3, LOW);
Serial.println(F("Multiplexer initialized"));
}
void selectChannel(int channel) {
int controlPin[] = {s0, s1, s2, s3};
for (int i = 0; i < 4; i++) {
digitalWrite(controlPin[i], muxChannel[channel][i]);
}
}
2 Answers 2
It's hard to offer much more than speculation without knowing more about the sensors and your current code, but here is one possibility:
If the bulk of your loop time is the sum of the conversion times, is it possible to cycle through the sensors twice, once to start each conversion (so they will convert nearly simultaneously), wait one conversion-time (or for the first sensor to complete), then cycle through them again to read back each converted value?
for each sensor,
setup mux;
send start conversion command;
end
for each sensor,
setup mux;
while conversion not done,
; // wait
read and store value;
end
For 16 sensors and assuming the conversion time the majority of the time spent, that could speed your sample rate to ~100Hz. Expect maybe half of that, since mux-setup and communication times are probably not negligible.
The technique suggested by @JRobert (starting all the conversions in one loop, then running another loop to wait for completions and read results) looks reasonable.
Here are a couple of ways to shorten the code shown in the question:
First, instead of four int
declarations to set the value of s0 ... s3
, use an enum
. An enum
is used to declare integer constants.
enum { s0 = 22, s1 = 24, s2 = 26, s3 = 28};
Second, don't bother with the lengthy, tedious, and unnecessary muxChannel
array. Delete the declaration of muxChannel
and replace selectChannel
with the following:
void selectChannel(int channel) {
int controlPin[] = {s0, s1, s2, s3};
for (int i = 0; i < 4; i++) {
digitalWrite(controlPin[i], channel & 1);
channel /= 2;
}
}
The expression channel & 1
picks off the least-significant-bit of channel
. The statement channel /= 2;
divides channel
by 2, which moves the next bit of channel
into place for output. You could instead say channel >>= 1;
or channel = channel/2;
, etc. if you prefer.
You might also look closely at your sensor boards to see if there is any way to add jumpers to get another bit or two of I2C device addressing, allowing you to avoid multiplexing.
millis()
to time your code and see where most of the time is spent?