/Users/eayars/Documents/Research/Chaotic_Rotor/SinDrive/SinDrive.ino

/*
SinDrive.ino
Eric Ayars
6/5/13

Uses an Arduino and MCP4725 DAC to drive the Helmholtz coils on my
chaotic rotor, and to report position and phase information.

*/

#include <Wire.h>
#include <Adafruit_MCP4725.h>

#define FPIN 0          // Frequency adjust knob, analog input 0
#define ZERO 11         // Zero-position button
#define PHASELED 12     // Indicator LED
#define ROTORLED 13     // Indicator LED
#define TMIN 500        // Minimum T for adjustment knob
#define TMAX 2500       // Maximum T for adjustment knob

// Define the DAC
Adafruit_MCP4725 DAC;

// Drive-related variables
unsigned long T;        // Note: if T is int, calculation of dt fails.
int dt;                 // time step, microseconds.
int residual = 0;       // residual microseconds to add in for each step
unsigned long M;        // micros
unsigned long lM;       // last micros
int dM;                 // change in micros

// Position variable
volatile int position = 0;

// Counter variable
byte j;                 // Byte so it wraps correctly with 8-bit LUT.

// Look-Up Table (LUT) for the sine wave.
// MCP4725 is 12-bit DAC, so maximum is 0x0FFF=4095.
PROGMEM uint16_t DACLookup_FullSine_8Bit[256] =
{
  2048, 2098, 2148, 2198, 2248, 2298, 2348, 2398,
  2447, 2496, 2545, 2594, 2642, 2690, 2737, 2784,
  2831, 2877, 2923, 2968, 3013, 3057, 3100, 3143,
  3185, 3226, 3267, 3307, 3346, 3385, 3423, 3459,
  3495, 3530, 3565, 3598, 3630, 3662, 3692, 3722,
  3750, 3777, 3804, 3829, 3853, 3876, 3898, 3919,
  3939, 3958, 3975, 3992, 4007, 4021, 4034, 4045,
  4056, 4065, 4073, 4080, 4085, 4089, 4093, 4094,
  4095, 4094, 4093, 4089, 4085, 4080, 4073, 4065,
  4056, 4045, 4034, 4021, 4007, 3992, 3975, 3958,
  3939, 3919, 3898, 3876, 3853, 3829, 3804, 3777,
  3750, 3722, 3692, 3662, 3630, 3598, 3565, 3530,
  3495, 3459, 3423, 3385, 3346, 3307, 3267, 3226,
  3185, 3143, 3100, 3057, 3013, 2968, 2923, 2877,
  2831, 2784, 2737, 2690, 2642, 2594, 2545, 2496,
  2447, 2398, 2348, 2298, 2248, 2198, 2148, 2098,
  2048, 1997, 1947, 1897, 1847, 1797, 1747, 1697,
  1648, 1599, 1550, 1501, 1453, 1405, 1358, 1311,
  1264, 1218, 1172, 1127, 1082, 1038,  995,  952,
   910,  869,  828,  788,  749,  710,  672,  636,
   600,  565,  530,  497,  465,  433,  403,  373,
   345,  318,  291,  266,  242,  219,  197,  176,
   156,  137,  120,  103,   88,   74,   61,   50,
    39,   30,   22,   15,   10,    6,    2,    1,
     0,    1,    2,    6,   10,   15,   22,   30,
    39,   50,   61,   74,   88,  103,  120,  137,
   156,  176,  197,  219,  242,  266,  291,  318,
   345,  373,  403,  433,  465,  497,  530,  565,
   600,  636,  672,  710,  749,  788,  828,  869,
   910,  952,  995, 1038, 1082, 1127, 1172, 1218,
  1264, 1311, 1358, 1405, 1453, 1501, 1550, 1599,
  1648, 1697, 1747, 1797, 1847, 1897, 1947, 1997
};

void positionUp() {
    position++;
}

void positionDown() {
    position--;
}

void setup() {
    // set up DAC
    DAC.begin(0x62);

    // initialize variables
    j=0;
    lM = micros();

    // set up buttons and LEDs
    pinMode(ZERO, INPUT);
    digitalWrite(ZERO, HIGH);
    pinMode(PHASELED, OUTPUT);
    pinMode(ROTORLED, OUTPUT);

    // Start serial
    Serial.begin(115200);
    while (!Serial) {
        ;
    }
    
    // Attach counter interrupts
    attachInterrupt(0,positionUp,RISING);
    attachInterrupt(1,positionDown,RISING);
}

void loop() {
    // Start by read the frequency knob and updating T:
    T = map(analogRead(FPIN),0,1023,TMIN,TMAX);
    dt = T*1000/256;

    // Now check the time and adjust output accordingly
    M = micros();
    dM = M - lM + residual;
    if (dM > dt) {
        // we just crossed a drive cycle time step, so...

        // adjust output.
        j = j + dM/dt;      // step forward requisite number of steps.
        DAC.setVoltage(pgm_read_word(&(DACLookup_FullSine_8Bit[j])), false);
        residual = dM % dt; // save "unused" microseconds for next dM.
        lM = M;

        // Check how position is doing
        if (!digitalRead(ZERO)) position = 0;
            // zero button has been pressed
        if (position > 359) position -= 360;
            // wrap backwards
        if (position < 0) position += 360;
            // wrap forwards

        // Update position indicator light 
        if (position==0) digitalWrite(ROTORLED, HIGH);
        else digitalWrite(ROTORLED, LOW);

        // Update phase indicator light 
        if (j==0) digitalWrite(PHASELED, HIGH);
        else digitalWrite(PHASELED, LOW);

        // Send information to the computer
        Serial.print(M, DEC);           // microseconds
        Serial.print(" ");
        Serial.print(j, DEC);           // phase angle (0-255)
        Serial.print(" ");
        Serial.print(position, DEC);    // position (degrees)
        Serial.print(" ");
        Serial.println(T, DEC);         // Drive period (ms)
    }

}

Generated by GNU enscript 1.6.4.