4-Layer "Instrument Droid"

This board is the capstone project to ECEN 5730 (Practical PCB Design and Manufacture) - the class that all three previous boards above were designed and manufactured for. There were several labs added as part of the exploration for this board to establish even more design principles. See the drop-down menu for those labs. 

IMG_5296.MOV

To the left is a video of the circuit operating. It is being powered by 5V from the wall on the top left and taking measurements from a 9V VRM on the bottom left. 

When it begins a 20 point measurement, the buzzer goes off and the smart LEDs flash red. 

When measuring, the smart LEDs form a loading bar to inform the user how far along the measurement cycle is. 

When a measurement is completed, the smart leds flash green and the buzzer goes off again. If not prompted by clicking the reset button, a new measurement occurs every 5 minutes. 

ECEN 5730 Board 4 Final.pdf

My Arduino Code:

// vrm characterizer board

#include <Wire.h>

#include <Adafruit_MCP4725.h>

#include <Adafruit_ADS1X15.h>

#include <Adafruit_NeoPixel.h>


#ifdef __AVR__

 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket

#endif



Adafruit_ADS1115 ads;

Adafruit_MCP4725 dac;




float R_sense = 10.0; //current sensor (make it 100 for 50 Ohm F-Generator

long itime_on_msec = 100; //on time for taking measurements

long itime_off_msec = itime_on_msec * 10; // time to cool off

int iCounter_off = 0; // counter for number of samples off

int iCounter_on = 0; // counter for number of samples on

float v_divider = 5000.0 / 15000.0; // voltage divider on the VRM

float DAC_ADU_per_v = 4095.0 / 5.0; //conversion from volts to ADU

int V_DAC_ADU; // the value in ADU to output on the DAC

int I_DAC_ADU; // the current we want to output

float I_A = 0.0; //the current we want to output, in amps

long itime_stop_usec; // this is the stop time for each loop

float ADC_V_per_ADU = 0.125 * 1e-3; // the voltage of one bit on the gain of 1 scale

float V_VRM_on_v; // the value of the VRM voltage

float V_VRM_off_v; // the value of the VRM voltage

float I_sense_on_A; // the current through the sense resistor

float I_sense_off_A; // the current through the sense resistor

float I_max_A = 0.250; // max current to set for (0.25 regularly, 0.160 for AA for some reason, 0.025 for 50 ohm)

int npts = 20; //number of points to measure

float I_step_A = I_max_A / npts; //step current change

float I_load_A; // the measured current load

float V_VRM_thevenin_v;

float V_VRM_loaded_v;

float R_thevenin;

int i;


#define PIN          7

#define NUMPIXELS    4

#define BUZZ         6


Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);


void setup() {

  Serial.begin(9600);

  dac.begin(0x62); // address is either 0x60, 0x61, 0x62,0x63, 0x64 or 0x65

  dac.setVoltage(0, false); //sets the output current to 0 initially

  // ads.setGain(GAIN_TWOTHIRDS); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default)

  ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV

  // ads.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV

  // ads.setGain(GAIN_FOUR); // 4x gain +/- 1.024V 1 bit = 0.5mV 0.03125mV

  // ads.setGain(GAIN_EIGHT); // 8x gain +/- 0.512V 1 bit = 0.25mV 0.015625mV

  // ads.setGain(GAIN_SIXTEEN); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV

  ads.begin(); // note- you can put the address of the ADS111 here if needed

   ads.setDataRate(RATE_ADS1115_860SPS);// sets the ADS1115 for higher speed


  #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)

    clock_prescale_set(clock_div_1);

  #endif


  pixels.begin();

  pixels.clear();

  pixels.show();

}



void func_meas_off(){

   dac.setVoltage(0, false); //sets the output current

   iCounter_off = 0; //starting the current counter

  V_VRM_off_v = 0.0; //initialize the VRM voltage averager

  I_sense_off_A = 0.0; // initialize the current averager

  itime_stop_usec = micros() + itime_off_msec * 1000; // stop time

  while (micros() <= itime_stop_usec) {

    V_VRM_off_v = (ads.readADC_Differential_0_1() * ADC_V_per_ADU / v_divider) + V_VRM_off_v;

    I_sense_off_A = (ads.readADC_Differential_2_3() * ADC_V_per_ADU / R_sense) +  I_sense_off_A;

    iCounter_off++;

  }

  V_VRM_off_v = V_VRM_off_v / iCounter_off;

  I_sense_off_A = I_sense_off_A / iCounter_off;

   //Serial.print(iCounter_off);Serial.print(", ");

   //Serial.print(I_sense_off_A * 1e3, 4); Serial.print(", ");

   //Serial.println(V_VRM_off_v, 4);

}


