Arduino doesn't work as expected, Seems to be digitalWrite issue? [semi-solved]

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, Powermax.

Here is the code: (I had to break this up so I don't exceed the maximum characters)

/*
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.
      * setVI 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.h>

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 (READorSET == 1){      //this is the defualy 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 butons.

      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 allowes me to basicaly measure the when
                    // the button is initally 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 illegable.
}
if (RS == HIGH){digitalWrite(13, 1);}
  if (RS == LOW){digitalWrite(13, 0);}

or more simply

digitalWrite(13, RS);

Please use auto format on your code

/ I tried making diagnosting this thing easier by making all the important data availible in the serial monitor.

...but you didn't show us any of it.

Please, give you pins some meaningful names.
We can only assume you've got appropriate external pullups fitted on your inputs - you're not using the free ones.

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.

I don't know how hard it was, but this learning is very dubious.

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

This does indeed occur in some circumstances - there is only one ADC shared between the analog pins. The most common solution is simply to read each pin twice and discard the first reading. I've never heard of anything similar on the digital pins though. Your issue smells like floating inputs to me, as AWOL suggested.

Firstly the original problem is a lack of pull-up or pull-down resistors? Seems plausible.

Secondly the ADC - if each input has a source impedance of 10k or less you don't
need to worry about anything the ADC will read to within 1 LSB happily. Its only
very high impedance sources that take more time to settle after switching analog
pins.

OK I have made a lot of progress with diagnosing this circuit, and more and more I am starting to believe it is indeed a hardware issue. That is why I posted this in the hardware issue of this forum. Please excuse me not replying to what I wrote, I registered here on the Arduino forms just yesterday and did not know I had to manually term on notifications.

Anyway, some say I did not wire the physical buttons correctly, but this is not the case. I have the buttons wired the exact same way I have seen other do it. I do have a proper pull-down resistor connected to a switch, which is on the high end of the 5V rail. As I said, this code was working flawlessly before, and just stopped working properly after a very minor change in the naming of some integers.

Some are also telling me that to use proper formatting for this: My answer, the 'proper' formatting just makes things more confusing and hard to follow to me. If you wish, you could add the additional lines for the {curie brackets}.

I have asked the same question on http://www.instructables.com/answers/This-arduino-code-does-not-work-as-expected-any-he/?, and some nice people there have helped me narrow the problem down to something with the Arduino. You can view my thread there and see what I have worked down to.

I ultimately ended up to cutting away the code, (including all the LCD section, all the 'if' statements, and everything else. ) Here is the code I am left with. Notice nowhere in the code do I define my RS pin, but I still have the same problem:

pressing the RS button and holding it down for approx. 25-35 Arduino loops will cause the setVI to magically go HIGH, even though it is grounded.
I can also get it to go HIGH by pressing and holding the setVI button, and then taping the RS button. the second I let go of RS, only pressing the setVI, setVI only goes LOW again.
If I press the RS button down and almost immediately tap the setVI button, I can get it to 'latch' on HIGH for as long as I continue to hold the RS button down.

int setVI = 0;
void setup() {
Serial.begin(9600);
Serial.println("setVI:");
}
void loop() {
setVI = digitalRead(7);
Serial.println(setVI);
}

That is why I posted this in the hardware issue of this forum

Actually, you didn't; you posted in the "Installation and troubleshooting" section, so I moved it here.

I do have a proper pull-down resistor connected to a switch, which is on the high end of the 5V rail.

Pull-down to 5volts. OK.

Assuming the code in Reply #6 is the total code needed to demonstrate the problem can you post the accompanying wiring diagram? It doesn't make much sense without that.

...R

AWOL:

if (RS == HIGH){digitalWrite(13, 1);}

if (RS == LOW){digitalWrite(13, 0);}



or more simply


digitalWrite(13, RS);




Please use auto format on your code



> / I tried making diagnosing this thing easier by making all the important data available in the serial monitor.


...but you didn't show us any of it.

Please, give you pins some meaningful names.
We can only assume you've got appropriate external pullups fitted on your inputs - you're not using the free ones.

I formatted the code so that I can read and interpret it the best for myself, since ultimately I am the one making it, and I am not used to the 'proper' formatting. I will autoformat it and repost it if you think it will be more legible that way.

Rest assured, I made sure that the hardware was correctly wired. Like I said, this whole thing was working almost flawlessly until I changed a few of the integers' names. Also, I did use names for the integers so I can understand the code better, and I also explained my though method of said integers.

'setVI' is the integer I use for reading an arbitrary pin (I changed it 100's of times to see if the problem was what pin I was using.) All that is important to know is that setVI is only the direct read input of some pin from a button I call setVI. it is called such because it allows the LCD to display what voltage and what current I want to change. I use the UP and DOWN integers to read other pins connected to the corresponding UP and DOWN buttons, so I call them, and they actually increment the the set voltage or current UP or DOWN.

RS is the button I use to actually change the 'mode' of this power supply project: by tapping the corresponding button, the LCD should either read the output voltage of the finished power supply, or allow me to set the voltage and current. As for the 'set' mode, I can flip between setting the current, of voltage output, and I can change which one the UP and DOWN arrows (and what is displayed on the screen) with the 'setVI' button.

I have used variables like "READorSET" to change in correspondence to, in this case, 'RS'. When RS goes from LOW to HIGH, (or the other way around, depending on how the code is changed up) the READorSET variable will be inverted. this is then used in the 'if' statements referring to what to write to the LCD, and the tapping the button ultimately controls the LCD and output voltage (the output has not been implemented yet, I am still working on the user interface.) I hope this clears the confusion up!

Let's simplify things even more.

Compile this code

void setup() 
{
  Serial.begin(9600);
  pinMode(7, INPUT_PULLUP);
}

void loop() 
{
  Serial.println(digitalRead(7));
}

Remove all external connections to the Arduino except for a wire plugged into pin 7. Run the program. What do you see on the monitor ? Touch the other end of the wire plugged into pin 7 onto the metal shield of the USB port. What do you see on the monitor ?

michinyon:

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.

I don't know how hard it was, but this learning is very dubious.

Yeah, I attempted this on a smaller scale while back when I first bought the Arduino, I knew nothing about it, and it was my first entry into digital technologies. before that I used 555's transistors, and op amps. I wanted to have a play around with microelectronics, and figured out why the control loop did not work at all! I simply made an if-else statement Arduino code that controlled a transistor that charged a capacitor, and the voltage on that capacitor was sent back into the analog pin so the voltage on the capacitor can be maintained. It did not work because that Arduino was not fast enough to make small, fine adjustments to the voltage output. Oh well.

wildbill:

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

This does indeed occur in some circumstances - there is only one ADC shared between the analog pins. The most common solution is simply to read each pin twice and discard the first reading. I've never heard of anything similar on the digital pins though. Your issue smells like floating inputs to me, as AWOL suggested.

The issue is a bit more deep-rooted though, there is a definite pattern noticed, and the way it is wired in fine, I checked millions of times.

pressing the RS button and holding it down for approx. 27-32 Arduino loops will cause the setVI to magically go HIGH, even though it is grounded. the time it to cause setVI to go high after pressing and holding RS seems to be dependent on how long neither one has been pressed.

I can also get it to go HIGH by pressing and holding the setVI button, and then taping the RS button. the second I let go of RS, only pressing the setVI, setVI only goes LOW again. doing it this way, the setVI output responds immediately.

If I press the RS button down and almost immediately tap the setVI button, I can get it to 'latch' on HIGH for as long as I continue to hold the RS button down.

I checked millions of times.

Hyperbole?

I checked millions of times.

Let us check once.
Show us an image.

It did not work because that Arduino was not fast enough to make small, fine adjustments to the voltage output.

I suspect it did not work because you did not understand the nature of the analogue output and the filtering required to get a smooth output. In fact the filter design for such a loop is almost impossible. It has nothing to do with the digital nature of the loop controller.

UKHeliBob:
Let's simplify things even more.

Compile this code

void setup() 

{
  Serial.begin(9600);
  pinMode(7, INPUT_PULLUP);
}

void loop()
{
  Serial.println(digitalRead(7));
}



Remove all external connections to the Arduino except for a wire plugged into pin 7. Run the program. What do you see on the monitor ? Touch the other end of the wire plugged into pin 7 onto the metal shield of the USB port. What do you see on the monitor ?

With your code, the Arduino now just spits out 1's, and nothing else. I tried this on pin 6 for a reference, same thing. I assume this is normal since the pin is being pulled up internally. this was the same on both pin 7 and 6. I changed the pinmode to INPUT, and it responded to the input properly. I notice this code gets rid of all integers, so I would guess this means it eliminated the possibility that there are errors associated with writing the data to a memory of some sort.

I then reverted back to my code, the same, but I define my one variable as well, and I still get the strange issue. Now, however, the problem seems to be a severely delayed response. Pin 7 must stay high for about 3/4ths of a second, or about 30 Arduino cycles before the serial registers a '1.' Before when I test this EXACT same code, the output was even dependent on other pins, at one point, even the analog pins! So I have no clue, but the exact properties of this problem seem to be changing and shifting around, and I have to re-elaborate on the problem every time because it changes ever so slightly.

AWOL:

That is why I posted this in the hardware issue of this forum

Actually, you didn't; you posted in the "Installation and troubleshooting" section, so I moved it here.

I do have a proper pull-down resistor connected to a switch, which is on the high end of the 5V rail.

Pull-down to 5volts. OK.

I meant troubleshooting, which is what I am currently doing. other than formatting like other have mentioned, I do not have an issue with the programming aspect. Also, just to clarify,when the buttons are not pressed, the output is LOW, because the resistors are on the LOW side of the circuit.

AWOL:

I checked millions of times.

Hyperbole?

Nope. I seriously checked it 100,193,527 times, now 100,193,528 ;).

Powermax:
I then reverted back to my code, the same, but I define my one variable as well, and I still get the strange issue. Now, however, the problem seems to be a severely delayed response.

Show us your code - AND the wiring diagram

Pin 7 must stay high for about 3/4ths of a second, or about 30 Arduino cycles before the serial registers a '1.'

What exactly do you mean? What is an "Arduino cycle"?

...R