Arduino/Android DAQ

This is an arduino/android bluetooth oscilloscope-type doohickey that I made for a wireless data acquisition project. In the video below, an analog voltage is sampled with the Arduino Nano, transmitted with the JY-MCU bluetooth module, and received/plotted with a Nexus 7.

Within the Android app, both time and frequency information can be displayed. The spectral estimate for the frequency analysis is calculated on the Arduino itself with a standard Cooley-Tukey FFT algorithm. The sampling rate on the Arduino is around 20 kHz when in "frequency mode." When viewing the time-domain plot, the Android commands the Arduino to reduce its sampling rate to around 900 Hz. This configuration was tailored to my particular project.

If I have time, I would like to clean up/post the Android code so it can be viewed/altered/improved by anyone who is interested. Until then, you can download the app itself below.

 

Demo Video (click to play):

Arduino Code:

Requires MeetAndroid library and PlainFFT.h. (easily google'able resources)

/*

Author: Will Forfang
Date: 11/7/2013

*/

#include <MeetAndroid.h>
MeetAndroid meetAndroid;

#include "PlainFFT.h"
PlainFFT FFT = PlainFFT(); /* Create FFT object */

// from time domain sketch
const float buffSize = 256;
unsigned long startTime;
//unsigned long endTime;
float fs;
//unsigned long timeTaken;
int c;

// from frequency domain sketch
const uint16_t samples = 128;
//double samplingFrequency;
//uint8_t startTime;
double vReal[samples]; 
double vImag[samples];
#define SCL_INDEX 0x00
#define SCL_TIME 0x01
#define SCL_FREQUENCY 0x02


// prescale to 16, test
#define FASTADC 1

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif



void setup() 
{
  Serial.begin(115200);
  Serial.println("WillForfang.com");
  pinMode(5,INPUT); 
  meetAndroid.registerFunction(timeDomain, 'A');
  meetAndroid.registerFunction(freqDomain, 'B');
  //prescale to 16, test
    int start ;
  int i ;
  
#if FASTADC
  // set prescale to 16
  sbi(ADCSRA,ADPS2) ;
  cbi(ADCSRA,ADPS1) ;
  cbi(ADCSRA,ADPS0) ;
#endif
  
  
  
}

void loop()
{
  meetAndroid.receive();
}

void timeDomain(byte flag, byte numOfValues)
{

  while(Serial.available() == 0)
  {
    startTime = micros();
    for (int c = 0; c <= buffSize-1; c++)
      {
        meetAndroid.send(uint8_t(analogRead(5)));
        delayMicroseconds(1000); //sampling rate ~ 800-900 Hz when delay is set to 1 millisecond

      }  
  
    Serial.print("\n Current Sampling Rate: ");
    fs = buffSize*1000000/(micros() - startTime); // is the -1 necessary?
    Serial.print(fs);
    Serial.println(" Hz.");
  }
}


void freqDomain(byte flag, byte numOfValues)
{
  while(Serial.available() == 0)
    {
      
       //clear values that don't seem to be refreshing during loop iterations:
    for (uint8_t ii = 0; ii < samples; ii++) {
            vImag[ii] = 0.0;
    }

       startTime = micros();
       for (uint8_t ii = 0; ii < samples; ii++) 
          {
        vReal[ii] = uint8_t(analogRead(5));
            delayMicroseconds(20);
      }
       fs = (samples-1)*1000000/(micros() - startTime); // is the -1 necessary?
       Serial.print("\n Current Sampling Rate: ");
       Serial.print(fs);
       Serial.println(" Hz.");

    FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);    /* Weigh data */
    FFT.Compute(vReal, vImag, samples, FFT_FORWARD); /* Compute FFT */
    FFT.ComplexToMagnitude(vReal, vImag, samples); /* Compute magnitudes */ 
    double x = FFT.MajorPeak(vReal, samples, fs);
//  Serial.println(x, 6);
    for (uint8_t jj = 0; jj < samples/2+2; jj++) { //shouldn't it be 0:(samples/2)? Does index start at one?
        meetAndroid.send(int(vReal[jj]));
    }
//
        meetAndroid.send(int(0101));
//        meetAndroid.send(x,6);
    delay(300); /* Repeat after delay */
    }
}

Android App:

https://drive.google.com/file/d/0BxDX-Pv0URO4TGhFX0wteWgtaHM/edit?usp=sharing

Note: This app requires Amarino, which can be found HERE. I've installed/tested this app on the Nexus 7 and the Galaxy S4 with no complications. Regardless, use at your own risk.