3dbeergoggles

Dual Channel Arduino Bias Tester beta 14

Jun 21st, 2022
627
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 10.35 KB | None | 0 0
  1. //Ver14: Implemented option for tubes that don't use screen grids to disable 5.5% grid calculation, added "Debug" tube to check direct measurement.
  2. //Ver13: Removed unneeded commented-out code sections
  3.  
  4. //Ver12: Rewrote bias calculation/display section to format values into padded text so flicker-inducing line blanking can be removed
  5.  
  6. //Next two are needed for the SH1106 compatible OLED library
  7. #include <Arduino.h>
  8. #include <U8x8lib.h>
  9.  
  10.  
  11. //Of the oroginal code, basically all that's left is the menu. This uses a different display library, an I2C ADC board, and displays two channels at the time time rather than one.
  12. //Please note that this code is rough and not even properly tidied up, so apologies for the mess.
  13. //This uses the Adafruit ADS1015 precision ADC board; rather than the internal Arduino ADC. The OLED display also runs on the I2C bus. Pushbuttons go to digital input 5,6,7
  14.  
  15. /**
  16.  * This work is licensed under a Creative Commons Attribution 4.0 International License. https://creativecommons.org/licenses/by/4.0/
  17.  * Please give credit to John Wagner - [email protected]
  18.  *
  19.  * ArduinoBiasMeter
  20.  a bias plug that is read in MILLIVOLTS. At no point should more than 5v be
  21.  *  read on this meter.
  22.  *  
  23.  *  Version 1.0 11/28/2017
  24.  */
  25.  
  26. // include the display library code:
  27. #include <Wire.h>
  28.  
  29.  
  30. //ADC Library
  31. #include <Adafruit_ADS1015.h>
  32.  
  33.  
  34.  
  35.  
  36. //Display Initialization
  37.  
  38.  
  39. //SH1106 OLED
  40. U8X8_SH1106_128X64_NONAME_HW_I2C lcd(A5,A4,U8X8_PIN_NONE);
  41.  
  42.  
  43. Adafruit_ADS1115 ads(0x48);
  44.  
  45.  
  46. //Note Changes these to ints, adjust math in the doBias section to avoid "fuzziness" of floats.
  47.  
  48. float VoltageA = 0.0;
  49. float CurrentA = 0.0;
  50. float ScreenCurrentA = 0.0;
  51. float VoltageB = 0.0;
  52. float CurrentB = 0.0;
  53. float ScreenCurrentB = 0.0;
  54. float PowerA = 0.0;
  55. float PowerB = 0.0;
  56.  
  57. float CurrentAPrevious = 0.0;
  58. float CurrentBPrevious = 0.0;
  59. float VoltageAPrevious = 0.0;
  60. float VoltageBPrevious = 0.0;
  61.  
  62. bool FirstBiasRun = false; //ensure results are displayed when started up with static inputs
  63.  
  64.  
  65.  
  66. int guiClick = 7; //Selector button
  67. //Prepping variables for Left/Right Digital buttons
  68. int guiLClick = 5;
  69. int guiRClick = 6;
  70.  
  71.  
  72. //presently the GUI has two modes
  73. #define GUI_MENU_SELECT_MODE 0
  74. #define GUI_BIAS_MODE 1
  75. //the GUI starts in menu mode
  76. int guiMode = GUI_MENU_SELECT_MODE;
  77. boolean movedMenu = false;
  78. int curMenuItem = 0;
  79.  
  80.  
  81.  
  82. //tube record
  83. struct TUBE
  84. {
  85.   String name;
  86.   int maxDissipation;
  87.   bool screengrid;
  88. };
  89.  
  90. //currently supported tubes - Tube name, max wattage, and TRUE/FALSE to subtract 5.5% for screen current
  91. TUBE tubes[] = { {"6L6GC", 30, true }, {"EL34", 25, true}, {"6V6", 12, true}, {"6L6/G/GB", 19, true} ,{"6L6WGB/WGC", 26, true} , {"5881", 23, true}, {"5881WXT", 26, true},{"6550", 42, true},{"EL84", 12, true},{"RAW No Ig2", 100, false} };
  92. #define arr_len( x )  ( sizeof( x ) / sizeof( *x ) )
  93.  
  94.  
  95. //voltage record for averaging
  96. struct VOLTAGE_AVG
  97. {
  98.   double pinVal; //average value read from pin
  99.   int count; //number of times pin value read
  100.   int pin;  //which pin
  101.   double voltage; //calculated voltage
  102. };
  103.  
  104. void zero(VOLTAGE_AVG *_this)
  105. {
  106.   _this->pinVal = 0;
  107.   _this->count = 0;
  108. }
  109.  
  110.  
  111.   char LeftArrow = 127;
  112.   char RightArrow = 126;
  113.  
  114.  
  115.  
  116.  
  117. void setup()
  118. {
  119.   //set the joystick pin to pullup
  120.   pinMode(guiClick, INPUT_PULLUP);
  121.   pinMode(guiRClick, INPUT_PULLUP);
  122.   pinMode(guiLClick, INPUT_PULLUP);
  123.  
  124.   //setup the LCD
  125.  
  126.  
  127.  
  128. //Config for SH1106. Uncomment only one!
  129.  
  130. lcd.begin();
  131.   lcd.setFont(u8x8_font_5x7_f);
  132.  // lcd.setFlipMode(1); //rotate display 180 degrees
  133.  
  134.  
  135. //uncomment and and edit as desired for boot-up screen.
  136. lcd.print("  Bias Tester\n Kiel Lydestad\n     2019");
  137.  
  138.  
  139.  
  140.  
  141.  delay(750);
  142.  
  143.  lcd.clear();
  144.  
  145.   //Configure ADC Gain
  146.   ads.setGain(GAIN_SIXTEEN);
  147.   ads.begin();
  148.  
  149. }
  150. void loop()
  151. {
  152.  
  153.   if (guiMode == GUI_MENU_SELECT_MODE)
  154.   {
  155.     if (processTubeMenu() == 1)
  156.     {
  157.      
  158.       //zero(&plate);
  159.       //zero(&cathode);
  160.       guiMode = GUI_BIAS_MODE;
  161.      
  162.       lcd.clear();
  163.       lcd.print(tubes[curMenuItem].name);
  164.       lcd.print(":");
  165.       lcd.setCursor(0, 1);
  166.       lcd.print(round(floor(tubes[curMenuItem].maxDissipation * .5)));
  167.       lcd.print("|");
  168.       lcd.print(round(floor(tubes[curMenuItem].maxDissipation * .6)));
  169.       lcd.print("|");
  170.       lcd.print(round(floor(tubes[curMenuItem].maxDissipation * .7)));
  171.       lcd.print("|");
  172.       lcd.print(tubes[curMenuItem].maxDissipation);
  173.  
  174.       //Screen header writes
  175.  
  176.       lcd.setCursor(0, 2);
  177.       lcd.setInverseFont(1);
  178.       lcd.print("A:");
  179.       lcd.setInverseFont(0);
  180.  
  181.       lcd.setCursor(8, 2);
  182.       lcd.setInverseFont(1);
  183.       lcd.print("B:");
  184.       lcd.setInverseFont(0);
  185.  
  186.  
  187.       lcd.setCursor(0,7);
  188.       lcd.setInverseFont(1);
  189.       lcd.print("Delta:");
  190.       lcd.setInverseFont(0);
  191.  
  192.  
  193.      
  194.      FirstBiasRun = true; //Makes sure that initial bias display shows data
  195.    
  196.  
  197.      
  198.      // lcd.print("w");
  199.     }
  200.   }
  201.   else if (guiMode == GUI_BIAS_MODE)
  202.   {
  203.     lcd.setCursor(0, 1);
  204.  
  205.     doBias();
  206.  
  207.     if (buttonClicked()) //Centre Button clicked
  208.     {
  209.       lcd.clear();
  210.       guiMode = GUI_MENU_SELECT_MODE;
  211.     }
  212.   }
  213.  
  214.   //delay(100);
  215. }
  216.  
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.  
  224. void doBias()
  225. {
  226.  
  227.   int16_t adc0;  // we read from the ADC, we have a sixteen bit integer as a result
  228.   int16_t adc1;
  229.   int16_t adc2;
  230.   int16_t adc3;
  231.   float aWattPerc = 0;
  232.   float bWattPerc = 0;
  233.  
  234.   char DisplayChar[6];
  235.   float CurrentDiff = 0;
  236.  
  237.  
  238.  
  239.   //Read voltages from all four channels
  240.   adc0 = ads.readADC_SingleEnded(0); //Channel A Voltage
  241.   adc1 = ads.readADC_SingleEnded(1); //Channel A Current
  242.   adc2 = ads.readADC_SingleEnded(2); //Channel B Voltage
  243.   adc3 = ads.readADC_SingleEnded(3); //Channel B Current
  244.  
  245.  //Multiply digital output reading by step value per bit
  246.   VoltageA = (adc0 * 0.078125);
  247.   CurrentA = (adc1 * 0.0078125);
  248.   VoltageB = (adc2 * 0.078125);
  249.   CurrentB = (adc3 * 0.0078125);
  250.  
  251.   //Subtract 5.5% of reading to approximate screen current
  252.  
  253.   if (tubes[curMenuItem].screengrid == false){
  254.      
  255.   }
  256.   else{
  257.     ScreenCurrentA = (CurrentA * 0.055);
  258.     ScreenCurrentB = (CurrentB * 0.055);
  259.     CurrentA = (CurrentA - ScreenCurrentA);
  260.     CurrentB = (CurrentB - ScreenCurrentB);
  261.   }
  262.  
  263.  
  264.   //Tube A readings
  265.  
  266.  
  267. //Clear line and write data
  268.  
  269. //Volts
  270.   if (VoltageA != VoltageAPrevious || FirstBiasRun){
  271.   lcd.setCursor(0, 3);
  272.   dtostrf(VoltageA, -6, 1, DisplayChar);
  273.   lcd.print(DisplayChar);
  274.   lcd.setCursor(6, 3);
  275.   lcd.print("V");
  276.   }
  277. //mA
  278.   if (CurrentA != CurrentAPrevious || FirstBiasRun){
  279.   lcd.setCursor(0, 4);
  280.   dtostrf(CurrentA, -5, 1, DisplayChar);
  281.   lcd.print(DisplayChar);
  282.   lcd.setCursor(5, 4);
  283.   lcd.print("mA");
  284.   }
  285.  
  286. //Watts
  287.   if (VoltageA != VoltageAPrevious || CurrentA != CurrentAPrevious || FirstBiasRun){
  288.   lcd.setCursor(0, 5);
  289.   dtostrf(abs((CurrentA * VoltageA) / 1000), -6, 1, DisplayChar);
  290.   lcd.print(DisplayChar);
  291.  
  292.   lcd.setCursor(6, 5);
  293.   lcd.print("W");
  294.  
  295. //% Rating
  296.   lcd.setCursor(0,6);
  297.   aWattPerc = ((CurrentA * VoltageA) / 1000);
  298.   dtostrf(abs((aWattPerc / tubes[curMenuItem].maxDissipation) * 100), -6, 1, DisplayChar);
  299.   lcd.print(DisplayChar);
  300.   lcd.setCursor(6,6);
  301.   lcd.print("%");
  302.  
  303.   }
  304.  
  305.   //Tube B readings
  306.  
  307.  //Volts
  308.   if (VoltageB != VoltageBPrevious || FirstBiasRun){
  309.   lcd.setCursor(8, 3);
  310.   dtostrf(VoltageB, -6, 1, DisplayChar);
  311.   lcd.print(DisplayChar);
  312.   lcd.setCursor(15, 3);
  313.   lcd.print("V");
  314.   }
  315.  
  316. //mA
  317.   if (CurrentB != CurrentBPrevious || FirstBiasRun){
  318.   lcd.setCursor(8,4);
  319.   dtostrf(CurrentB, -5, 1, DisplayChar);
  320.   lcd.print(DisplayChar);
  321.  
  322.   lcd.setCursor(14, 4);
  323.   lcd.print("mA");
  324.   }
  325.  
  326.  
  327.   //Watts
  328.   if (VoltageB != VoltageBPrevious || CurrentB != CurrentBPrevious|| FirstBiasRun){
  329.  
  330.   lcd.setCursor(8, 5);
  331.   dtostrf(abs((CurrentB * VoltageB) / 1000), -6, 1, DisplayChar);
  332.   lcd.print(DisplayChar);
  333.   lcd.setCursor(15, 5);
  334.   lcd.print("W");
  335.  
  336. //% Dissipation
  337.   lcd.setCursor(8,6);
  338.   bWattPerc = ((CurrentB * VoltageB) / 1000);
  339.   dtostrf(abs((bWattPerc / tubes[curMenuItem].maxDissipation) * 100), -6, 1, DisplayChar);
  340.   lcd.print(DisplayChar);
  341.   lcd.setCursor(15,6);
  342.   lcd.print("%");
  343.   }
  344.  
  345. //Tube A/B difference calculation
  346.  
  347.  
  348.   if (CurrentAPrevious != CurrentA || CurrentBPrevious != CurrentB || VoltageAPrevious != VoltageA || VoltageBPrevious !=VoltageB || FirstBiasRun){
  349.   lcd.setCursor(7,7);
  350.   //lcd.print((CurrentA - CurrentB),1);
  351.  
  352.   CurrentDiff = CurrentA - CurrentB;
  353.  
  354.   CurrentDiff = abs(CurrentDiff);
  355.  
  356.   dtostrf(abs(CurrentDiff), -5, 1, DisplayChar);
  357.   lcd.print(DisplayChar);
  358.  
  359.   lcd.setCursor(14,7);
  360.   lcd.print("mA");
  361.   }
  362.  
  363.  
  364. //Setting previous data values to evaluate if data has changed
  365. CurrentAPrevious = CurrentA;
  366. CurrentBPrevious = CurrentB;
  367. VoltageAPrevious = VoltageA;  
  368. VoltageBPrevious = VoltageB;
  369. FirstBiasRun = false;  //Flag for first-time run to ensure data has written
  370. }
  371.  
  372.  
  373.  
  374. int processTubeMenu()
  375. {
  376.   displayTubeTypes(); //disply the types of tubes
  377.  
  378.  
  379.  
  380.   if (debouncedButtonPressed(guiLClick) == true && movedMenu == false)
  381.   {
  382.     lcd.clearLine(1);
  383.     lcd.clearLine(2);
  384.     movedMenu = true;
  385.     curMenuItem--;
  386.     if (curMenuItem < 0)
  387.     {
  388.       curMenuItem = arr_len(tubes) - 1;
  389.     }
  390.   }
  391.   else if (debouncedButtonPressed(guiRClick) == true && movedMenu == false)
  392.   {
  393.     lcd.clearLine(1);
  394.     lcd.clearLine(2);
  395.     movedMenu = true;
  396.     curMenuItem++;
  397.     if (curMenuItem >= arr_len(tubes))
  398.     {
  399.       curMenuItem = 0;
  400.     }
  401.   }
  402.  
  403.  
  404.  else if (debouncedButtonPressed(guiRClick) == false && debouncedButtonPressed(guiLClick) == false)
  405. {
  406.  movedMenu = false;
  407. }
  408.  
  409.   if (buttonClicked()) //joystick clicked
  410.   {
  411.     return 1;
  412.   }
  413.  
  414.   return 0;
  415. }
  416.  
  417. void displayTubeTypes()
  418. {
  419.   lcd.setCursor(0, 0);
  420.   lcd.print("Select Tube");
  421.   lcd.setCursor(0, 1);
  422.   lcd.print("<");
  423.  // lcd.print(" ");
  424.   lcd.print(tubes[curMenuItem].name);
  425.   lcd.print(" ");
  426.   lcd.print(tubes[curMenuItem].maxDissipation);
  427.   lcd.print("W");
  428.   lcd.print(">");
  429.  // lcd.print("   "); //trailing clear removed 7-17-2019
  430.  
  431.  
  432. }
  433.  
  434. //debounce the button
  435.  
  436. boolean buttonClicked()
  437. {
  438.   if (digitalRead(guiClick) == LOW)
  439.   {
  440.     delay(30);
  441.     if (digitalRead(guiClick) == LOW)
  442.     {
  443.       return true;
  444.     }
  445.   }
  446.   return false;
  447. }
  448.  
  449.  
  450. boolean debouncedButtonPressed(int inputPin)
  451. {
  452.   if (digitalRead(inputPin) == LOW)
  453.   {
  454.     delay(30);
  455.     if (digitalRead(inputPin) == LOW)
  456.     {
  457.       return true;
  458.     }
  459.   }
  460.   return false;
  461. }
Advertisement
Add Comment
Please, Sign In to add comment