Read input analogic signal without analogRead ()

Hello everyone,
the code below read the analog input signal by my arduino Mega2560 without use the function analogRead ().
for that, I was sitting the registre ADMUX (0 & 0x07) and prescale the ADC clock in 16.

int TimeSample=0;
long t, t0;
void setup()
{
  Serial.begin(115200);
  ADCSRA = 0;             
  ADCSRB = 0;             
  ADMUX |= (0 & 0x07);    
  ADMUX |= (1 << REFS0);  
  ADMUX |= (1 << ADLAR);  
 
  ADCSRA |= (1 << ADPS2);                   
 
  ADCSRA |= (1 << ADATE); 
  ADCSRA |= (1 << ADIE);  
  ADCSRA |= (1 << ADEN);  
  ADCSRA |= (1 << ADSC);  
}

ISR(ADC_vect)
{
  byte x = ADCH;  
  TimeSample++;
}
  
void loop()
{
   if (TimeSample>=1000)
  {
    t = micros()-t0;  // calculate elapsed time

    Serial.print("Sampling frequency: ");
    Serial.print((float)1000000/t);
    Serial.println(" KHz");
    Serial.print("micros:  ");
    Serial.println(micros());
    Serial.println(A0);
    
    t0 = micros();
    TimeSample=0;
  }
}

The code result as follows :

Sampling frequency: 76.92 KHz
micros:  2407214368
54
Sampling frequency: 76.92 KHz
micros:  2407229164
54
Sampling frequency: 76.92 KHz
micros:  2407243956
54
Sampling frequency: 76.92 KHz
micros:  2407258752
54

but I have three problems with this result :sweat::

  1. Why I have only one value 54 from the input A0?
    when I use the function analogRead () , the result is correct.

  2. For me, the frequency of data acqusition is 76.92 Hz , but for my friend the frequency is 76.92KHz? Which one is right (Hz or KHz)?

  3. When I display the micros () , the elapsed time between two successive values is 14792 microS (ex : 2407229164 - 2407243956), that's mean for me, we have 67,6 Hz ((1/14792)*1000000) , so far from the resulte 76.92KHz?

I hope my problem is clear for you , and thanks so much for help

Because, on a Mega, A0 has the value 54; on a Uno, it's 14.

1 Like

Serial.println(" KHz");

What you expect?

1 Like

No, it's the time between 1000 samples.

1 Like

As this had not much to do with Storage, your topic has been moved to a more suitable location on the forum.

1 Like

Should be volatile

@killzone_kid

This variable do his function correctly in this code?
int TimeSample=0 in the beginning just for rest the value.
it's a internal variable.
For me the problem is not this variable

thanks for your reply, I expect to read on high frequency the value of my analog sensor.
But when I subtract two successive values of micro() i have only 67,6Hz.
This code mention that we can have 76,92kHz.
Something is not clear for me in this history?!

How to change that for having the value of sensor without use the analogread ()?
thanks

The variables t and t0 should be unsigned long.

You are using micros for the calculation before you print the data, then setting t0 to the value of micros after printing. The printing, and more significantly the float calculation and analogRead, will take a fairly significant number of microseconds and cause an error in the calculation. Call micros once and save that value, then use the saved value for the calculation.

TimeSample should be declared volatile, and you should temporarily disable interrupts while accessing it since an int is two bytes and an interrupt can occur between bytes.

void loop()
{
  //make a copy of TimeSample so that interrupt does not occur between bytes
  //  note - TimeSample needs to be declared volatile
  noInterrupts();
  int ts = TimeSample; 
  interrupts();
  
  if (ts >= 1000)
  {
    noInterrupts();
    TimeSample = 0;
    interrupts();
    unsigned long tc = micros();
    t = tc - t0; // calculate elapsed time
    t0 = tc;
    Serial.print("Sampling frequency: ");
    Serial.print((float)1000000 / t);
    Serial.println(" Hz");
    Serial.print("micros:  ");
    Serial.println(tc);
    Serial.println(analogRead(A0));
  }
}

< edit > corrected some mistakes in code

1 Like

@david_2018.
I will try that and I tell you the results

David,
According to your advices, I make the code as below

volatile byte TimeSample;
unsigned long t, t0;
void setup()
{
  Serial.begin(115200);
  ADCSRA = 0;             
  ADCSRB = 0;             
  ADMUX |= (0 & 0x07);    
  ADMUX |= (1 << REFS0);  
  ADMUX |= (1 << ADLAR);  
 
  ADCSRA |= (1 << ADPS2);                   
 
  ADCSRA |= (1 << ADATE); 
  ADCSRA |= (1 << ADIE);  
  ADCSRA |= (1 << ADEN);  
  ADCSRA |= (1 << ADSC);  
}

ISR(ADC_vect)
{
  byte x = ADCH;  
  TimeSample++;
}
  
void loop()
{
  noInterrupts();
  int ts = TimeSample; 
  interrupts();
  
  if (ts >= 1000)
  {
    noInterrupts();
    TimeSample = 0;
    interrupts();
    unsigned long tc = micros();
    t = tc - t0; // calculate elapsed time
    t0 = tc;
    Serial.print("Sampling frequency: ");
    Serial.print((float)1000000 / t);
    Serial.println(" Hz");
    Serial.print("micros:  ");
    Serial.println(tc);
    Serial.println(analogRead(A0));
  }

}

I don't have error in the code, but nothing happens in the serial monitor,
Maybe missing something

You changed TimeSample to a byte, it will never be >= 1000.

See About the Storage category to understand what the Storage category is for.

As your topic has nothing to do with EEPROMs, SD cards and the likes, it was moved to a more suitable location.

Thanks Dvaid ,
You're right, with byte the maximum is 256, I changed that for this varaible.
For another thing, in this code :
Do you have any idea how I can display the sensor value wired on A0 without uses the function like : analogRead() , pinMode (), etc.
with this code, in Mega, I have only the value 54 of A0 ( see the previouse post of : @ [TheMemberFormerlyKnownAsAWOL] ).

Reading ADCL and ADCH will give you the value from the analog input. You are currently only reading ADCH in the interrupt and doing nothing with it. Note that you must read those in the correct order, ADCL followed by ADCH.

You are getting the value 54 because you are printing the pin number for A0, not reading the analog input.

Great David, actually, it was simple, only to read ADCH and ADCL by serial print. (I missed that).
But, I think if we need 8 bits precision, we can read only ADCH registre and ignore ADCL .
For 10 bits precision, we use a both registers (ADCL first and then ADCH).
Thanks again for this answer