void func_meas_on(){

  //now turn on the current

  I_DAC_ADU = I_A * R_sense * DAC_ADU_per_v;

  dac.setVoltage(I_DAC_ADU, false); //sets the output current

  iCounter_on = 0;

  V_VRM_on_v = 0.0; //initialize the VRM voltage averager

  I_sense_on_A = 0.00; // initialize the current averager

  itime_stop_usec = micros() + itime_on_msec * 1000; // stop time

  while (micros() <= itime_stop_usec) {

    V_VRM_on_v = (ads.readADC_Differential_0_1() * ADC_V_per_ADU / v_divider) + V_VRM_on_v;

    I_sense_on_A = (ads.readADC_Differential_2_3() * ADC_V_per_ADU / R_sense) + I_sense_on_A;

    iCounter_on++;

  }

  dac.setVoltage(0, false); //sets the output current to zero

  V_VRM_on_v = V_VRM_on_v / iCounter_on;

  I_sense_on_A = I_sense_on_A / iCounter_on;

  //Serial.print(iCounter_on);Serial.print(", ");

  //Serial.print(I_sense_on_A * 1e3, 4);Serial.print(", ");

  //Serial.println(V_VRM_on_v, 4);

}



void loop() {

  tone(BUZZ, 391);

  delay(150);

  tone(BUZZ, 494);

  delay(150);

  tone(BUZZ, 587);

  delay(150);

  noTone(BUZZ); 

  

  pixels.clear();

  pixels.show();

  

  for(int k = 1; k <= 7; k++)

  {

    pixels.setPixelColor(0, pixels.Color(30, 0, 0));

    pixels.setPixelColor(1, pixels.Color(30, 0, 0));

    pixels.setPixelColor(2, pixels.Color(30, 0, 0));

    pixels.setPixelColor(3, pixels.Color(30, 0, 0));

    pixels.show();

    delay(100);

    pixels.clear();

    pixels.show();

    delay(100);

  }


  int j = 0;

  for (i = 1; i <= npts; i++) {

      if(i % 5 == 0)

      {

        pixels.setPixelColor(3-j, pixels.Color(0, 10, 0));

        pixels.show();  

        j++;

      }

    I_A = i * I_step_A;

    dac.setVoltage(0, false); //sets the output current

    func_meas_off();

    func_meas_on();

     dac.setVoltage(0, false); //sets the output current

    I_load_A = I_sense_on_A - I_sense_off_A; //load current

    V_VRM_thevenin_v = V_VRM_off_v;

    V_VRM_loaded_v = V_VRM_on_v;

    R_thevenin = (V_VRM_thevenin_v - V_VRM_loaded_v) / I_load_A;

    if (V_VRM_loaded_v < 0.75 * V_VRM_thevenin_v) i = npts; //stops the ramping

    Serial.print(i);

    Serial.print(", ");

    Serial.print(I_load_A * 1e3, 3);

    Serial.print(", ");

    Serial.print(V_VRM_thevenin_v, 4);

    Serial.print(", ");

    Serial.print(V_VRM_loaded_v, 4);

    Serial.print(", ");

    Serial.println(R_thevenin, 4);

  }

  Serial.println("done");

  pixels.clear();

  pixels.show();

  for(int k = 1; k <= 3; k++)

  {

    pixels.setPixelColor(0, pixels.Color(0, 20, 0));

    pixels.setPixelColor(1, pixels.Color(0, 20, 0));

    pixels.setPixelColor(2, pixels.Color(0, 20, 0));

    pixels.setPixelColor(3, pixels.Color(0, 20, 0));

    pixels.show();

    delay(100);

    pixels.clear();

    pixels.show();

    delay(100);

  }

    tone(BUZZ, 587);

    delay(150);

    tone(BUZZ, 494);

    delay(150);

    tone(BUZZ, 391);

    delay(150);

    noTone(BUZZ); 

    

  delay(300000);

}