123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- #include <Adafruit_ADS1X15.h>
- #include <SPI.h>
- #include <Wire.h>
- #include <Adafruit_GFX.h>
- #include <Adafruit_SSD1306.h>
- float computeMilliVolts(int16_t counts);
- #define SCREEN_WIDTH 128 // OLED display width, in pixels
- #define SCREEN_HEIGHT 64 // OLED display height, in pixels
- #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
- #define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
- Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
- Adafruit_ADS1115 ads; /* Use this for the 16-bit version */
- // These constants won't change. They're used to give names to the pins used:
- // constants won't change. They're used here to set pin numbers:
- const int emitterPin = 2; // arduino pin the emitter pin of the transistor is on
- const int basePin = 3; // arduino pin the base pin of the transistor is on
- const int collectorPin = 5; // arduino pin the collector pin of the transistor is on
- const int collectorResistorPin = 6; // arduino pin the collector resistor is on
- const int baseResistorPin = 7; // arduino pin the base resistor is on
- // variables will change:
- int collectorPinState = 0; // variable for reading the collector pin status
- int transistorType = 0; // Type 0 is NPN, Type 1 is PNP
- void setup() {
- int16_t adc0, adc1; // variables to hold the 16-bit ADC reading
- float collector_milliVolts = 0.0; // variable to hold the collector voltage in milli-volts
- float rail_milliVolts = 0.0; // variable to hold the rail voltage in milli-volts
- float leak_milliVolts = 0.0; // variable to hold leakage voltage in milli-volts
- float leak_uA = 0.0; // variable to hold leakage current in micro-amps
- float baseCurrent_uA = 0.0; // variable to hold the base current in micro-amps
- float gain = 0.0; // variable to hold the gain (which includes the leakage)
- float trueGain = 0.0; // variable to hold the true gain (subtracting leakage)
- // below are the results of resistance of the resistors used on this board.
- int16_t collector_resistor = 997; // collector resistor 1K is really 0.997K
- long base_resistor = 1204000; // base resistor 1.2M is really 1.204M
-
- // initialize serial communications at 9600 bps:
- Serial.begin(9600);
- // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
- if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
- Serial.println(F("SSD1306 allocation failed"));
- for(;;); // Don't proceed, loop forever
- }
- // Show initial display buffer contents on the screen --
- // the library initializes this with an Adafruit splash screen.
- display.display();
- if (!ads.begin()) {
- Serial.println("Failed to initialize ADS.");
- while (1);
- }
- // In this step, we will set the emitter pin to GND and the base pin
- // to 5 volts. So, we need to set the emitter and base pins to output
- // mode, so we can connect them to those power rails. The collector
- // pin will need to be set to input, as we will use this to see if the
- // transistor is an NPN or PNP germanium transistor
- pinMode(emitterPin, OUTPUT);
- pinMode(basePin, OUTPUT);
- pinMode(collectorPin, INPUT);
-
- digitalWrite(emitterPin, LOW); // set the emitter pin to GND
- digitalWrite(basePin, HIGH); // set the base pin to 5V
- delay(50); // wait a moment
- // see what the voltage is on the collector pin
- collectorPinState = digitalRead(collectorPin);
- // based off if voltage was detected on the collector pin...
- if (collectorPinState == HIGH) {
- // if we saw the voltage from the base pin jump over to the collector pin,
- // it's a PNP transistor (type 1)
- transistorType = 1;
- } else {
- // otherwise, the voltage from the base pin did not jump to the collector
- // pin, it's an NPN transistor (type 0)
- transistorType = 0;
- // if it is a silicon PNP transistor, this will have the same effect as an NPN
- // so it doesn't work.
- }
- delay(50); // wait a moment
- // reset the emitter and base pins and set them back to floating
- digitalWrite(emitterPin, LOW);
- pinMode(emitterPin, INPUT);
- digitalWrite(basePin, LOW);
- pinMode(basePin, INPUT);
- delay(50); // wait a moment
- // Now that we know if we have an NPN or PNP transistors, we can begin to read leak
- // of the transistor.
- // if it is a PNP transistor, emitter goes to 5V and collector goes through the
- // collector resistor to ground.
- // if it is an NPN transistor, emitter goes to ground and collector goes through the
- // collector resistor to 5V.
- if(transistorType == 1) {
- // Transistor is PNP
- pinMode(emitterPin, OUTPUT); // Set emitter pin to output so that we can...
- digitalWrite(emitterPin, HIGH); // Emitter goes straight to 5V
- pinMode(collectorResistorPin, OUTPUT);
- digitalWrite(collectorResistorPin, LOW); // Collector goes to ground via collector resistor
- } else {
- // Transistor is NPN
- pinMode(emitterPin, OUTPUT); // Set emitter pin to output so that we can...
- digitalWrite(emitterPin, LOW); // Emitter goes straight to ground
- pinMode(collectorResistorPin, OUTPUT);
- digitalWrite(collectorResistorPin, HIGH); // Collector goes to 5V via collector resistor
- }
- // read in voltages from the 16-bit ADC
- adc0 = ads.readADC_SingleEnded(0);
- adc1 = ads.readADC_SingleEnded(1);
- // rail voltage goes into ADC0 and collector voltage goes into ADC1
- rail_milliVolts = computeMilliVolts(adc0);
- collector_milliVolts = computeMilliVolts(adc1);
- // ohms law, V / R = I. Because we want current in uA and the volts are in milliVolts,
- // we need to multiply by 1000.0. This will give us the current from the base pin.
- // we have not applied base current at this point, but will do so later on.
- baseCurrent_uA = (rail_milliVolts * 1000.0) / base_resistor;
- if(transistorType == 1) {
- // Transistor is PNP
- // in case we get any weird jitter on the collector pin
- if(collector_milliVolts <= 0.1) {
- collector_milliVolts = 0.0;
- }
- // the leakage has caused an amount of collector voltage that we need to record and subtract
- // from the gain, when we get to that point.
- leak_milliVolts = collector_milliVolts;
- // ohms law, V / R = I. Because we want current in uA and the volts are in milliVolts,
- // we need to multiply by 1000.0. This will give us the current from the collector pin.
- leak_uA = (leak_milliVolts * 1000.0) / collector_resistor;
- // Output our findings thus far out the serial port
- Serial.println("PNP Transistor");
- Serial.print("PWR Rail: ");
- Serial.print(rail_milliVolts);
- Serial.println("mV");
- Serial.print("Collector: ");
- Serial.print(leak_milliVolts);
- Serial.println("mV");
- Serial.print("Leak: ");
- Serial.print(leak_uA);
- Serial.println("uA");
- Serial.print("Base: ");
- Serial.print(baseCurrent_uA);
- Serial.println("uA");
- delay(50); // wait a moment
- // now we set the base pin to output and apply a small, but pre-calculated, current over it.
- pinMode(baseResistorPin, OUTPUT);
- digitalWrite(baseResistorPin, LOW); // Base goes to ground via base resistor because it is PNP
- // read in voltages from the 16-bit ADC
- adc0 = ads.readADC_SingleEnded(0);
- adc1 = ads.readADC_SingleEnded(1);
- // rail voltage goes into ADC0 and collector voltage goes into ADC1
- rail_milliVolts = computeMilliVolts(adc0);
- collector_milliVolts = computeMilliVolts(adc1);
- // gain is collector-voltage / collector-resistance / base-current
- // so if we have 750 millivolts on the collector after applying 4uA of current to the base pin,
- // and we are using a 1K resistor for the collector resistor, the our gain calculation would look like this:
- // gain = (750mV / 1000) / 1000 ohms / (4uA / 1,000,000)
- // gain = 0.75V / 1000 ohms / 0.000004A
- // gain = 187.5
- gain = (collector_milliVolts / 1000.0) / collector_resistor / (baseCurrent_uA / 1000000.0);
- // however, this isn't the true story. The leakage voltage also goes over the collector resistor, so we must subtract
- // the leakage voltage from the collector voltage. So, if we had a leakage voltage of 100mV (which with a 1K collector
- // resistor is 100uA of leakage current), we don't actually have 750 millivolts on the collector after applying the
- // 4uA of current to the base pin, but rather 750mV - 100mV = 650mV, so the true gain would calculate as:
- // gain = (650mV / 1000) / 1000 ohms / (4uA / 1,000,000)
- // gain = 0.65V / 1000 ohms / 0.000004A
- // gain = 162.5
- trueGain = ((collector_milliVolts - leak_milliVolts) / 1000.0) / collector_resistor / (baseCurrent_uA / 1000000.0);
- // output our findings out the serial port
- Serial.print("Gain: ");
- Serial.print(gain);
- Serial.println(" hfe");
- Serial.print("True Gain: ");
- Serial.print(trueGain);
- Serial.println(" hfe");
- // clear the OLED display
- display.clearDisplay();
- display.setTextSize(1); // Normal 1:1 pixel scale
- display.setTextColor(SSD1306_WHITE); // Draw white text
- display.setCursor(0,0); // Start at top-left corner
- display.println(F("PNP Transistor")); // Start printing to screen
- // we will continue the rest later
-
- } else {
- // Transistor is NPN
- // the leakage has caused an amount of collector voltage that we need to record and subtract
- // from the gain, when we get to that point. Because the leakage is in reference to the rail
- // voltage, as this is an NPN transistor, we must subtract from the rail voltage to get leak
- // voltage
- leak_milliVolts = rail_milliVolts - collector_milliVolts;
- // in case we get any weird jitter on the collector pin
- if(leak_milliVolts < 0.1) {
- leak_milliVolts = 0.0;
- }
- // ohms law, V / R = I. Because we want current in uA and the volts are in milliVolts,
- // we need to multiply by 1000.0. This will give us the current from the collector pin.
- leak_uA = (leak_milliVolts / collector_resistor) * 1000.0;
-
- Serial.println("NPN Transistor");
- Serial.print("PWR Rail: ");
- Serial.print(rail_milliVolts);
- Serial.println("mV");
- Serial.print("Collector: ");
- Serial.print(leak_milliVolts);
- Serial.println("mV");
- Serial.print("Leak: ");
- Serial.print(leak_uA);
- Serial.println("uA");
- Serial.print("Base: ");
- Serial.print(baseCurrent_uA);
- Serial.println("uA");
- delay(50); // wait a moment
- // now we set the base pin to output and apply a small, but pre-calculated, current over it.
- pinMode(baseResistorPin, OUTPUT);
- digitalWrite(baseResistorPin, HIGH); // Base goes to 5V via base resistor because it is NPN
- // read in voltages from the 16-bit ADC
- adc0 = ads.readADC_SingleEnded(0);
- adc1 = ads.readADC_SingleEnded(1);
- // rail voltage goes into ADC0 and collector voltage goes into ADC1
- rail_milliVolts = computeMilliVolts(adc0);
- collector_milliVolts = computeMilliVolts(adc1);
- // because the collector voltage is in reference to the rail voltage, we have to subtract from the rail voltage
- // gain is collector-voltage / collector-resistance / base-current
- // so if we have 750 millivolts on the collector after applying 4uA of current to the base pin,
- // and we are using a 1K resistor for the collector resistor, the our gain calculation would look like this:
- // gain = (750mV / 1000) / 1000 ohms / (4uA / 1,000,000)
- // gain = 0.75V / 1000 ohms / 0.000004A
- // gain = 187.5
- gain = ((rail_milliVolts - collector_milliVolts) / 1000.0) / collector_resistor / (baseCurrent_uA / 1000000.0);
- // however, this isn't the true story. The leakage voltage also goes over the collector resistor, so we must subtract
- // the leakage voltage from the collector voltage. So, if we had a leakage voltage of 100mV (which with a 1K collector
- // resistor is 100uA of leakage current), we don't actually have 750 millivolts on the collector after applying the
- // 4uA of current to the base pin, but rather 750mV - 100mV = 650mV, so the true gain would calculate as:
- // gain = (650mV / 1000) / 1000 ohms / (4uA / 1,000,000)
- // gain = 0.65V / 1000 ohms / 0.000004A
- // gain = 162.5
- trueGain = (((rail_milliVolts - collector_milliVolts) - leak_milliVolts) / 1000.0) / collector_resistor / (baseCurrent_uA / 1000000.0);
- Serial.print("Gain: ");
- Serial.print(gain);
- Serial.println(" hfe");
- Serial.print("True Gain: ");
- Serial.print(trueGain);
- Serial.println(" hfe");
- // clear the OLED display
- display.clearDisplay();
- display.setTextSize(1); // Normal 1:1 pixel scale
- display.setTextColor(SSD1306_WHITE); // Draw white text
- display.setCursor(0,0); // Start at top-left corner
- display.println(F("NPN Transistor")); // Start printing to screen
- // we will continue the rest later
- }
- // Now display our gain and leakage findings
- display.print(F("Gain: "));
- display.print(trueGain);
- display.println(F(" hfe"));
- display.print(F("Leak: "));
- display.print(leak_uA);
- display.println(F("uA"));
- display.display();
- // Then reset all pins back to input mode
- pinMode(emitterPin, INPUT);
- pinMode(basePin, INPUT);
- pinMode(collectorPin, INPUT);
- pinMode(collectorResistorPin, INPUT);
- pinMode(baseResistorPin, INPUT);
- // So that we can then set the pins back to floating
- digitalWrite(emitterPin, LOW);
- digitalWrite(basePin, LOW);
- digitalWrite(collectorPin, LOW);
- digitalWrite(collectorResistorPin, LOW);
- digitalWrite(baseResistorPin, LOW);
- }
- void loop() {
-
- // wait 500 milliseconds before the next loop for the analog-to-digital
- // converter to settle after the last reading:
- delay(500);
- }
- /**************************************************************************/
- /*!
- @brief Returns true if conversion is complete, false otherwise.
- @param counts the ADC reading in raw counts
- @return the ADC reading in milli-volts
- */
- /**************************************************************************/
- float computeMilliVolts(int16_t counts) {
- uint8_t bitShift = 0; ///< bit shift amount
- return counts * 1000.0 * (6.144f / (32768 >> bitShift));
- }
|