Recently, I wanted to make a laboratory grade linear semi-precision power supply using an Arduino, LCD, some comparators, and MOSFETs. Idealistically, I want measurements to be 3 significant figures of precision (0.1% accuracy @ 30V), voltages as high as 30V, and max current of 10A. The power supply is most likely going to be just a single regulated output, maybe if I feel lucky I will make 2 regulated outputs once I get the darn Arduino code to work. The Arduino's job is to simply set and read the output voltage, and is not part of the control loop. That is what the comparators are for. (I learned the hard way that using the Arduino within the control loop just results in parasitic oscillations because the Arduino is a clocked device and can only self correct at timed intervals.) Anyway, below is the code. I made explanations of all portions of it as clear as possible, and I also give the wiring used for the LCD, 4 buttons, and analog inputs used to set and read the voltage and current. However, the issue arises when I upload the code, the setVI button does not work unless I press both it and the RS button at same time. I made the many of the integers display in the serial output to diagnosing easier hopefully. I can see the setVI integer and my dudd integer only goes HIGH when either it and the RS buttons are pressed simultaneously, or when the RS butten is held down for a long enough time. However, as far as I am aware, nowhere in the code do I manipulate that code so setVI goes HIGH dependant on other buttons, so I am bewildered by this parasitic phenomenon. Is my Arduino MEGA broken? I had a similar problem in the past, where I had multiple analogRead statements It strangely seemed to factor in the outputs of other input pins. Anyway, here is the code. Maybe someone could upload it and tell me if it functions properly on their arduino? That would help me determine if it is indeed a software issue. (p.s. I use an Arduino ripoff called the Funduino, but it is not broken in any way, I don't think?) Any and all help would be greatly appreciated, thank you in advance, -Max-. p.s. To make the code below legible, please copy/paste it in an IDE or in notepad and convert it into a monospaced font, it will make it very easy to follow. //---------------------------------------------------------------------------------------------------------------// /* Arduino Software for lab power supply. Wireing guide: **Wiring for 16x2 LCD:** * LCD RS pin to digital pin 12 * LCD Enable pin to digital pin 11 * LCD D4 pin to digital pin 5 * LCD D5 pin to digital pin 4 * LCD D6 pin to digital pin 3 * LCD D7 pin to digital pin 2 * LCD R/W pin to ground * 10K resistor: * ends to +5V and ground * wiper to LCD VO pin (pin 3) **Wiring for buttons:** * RS button to pin 6 (as a digital input) -- Switches from reading read current/voltage values to setting those values, and Vice Versa. * VIselect button to pin 7 (as a digital input) -- Switches to the 'set' mode and flips from setting the voltage to setting the current. * UP button to pin 8 (as a digital input) -- Increments the voltage or current up when in the 'set' mode. * DOWN button to pin 9 (as a digital input) -- Increments the voltage or current up when in the 'set' mode. **Analog inputs/outputs:** *A0 -- Measures a potential of a resistor divider that can output a voltage of 0-5V based on the 0-30V output this PSW capable of. *A1 -- Measures the current flow through a resistor to measure current. (Some reason there seems to be a pulldown resistor on this pin, so the voltage does not float.) *Vout -- This will be later implemented if I get a DAC, for the increased resolution. (1024 is just not enough in my opinion. At least 12 bits) *Aout -- This will be later implemented if I get a DAC, for the increased resolution. (1024 is just not enough in my opinion. At least 12 bits) */ int UP = 0; // These are the 2 buttons used to incrementally int DOWN = 0; // step up or down the voltage on the output int RS = 0; // These 2 buttons tell the LCD to either read out the voltage on the analog pins. (I plan to change this so it reads from a 14 bit ADC and writes int setVI = 0; // the voltage output through a 14 (or 16 bit) bit ADC. I need 3 significant digits, or at least 0.1% accuracy. int dudd = 0; // this dudd (dummy variable) is just here to prove that digitaslreading pin 7 works very weird! Any help on this? int preRS = 1; // Anything with a "Pre" before it is simply what said integer/variable on the last loop. I use these to prevent a parasitic int presetVI = 1; // oscillation of states that they control, so when a button is pressed, it will not jump between 2 states every cycle. int preUP = 0; int preDOWN = 0; float Aset = 0.00; // I need these to be "floated" so I can set the exact value of these to 3 significant digits. float Vset = 0.00; // Aset and Vset define what the output voltage *should* be, and are defined with the UP/DOWN buttons. int VIselection = 1;// this variable will invert when Aset button is pressed. Similar to the IVselect, this number will also invert int READorSET = 1; // Bset button is pressed. This allows the mode to be changed from SET mode or the READ output mode, thus allowing // one to compare the output voltage and current to the set value, as well as set the output voltage and current. #include LiquidCrystal lcd(12, 11, 5, 4, 3, 2);// initialize the library with the numbers of the interface pins void setup() { //-------------------------// I tried making diagnosting this thing easier by making all the important data availible in the serial monitor. lcd.begin(16, 2); Serial.begin(9600); Serial.print("INPUTS RS: READorSET: setVI & dudd: VIselection:"); Serial.println(""); } void loop() { float V = (30.00*analogRead(A0))/1024.00; //These are what I use to read the voltage output of my power supply. I will have a voltage divider on the output, float A = (15.000*analogRead(A1))/1024.000; //to limit the voltage range from 0-30V to 0-5V. Same concept goes for the current measurement. int dudd = digitalRead(7);// RS = digitalRead(6);//RS stands for "Read/set" setVI = digitalRead(7);//VI is stands for "Current/Voltage set" UP = digitalRead(8);//UP is simply a button used to set voltage & current DOWN = digitalRead(9);//DOWN is simply a button used to set voltage & current if(presetVI == LOW && setVI == HIGH){VIselection = -VIselection;} if(preRS == LOW && RS == HIGH){READorSET = -READorSET;} Serial.print("\t "); // prints an inital space. Serial.print(RS); // prints the RS reading. It should be '1' when pin 7 is HIGH. Serial.print("\t "); Serial.print(READorSET); // prints the READorSET reading. This should only change when the RS button is pressed. Serial.print("\t "); Serial.print(setVI); // prints the setVI reading. It should be '1' when pin 7 is HIGH. Serial.print("\t"); Serial.print(dudd); // prints the setVI reading. It should be '1' when pin 7 is HIGH. Serial.print("\t "); Serial.println(VIselection); // prints the VIselection reading. This should only change when the setVI button is pressed. //if(presetVI == LOW && setVI == HIGH && READorSET == 1) {READorSET = -READorSET; VIselect = -VIselect;} // This line of code just makes so that when I need to go from the voltage read screen to // the set mode, I can just press the VIselect button. It just makes things more intuitive, but could be // causeing the error, so I nulled it. I also nulled it out another portion that will keep the voltage or // current setting the same when using the VI buttton to select the set mode. (otherwise it has to be // double pressed to return to, say, the current setting, if that is where you left off.) if(UP == HIGH && DOWN == LOW && VIselection == -1){if(Aset <= 10.00) {Aset += 0.05;}} if(DOWN == HIGH && UP == LOW && VIselection == -1){if(Aset >= 0.10) {Aset -= 0.05;}} if(UP == HIGH && DOWN == LOW && VIselection == 1) {if(Vset <= 30.00) {Vset += 0.05;}} if(DOWN == HIGH && UP == LOW && VIselection == 1) {if(Vset >= 0.05) {Vset -= 0.05;}} if (RS == HIGH){digitalWrite(13, 1);} if (RS == LOW){digitalWrite(13, 0);} //============================================================================================================// if (READorSET == 1){ //this is the defualt screen, and shows the output voltage and current. lcd.clear(); lcd.setCursor(0, 0); lcd.print("VOLTAGE:"); lcd.setCursor(0, 1); lcd.print("CURRENT:"); lcd.setCursor(10, 0); lcd.print(V); lcd.setCursor(15, 0); lcd.print("V"); lcd.setCursor(10, 1); lcd.print(A); lcd.setCursor(15, 1); lcd.print("A"); } if (READorSET == -1){ // This is the portion of the code allowing me to set the current and voltage lcd.clear(); // using the up/down buttons. if (VIselection == -1){ lcd.setCursor(0, 0); lcd.print(" SET CURRENT:"); lcd.setCursor(5, 1); lcd.print(Aset); lcd.print("A "); } if(VIselection == 1){ lcd.setCursor(0, 0); lcd.print(" SET VOLTAGE:"); lcd.setCursor(5, 1); lcd.print(Vset); lcd.print("V "); } } //============================================================================================================// presetVI = setVI; // At the end of each loop, the current variable settings that were used are set equal preRS = RS; // to the 'pre' versions of the code. This allows me to basically measure the when // the button is initially pressed, and/or released. Using this method with the delay() // function, however, is a bit buggy, but I did have it working well enough before. If you // tap the button too quickly. You almost have to hold it for a split second. If you // know a better, simpler way of doing this, please tell me, thank you. delay(80); // The delay helps stabilize the reading on the LCD, but if it is too large, than the // refresh rate suffers, and the buttons respond slower. However, setting too low will // cause the reading on the display to change so rapidly, it is illegible. }