germanium_tester.ino 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. #include <Adafruit_ADS1X15.h>
  2. #include <SPI.h>
  3. #include <Wire.h>
  4. #include <Adafruit_GFX.h>
  5. #include <Adafruit_SSD1306.h>
  6. float computeMilliVolts(int16_t counts);
  7. #define SCREEN_WIDTH 128 // OLED display width, in pixels
  8. #define SCREEN_HEIGHT 64 // OLED display height, in pixels
  9. #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
  10. #define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
  11. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  12. Adafruit_ADS1115 ads; /* Use this for the 16-bit version */
  13. // These constants won't change. They're used to give names to the pins used:
  14. // constants won't change. They're used here to set pin numbers:
  15. const int emitterPin = 2; // arduino pin the emitter pin of the transistor is on
  16. const int basePin = 3; // arduino pin the base pin of the transistor is on
  17. const int collectorPin = 5; // arduino pin the collector pin of the transistor is on
  18. const int collectorResistorPin = 6; // arduino pin the collector resistor is on
  19. const int baseResistorPin = 7; // arduino pin the base resistor is on
  20. // variables will change:
  21. int collectorPinState = 0; // variable for reading the collector pin status
  22. int transistorType = 0; // Type 0 is NPN, Type 1 is PNP
  23. void setup() {
  24. int16_t adc0, adc1; // variables to hold the 16-bit ADC reading
  25. float collector_milliVolts = 0.0; // variable to hold the collector voltage in milli-volts
  26. float rail_milliVolts = 0.0; // variable to hold the rail voltage in milli-volts
  27. float leak_milliVolts = 0.0; // variable to hold leakage voltage in milli-volts
  28. float leak_uA = 0.0; // variable to hold leakage current in micro-amps
  29. float baseCurrent_uA = 0.0; // variable to hold the base current in micro-amps
  30. float gain = 0.0; // variable to hold the gain (which includes the leakage)
  31. float trueGain = 0.0; // variable to hold the true gain (subtracting leakage)
  32. // below are the results of resistance of the resistors used on this board.
  33. int16_t collector_resistor = 997; // collector resistor 1K is really 0.997K
  34. long base_resistor = 1204000; // base resistor 1.2M is really 1.204M
  35. // initialize serial communications at 9600 bps:
  36. Serial.begin(9600);
  37. // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  38. if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
  39. Serial.println(F("SSD1306 allocation failed"));
  40. for(;;); // Don't proceed, loop forever
  41. }
  42. // Show initial display buffer contents on the screen --
  43. // the library initializes this with an Adafruit splash screen.
  44. display.display();
  45. if (!ads.begin()) {
  46. Serial.println("Failed to initialize ADS.");
  47. while (1);
  48. }
  49. // In this step, we will set the emitter pin to GND and the base pin
  50. // to 5 volts. So, we need to set the emitter and base pins to output
  51. // mode, so we can connect them to those power rails. The collector
  52. // pin will need to be set to input, as we will use this to see if the
  53. // transistor is an NPN or PNP germanium transistor
  54. pinMode(emitterPin, OUTPUT);
  55. pinMode(basePin, OUTPUT);
  56. pinMode(collectorPin, INPUT);
  57. digitalWrite(emitterPin, LOW); // set the emitter pin to GND
  58. digitalWrite(basePin, HIGH); // set the base pin to 5V
  59. delay(50); // wait a moment
  60. // see what the voltage is on the collector pin
  61. collectorPinState = digitalRead(collectorPin);
  62. // based off if voltage was detected on the collector pin...
  63. if (collectorPinState == HIGH) {
  64. // if we saw the voltage from the base pin jump over to the collector pin,
  65. // it's a PNP transistor (type 1)
  66. transistorType = 1;
  67. } else {
  68. // otherwise, the voltage from the base pin did not jump to the collector
  69. // pin, it's an NPN transistor (type 0)
  70. transistorType = 0;
  71. // if it is a silicon PNP transistor, this will have the same effect as an NPN
  72. // so it doesn't work.
  73. }
  74. delay(50); // wait a moment
  75. // reset the emitter and base pins and set them back to floating
  76. digitalWrite(emitterPin, LOW);
  77. pinMode(emitterPin, INPUT);
  78. digitalWrite(basePin, LOW);
  79. pinMode(basePin, INPUT);
  80. delay(50); // wait a moment
  81. // Now that we know if we have an NPN or PNP transistors, we can begin to read leak
  82. // of the transistor.
  83. // if it is a PNP transistor, emitter goes to 5V and collector goes through the
  84. // collector resistor to ground.
  85. // if it is an NPN transistor, emitter goes to ground and collector goes through the
  86. // collector resistor to 5V.
  87. if(transistorType == 1) {
  88. // Transistor is PNP
  89. pinMode(emitterPin, OUTPUT); // Set emitter pin to output so that we can...
  90. digitalWrite(emitterPin, HIGH); // Emitter goes straight to 5V
  91. pinMode(collectorResistorPin, OUTPUT);
  92. digitalWrite(collectorResistorPin, LOW); // Collector goes to ground via collector resistor
  93. } else {
  94. // Transistor is NPN
  95. pinMode(emitterPin, OUTPUT); // Set emitter pin to output so that we can...
  96. digitalWrite(emitterPin, LOW); // Emitter goes straight to ground
  97. pinMode(collectorResistorPin, OUTPUT);
  98. digitalWrite(collectorResistorPin, HIGH); // Collector goes to 5V via collector resistor
  99. }
  100. // read in voltages from the 16-bit ADC
  101. adc0 = ads.readADC_SingleEnded(0);
  102. adc1 = ads.readADC_SingleEnded(1);
  103. // rail voltage goes into ADC0 and collector voltage goes into ADC1
  104. rail_milliVolts = computeMilliVolts(adc0);
  105. collector_milliVolts = computeMilliVolts(adc1);
  106. // ohms law, V / R = I. Because we want current in uA and the volts are in milliVolts,
  107. // we need to multiply by 1000.0. This will give us the current from the base pin.
  108. // we have not applied base current at this point, but will do so later on.
  109. baseCurrent_uA = (rail_milliVolts * 1000.0) / base_resistor;
  110. if(transistorType == 1) {
  111. // Transistor is PNP
  112. // in case we get any weird jitter on the collector pin
  113. if(collector_milliVolts <= 0.1) {
  114. collector_milliVolts = 0.0;
  115. }
  116. // the leakage has caused an amount of collector voltage that we need to record and subtract
  117. // from the gain, when we get to that point.
  118. leak_milliVolts = collector_milliVolts;
  119. // ohms law, V / R = I. Because we want current in uA and the volts are in milliVolts,
  120. // we need to multiply by 1000.0. This will give us the current from the collector pin.
  121. leak_uA = (leak_milliVolts * 1000.0) / collector_resistor;
  122. // Output our findings thus far out the serial port
  123. Serial.println("PNP Transistor");
  124. Serial.print("PWR Rail: ");
  125. Serial.print(rail_milliVolts);
  126. Serial.println("mV");
  127. Serial.print("Collector: ");
  128. Serial.print(leak_milliVolts);
  129. Serial.println("mV");
  130. Serial.print("Leak: ");
  131. Serial.print(leak_uA);
  132. Serial.println("uA");
  133. Serial.print("Base: ");
  134. Serial.print(baseCurrent_uA);
  135. Serial.println("uA");
  136. delay(50); // wait a moment
  137. // now we set the base pin to output and apply a small, but pre-calculated, current over it.
  138. pinMode(baseResistorPin, OUTPUT);
  139. digitalWrite(baseResistorPin, LOW); // Base goes to ground via base resistor because it is PNP
  140. // read in voltages from the 16-bit ADC
  141. adc0 = ads.readADC_SingleEnded(0);
  142. adc1 = ads.readADC_SingleEnded(1);
  143. // rail voltage goes into ADC0 and collector voltage goes into ADC1
  144. rail_milliVolts = computeMilliVolts(adc0);
  145. collector_milliVolts = computeMilliVolts(adc1);
  146. // gain is collector-voltage / collector-resistance / base-current
  147. // so if we have 750 millivolts on the collector after applying 4uA of current to the base pin,
  148. // and we are using a 1K resistor for the collector resistor, the our gain calculation would look like this:
  149. // gain = (750mV / 1000) / 1000 ohms / (4uA / 1,000,000)
  150. // gain = 0.75V / 1000 ohms / 0.000004A
  151. // gain = 187.5
  152. gain = (collector_milliVolts / 1000.0) / collector_resistor / (baseCurrent_uA / 1000000.0);
  153. // however, this isn't the true story. The leakage voltage also goes over the collector resistor, so we must subtract
  154. // the leakage voltage from the collector voltage. So, if we had a leakage voltage of 100mV (which with a 1K collector
  155. // resistor is 100uA of leakage current), we don't actually have 750 millivolts on the collector after applying the
  156. // 4uA of current to the base pin, but rather 750mV - 100mV = 650mV, so the true gain would calculate as:
  157. // gain = (650mV / 1000) / 1000 ohms / (4uA / 1,000,000)
  158. // gain = 0.65V / 1000 ohms / 0.000004A
  159. // gain = 162.5
  160. trueGain = ((collector_milliVolts - leak_milliVolts) / 1000.0) / collector_resistor / (baseCurrent_uA / 1000000.0);
  161. // output our findings out the serial port
  162. Serial.print("Gain: ");
  163. Serial.print(gain);
  164. Serial.println(" hfe");
  165. Serial.print("True Gain: ");
  166. Serial.print(trueGain);
  167. Serial.println(" hfe");
  168. // clear the OLED display
  169. display.clearDisplay();
  170. display.setTextSize(1); // Normal 1:1 pixel scale
  171. display.setTextColor(SSD1306_WHITE); // Draw white text
  172. display.setCursor(0,0); // Start at top-left corner
  173. display.println(F("PNP Transistor")); // Start printing to screen
  174. // we will continue the rest later
  175. } else {
  176. // Transistor is NPN
  177. // the leakage has caused an amount of collector voltage that we need to record and subtract
  178. // from the gain, when we get to that point. Because the leakage is in reference to the rail
  179. // voltage, as this is an NPN transistor, we must subtract from the rail voltage to get leak
  180. // voltage
  181. leak_milliVolts = rail_milliVolts - collector_milliVolts;
  182. // in case we get any weird jitter on the collector pin
  183. if(leak_milliVolts < 0.1) {
  184. leak_milliVolts = 0.0;
  185. }
  186. // ohms law, V / R = I. Because we want current in uA and the volts are in milliVolts,
  187. // we need to multiply by 1000.0. This will give us the current from the collector pin.
  188. leak_uA = (leak_milliVolts / collector_resistor) * 1000.0;
  189. Serial.println("NPN Transistor");
  190. Serial.print("PWR Rail: ");
  191. Serial.print(rail_milliVolts);
  192. Serial.println("mV");
  193. Serial.print("Collector: ");
  194. Serial.print(leak_milliVolts);
  195. Serial.println("mV");
  196. Serial.print("Leak: ");
  197. Serial.print(leak_uA);
  198. Serial.println("uA");
  199. Serial.print("Base: ");
  200. Serial.print(baseCurrent_uA);
  201. Serial.println("uA");
  202. delay(50); // wait a moment
  203. // now we set the base pin to output and apply a small, but pre-calculated, current over it.
  204. pinMode(baseResistorPin, OUTPUT);
  205. digitalWrite(baseResistorPin, HIGH); // Base goes to 5V via base resistor because it is NPN
  206. // read in voltages from the 16-bit ADC
  207. adc0 = ads.readADC_SingleEnded(0);
  208. adc1 = ads.readADC_SingleEnded(1);
  209. // rail voltage goes into ADC0 and collector voltage goes into ADC1
  210. rail_milliVolts = computeMilliVolts(adc0);
  211. collector_milliVolts = computeMilliVolts(adc1);
  212. // because the collector voltage is in reference to the rail voltage, we have to subtract from the rail voltage
  213. // gain is collector-voltage / collector-resistance / base-current
  214. // so if we have 750 millivolts on the collector after applying 4uA of current to the base pin,
  215. // and we are using a 1K resistor for the collector resistor, the our gain calculation would look like this:
  216. // gain = (750mV / 1000) / 1000 ohms / (4uA / 1,000,000)
  217. // gain = 0.75V / 1000 ohms / 0.000004A
  218. // gain = 187.5
  219. gain = ((rail_milliVolts - collector_milliVolts) / 1000.0) / collector_resistor / (baseCurrent_uA / 1000000.0);
  220. // however, this isn't the true story. The leakage voltage also goes over the collector resistor, so we must subtract
  221. // the leakage voltage from the collector voltage. So, if we had a leakage voltage of 100mV (which with a 1K collector
  222. // resistor is 100uA of leakage current), we don't actually have 750 millivolts on the collector after applying the
  223. // 4uA of current to the base pin, but rather 750mV - 100mV = 650mV, so the true gain would calculate as:
  224. // gain = (650mV / 1000) / 1000 ohms / (4uA / 1,000,000)
  225. // gain = 0.65V / 1000 ohms / 0.000004A
  226. // gain = 162.5
  227. trueGain = (((rail_milliVolts - collector_milliVolts) - leak_milliVolts) / 1000.0) / collector_resistor / (baseCurrent_uA / 1000000.0);
  228. Serial.print("Gain: ");
  229. Serial.print(gain);
  230. Serial.println(" hfe");
  231. Serial.print("True Gain: ");
  232. Serial.print(trueGain);
  233. Serial.println(" hfe");
  234. // clear the OLED display
  235. display.clearDisplay();
  236. display.setTextSize(1); // Normal 1:1 pixel scale
  237. display.setTextColor(SSD1306_WHITE); // Draw white text
  238. display.setCursor(0,0); // Start at top-left corner
  239. display.println(F("NPN Transistor")); // Start printing to screen
  240. // we will continue the rest later
  241. }
  242. // Now display our gain and leakage findings
  243. display.print(F("Gain: "));
  244. display.print(trueGain);
  245. display.println(F(" hfe"));
  246. display.print(F("Leak: "));
  247. display.print(leak_uA);
  248. display.println(F("uA"));
  249. display.display();
  250. // Then reset all pins back to input mode
  251. pinMode(emitterPin, INPUT);
  252. pinMode(basePin, INPUT);
  253. pinMode(collectorPin, INPUT);
  254. pinMode(collectorResistorPin, INPUT);
  255. pinMode(baseResistorPin, INPUT);
  256. // So that we can then set the pins back to floating
  257. digitalWrite(emitterPin, LOW);
  258. digitalWrite(basePin, LOW);
  259. digitalWrite(collectorPin, LOW);
  260. digitalWrite(collectorResistorPin, LOW);
  261. digitalWrite(baseResistorPin, LOW);
  262. }
  263. void loop() {
  264. // wait 500 milliseconds before the next loop for the analog-to-digital
  265. // converter to settle after the last reading:
  266. delay(500);
  267. }
  268. /**************************************************************************/
  269. /*!
  270. @brief Returns true if conversion is complete, false otherwise.
  271. @param counts the ADC reading in raw counts
  272. @return the ADC reading in milli-volts
  273. */
  274. /**************************************************************************/
  275. float computeMilliVolts(int16_t counts) {
  276. uint8_t bitShift = 0; ///< bit shift amount
  277. return counts * 1000.0 * (6.144f / (32768 >> bitShift));
  278. }