1.
The following interrupt driven sketch demonstrates the technique of simultaneous acquisition of four channels (tested on UNO using test signals). The ADC works well for ADC-clock frequency up to 1 MHz (this brings the conversion time to: 13 us) though the recommended ADC-clock frequency is 125 kHz (conversion time: 104 us).
volatile int analogVal[4]; //volatile tells compiler not to keep variable in register
volatile bool flag = false; //helps to execute print() method in loop() function
volatile byte i = 0; //array index
void setup()
{
Serial.begin(9600);
ADCSRA = 0x00; //reset
ADMUX = 0x00; //reset
ADMUX |= 1 << REFS0; //Ch-0, right adjust, Vref = 5V
ADCSRA |= 1 << ADPS2 | 0 << ADPS1 | 0 << ADPS0;//1 MHz adcClk
ADCSRA |= 1 << ADIE; //ADC EOC interupt enable
ADCSRA |= 1 << ADEN; //ADC Module is active
interrupts(); //Global interrupt logic is enabled
}
void loop()
{
bitWrite(ADMUX, 0, bitRead(i, 0)); //select channel
bitWrite(ADMUX, 1, bitRead(i, 1));
ADCSRA |= 1 << ADSC; //Start ADC
if (flag == true)
{
analogVal[i] = ADCL | (ADCH << 8); //read ADCL first
Serial.print("Ch-"); Serial.print(i);
Serial.print(" = "); Serial.println(analogVal[i]);
flag = false;
i++;
if (i == 4)
{
i = 0;
Serial.println("=================");
}
}
delay(1000); //test interval
}
ISR(ADC_vect)//conversion ends, ADSC goes LOW, ADIF goes HIGH and interrupts MCU
{
flag = true;
}
Output:
Ch-0 = 663 //3.3V
Ch-1 = 1023 //5V
Ch-2 = 0 //0V
Ch-3 = 1023 //5V
=================
2.
In Serial Communication, the speed is measured in Bd (bits/sec) and not in kHz/Hz.
You have 50 us interval among the four sensors; so, you can go well with ADC-clock frequency of 1 MHz (above that my above sketch does not work!). My experiment on the above sketch shows that about 30 us time is required to acquire/save (no dsiplay on Serial Monitor) a signal from a channel with adcClk = 1 MHz.
3.
What is 20 ksps?
ADC's conversion clock frequency has the unit of Hz/kHz/MHz.
4.
You can not operate the ADC at 5 kHz. The minimum frequency that you can select is 125 kHz with division factor 128.
5.
You may use TC1 to generate 50 us Time Tick to drive the ADC for acquiring signals from the four sensors.
Test Sketch:
volatile int analogVal[4]; //volatile tells compiler not to keep variable in register
volatile bool flag = false; //helps to execute print() method in loop() function
volatile byte i = 0; //array index
byte chCounter = 0;
void setup()
{
Serial.begin(9600);
ADCSRA = 0x00; //reset
ADMUX = 0x00; //reset
ADMUX |= 1 << REFS0; //Ch-0, right adjust, Vref = 5V
ADCSRA |= 1 << ADPS2 | 0 << ADPS1 | 0 << ADPS0;//1 MHz adcClk
ADCSRA |= 1 << ADIE; //ADC EOC interupt enable
ADCSRA |= 1 << ADEN; //ADC Module is active
//----------------------------
TCCR1A = 0x00;
TCCR1B = 0x00;
TCNT1 = 65436; //preset value for 50 us rollover
TCCR1B |= 1 << CS11; //start TC1 with division factor 8 (0x02)
interrupts(); //Global interrupt logic is enabled
}
void loop()
{
while(bitRead(TIFR1, TOV1) !=HIGH)
{
; //wait until 50 us has gone
}
bitSet(TIFR1, TOV1);
TCNT1 = 65436;
chCounter++;
if(chCounter == 4)
{
chCounter = 0;
}
acqSignal();
delay(1000); //test interval
}
void acqSignal()
{
bitWrite(ADMUX, 0, bitRead(i, 0)); //select channel
bitWrite(ADMUX, 1, bitRead(i, 1));
ADCSRA |= 1 << ADSC; //Start ADC
if (flag == true)
{
analogVal[i] = ADCL | (ADCH << 8); //read ADCL first
Serial.print("Ch-"); Serial.print(i);
Serial.print(" = "); Serial.println(analogVal[i]);
flag = false;
i++;
if (i == 4)
{
i = 0;
Serial.println("=================");
}
}
//delay(1000); //test interval
}
ISR(ADC_vect)//conversion ends, ADSC goes LOW, ADIF goes HIGH and interrupts MCU
{
flag = true;
}