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))
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

void setup() 
  meetAndroid.registerFunction(timeDomain, 'A');
  meetAndroid.registerFunction(freqDomain, 'B');
  //prescale to 16, test
    int start ;
  int i ;
  // set prescale to 16
  sbi(ADCSRA,ADPS2) ;
  cbi(ADCSRA,ADPS1) ;
  cbi(ADCSRA,ADPS0) ;

void loop()

void timeDomain(byte flag, byte numOfValues)

  while(Serial.available() == 0)
    startTime = micros();
    for (int c = 0; c <= buffSize-1; c++)
        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.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));
       fs = (samples-1)*1000000/(micros() - startTime); // is the -1 necessary?
       Serial.print("\n Current Sampling Rate: ");
       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(x,6);
    delay(300); /* Repeat after delay */

Android App:

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.