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.
![](https://www.google.com/images/icons/product/drive-32.png)
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.
![](https://www.google.com/images/icons/product/drive-32.png)
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);
}