ISR(ADC_vect) Reading in Analog values from a wave(rand) and want to over sample

Hello,

I am currently trying to find a way to simply over sample an incoming wave. I have looked around lots of forums and found out the best way to do such thing is to bypass the analogRead() function and to use interrupts. I am aware that I have to use ISR(ADC_vect). I just do not know how to incorporate this when I am passing in a wave from a waveform generator and I want to get more samples per second than an analogRead().


Details:

I am using the Arduino IDE. I am inputting a 50Hz signal and I would like 1,000 data points. I would like to sample at 1KHz. Ideally I would like to check the values attained through a Serial.println() and copy and paste the results to an excel document to see if the data points are in fact giving me the correct waveform that I inputted with (of course) a lot of data points.


Questions for the non-n00bs:

  1. What needs to be in my void setup() to achieve this? (If I do need anything there)
  2. What exactly does ADC_vect mean?
  3. Help.. :frowning:

Links I have already explored:

http://code.google.com/p/ardu-imu/issues/attachmentText?id=2&aid=2044103505418049416&name=ADC.pde&token=c8e4425200064980e51da51ec803edac
http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html#gad28590624d422cdf30d626e0a506255f

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=48188

http://forum.arduino.cc/index.php?topic=109899.0
http://forum.arduino.cc/index.php/topic,91042.msg683916.html#msg683916

^^All of these links I looked at but either they were confusing or they weren't quite what I was looking for.

Any and all help is MUCH appreciated!

:slight_smile:

Try this, simple one: http://coolarduino.wordpress.com/2011/03/14/quasi-real-time-oscilloscope/
More complex projects, you will have to "extract" a sampling subroutine:
http://coolarduino.wordpress.com/2013/01/09/audio-vu-meter/

analogRead() will vastly over sample a 50Hz signal. Why not test it instead of just junking it.

Mark

I happened to have a very similar requirement in a project a while ago. Here are the relevant code snippets. It uses timer 2 to generate an interrupt every 1ms, which is used to kick off the ADC conversion.

const int mainsMonitorRefPin = 0;
static volatile unsigned char currentAdcChannel;

void setup()
{
  // Set up the ADC. We need to read the mains voltage frequently in order to get a sufficiently accurate RMS reading.
  // To avoid using too much CPU time, we use the conversion-complete interrupt. This means we can't use analogRead(),
  // we have to access the ADC ports directly. 
  currentAdcChannel = mainsMonitorRefPin;      // set up which analog input we will read first
  ADMUX = B01000000 | currentAdcChannel;
  ADCSRB = B00000000; // Analog Input bank 1
  ADCSRA = B10011111; // ADC enable, manual trigger mode, ADC interrupt enable, prescaler = 128
  
  // Set up a timer 2 interrupt every 1ms to kick off ADC conversions etc.
  // Do this last after we have initialized everything else
  ASSR = 0;
  TCCR2A = (1 << WGM21);    // CTC mode
  TCCR2B = (1 << CS22);     // prescaler = 64
  TCNT2 = 0;                // restart counter
  OCR2A = 249;              // compare register = 249, will be reached after 1ms
  TIMSK2 = (1 << OCIE2A);
}

// Interrupt service routine for the 1ms tick
ISR(TIMER2_COMPA_vect)
{
  TIFR2 = (1 << OCF2B);  // shouldn't be needed according to the documentation, but is (perhaps the ISR is too short without it?)
  // Kick off a new ADC conversion. We already set the multiplexer to the correct channel when the last conversion finished.
  ADCSRA = B11001111;   // ADC enable, ADC start, manual trigger mode, ADC interrupt enable, prescaler = 128
}

// Interrupt service routine for ADC conversion complete
ISR(ADC_vect) 
{
  // The mcu requires us to read the ADC data in the order (low byte, high byte)
  unsigned char adcl = ADCL;
  unsigned char adch = ADCH;
  unsigned int adcVal = (adch << 8) | adcl;
  
  switch(currentAdcChannel)
  {
    case mainsMonitorRefPin:
      // do whatever you want with the reading in adcVal
      // set currentAdcChannel to the next pin you want to read
      ...
      break;

   // add switch cases fort the other channels you want to read here...
  }
  
  // Set the ADC multiplexer to the channel we want to read next. Setting if here rather than in the tick ISR allows the input
  // to settle, which is required for ADC input sources with >10k resistance.
  ADMUX = (B01000000 | currentAdcChannel);   // Vcc reference, select current channel
}

Thank you all for the responses! I ended up doing something VERY simple. Check out the code below:

void setup(){
  Serial.begin(115200);
}
void loop(){
Serial.println(analogRead(A0));
}

It is crazy how the simpliest things do what you want! I put in a 50 Hz signal and got 50 samples per cycle which turns out to be 1,000 samples per second! :slight_smile: :stuck_out_tongue:

Your code won't work very well as Serial blocks when it's 64? char buffer becomes full so you will get some odd spacings to the readings.

Google up arduino scope for better designs.

Mark

Thank you for the heads up, Mark! X :slight_smile: