This arduino code does not work as expected, any help? there seems to be an issue with the digitalWrite function.

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.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 (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.
}

sort by: active | newest | oldest
Libahunt3 years ago

If you leave only reading inputs and printing them to serial and remove the rest of the code, does it still behave strange?

Then put back the two if statements after digitalreads and the two presetVI and preRS lines at the end of the loop. Then what happens?

Possibly it is not good idea to check "when the button is initially pressed" which you are trying to do. You most probably need debounce instead (

http://arduino.cc/en/Tutorial/Debounce#.Uwf5F0nWT-... Delay in a loop is not sufficient replacement for button debouncing, in my experience.

-max- (author)  Libahunt3 years ago

Yes, it still acts strange if everything except the digitalRead and serial functions are nulled. In fact, I went ahead, opened a new IDE, and cut the code down to just this. It simply reads the pins and writes it to the serial. Could you test this and see if there is anything wrong?

[code]

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int RS = 0;
int setVI = 0;

void setup() {
Serial.begin(9600);
Serial.print("INPUTS RS: setVI:");
Serial.println("");
}
void loop() {
RS = digitalRead(6);
setVI = digitalRead(7);
Serial.print("\t ");
Serial.print(RS);
Serial.print("\t ");
Serial.println(setVI);
}
[/code]
-max- (author)  -max-3 years ago

On closer observation with just the stripped down code, 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. Any ideas?

Libahunt -max-3 years ago

It is starting to look very much like hardware problem. I did a real life test with your code (the one that was stripped down to reading pins 6 and 7). When I have two buttons with pulldown resistors connected, it works as expected. But when I removed the connecting wire from pin 7 then reading of 7 started to follow reading of 6. The pin with nothing connected to it is picking up noise, in this case the state of the nearby pin.
In your description there is a more complicated pattern of how and when pin 7 follows reading of pin 6. I suppose this can be due to some bad connection that could act as voltage divider or some stray capacitance.

Next you should try to find out if the problem is on the side of your external hardware (buttons, pulldowns, breadboard) or on the arduino board or inside microcontroller. I can think of two tests.

You can move the buttons to other pins or swap between 6 and 7 - if the problem persists, there is something wrong with external components. (Which I understand you already did with similar results? The button-pulldown setup could be the source of the problem.)

In case the first test still leaves the culprit to arduino then you can also try to measure voltage on the pin of the chip while the button is pressed and while it is not. I understand you have fubarino mega. Here is a mega controller pinout

http://www.pighixxx.com/pgdev/Temp/ATMEGA2560U.png... but carry in mind that if pin 7 happens to be loose from the board then pushing multimeter probe against it probably makes connection better for that moment. So keep an eye on the serial monitor also. Or you can measure resistance between a wire connected to header and controller pin. Loose leg or loose header are probably only things that can be fixed, otherwise stop using the faulty pin in any project.

* fubarino - I meant funduino.

-max- (author)  Libahunt3 years ago

I came to the conclusion that this might be an error in either the IDE uploading the code, or something wrong with wherever the compiled sketch is loaded. I found some code to completely wipe the EEPROM memory and then unplugged it and let it sit for awhile, hopefully to allow time to for maybe the RAM to also clear. This did not seem to help, but the rolls of pin 7 and 6 seemed to have flipped, although I did not test that extensively. So more test will be needed. Is it possible to completely dump its memory? I did try another pin and it did not have the problem, but I don't reckon it is that pin, because the issue will come back with the full code, and I have had a very similar issue several times in the past with the analog pins.

Libahunt -max-3 years ago

I don't have any knowledge about how could these things go wrong. Have you posted you problem description to AVRfreaks forum yet

http://www.avrfreaks.net/index.php?name=PNphpBB2&f... ?

There should be people around who are more educated in the specifics of microcontroller internals.

-max- (author)  Libahunt3 years ago

No, but I have posted this question on the official Arduino forum.

-max- (author)  Libahunt3 years ago

OK, I even removed the RS button entirely, so I do not define it, read it, anything. However, it STILL has the exact same problems!!! I have no idea what could be wrong other than a major error in either the compiling or the uploading! [banging my head against the wall & tearing my hair out]

here is the most stripped down code possible!

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

-max- (author) 3 years ago

Intrestingly, the problem went away without a trace, and I dont know why :-/

Libahunt -max-3 years ago

In the meanwhile I exercised by brains on the debouncing topic and wrote a tiny helper library that allows to read many buttons with as short and simple code as possible. If you find any trouble from button bouncing, check that out

http://www.libahunt.ee/debouncedbuttons

iceng -max-3 years ago

That points to a physical hardware like ;

  1. A solder ball
  2. A trace dendrite short
  3. Surface contamination
  4. Frayed wire
  5. Lone wire strand not going through mounting hole.

.

A


-max- (author)  iceng3 years ago
Oddly though, I was not able to recreate the error by purposely wiring it incorrectly. After that issue was fixed, the serial to USB converter stoped working, I couldn't upload sketches, being who I am, I shorted the pins on the RX and TX to the corresponding LEDs, then I tried just pressing on the chip itself. oddly, that worked. I guess the pressure caused a poor connection internally to work again.
iceng -max-3 years ago

Gremlins at work.

.

When I had a CPM Kaypro the disc drives ( no hard drives those days ) occasionally wouldn't work and removing the case and rapping an IC let me get disc data.

One day the screen was flaking and the disc was stubborn too. Rapping the drive IC wasn't responding, so I really knuckled it and the chip jump out of the socket.

I must have lost my presence of mind there and struck the PCB repeatedly with a hammer.

Next day I got another computer and nailed the offending PCB to a wood post.

iceng3 years ago

In past similar events, where my inputs were misacting.

I have found placing extra dummy commands in between read commands to force the compiled MachineCode to re-read the word and mask test the bits which is what is being mixed up.

Or switch order and save data to memory before retest branching

it just slows execution but you do have the time if it works.

A

-max- (author)  iceng3 years ago

Unfortunately, the 1st solution did not solve the problem. I added some unnecessary digitalRead and digitalWrite functions between the affect pieces of code, and nothing changed. Could you elaborate what you mean by "Or switch order and save data to memory before retest branching?"

iceng -max-3 years ago

Do not use a read write as a dummy load use a constant or delay(2).

you want to step away from r/w area of the CPU.

2. When you bit test branch the CPU reads a whole word and masks those bits of your interest in fact if the bits are across two registers inPa and inPb,

the CPU has to read two 8bit words mask appropriate bits and branch on results.

I suggested you read one bit line and place it in a named sequential variable or array like Butn0, Butn1, Butn2, Butn3 and then do your branch decisions on Butnx.

A

-max- (author)  iceng3 years ago

I also tried delay functions; they did not work either.

what evidence have you that the buttons are working in any circuit ? make a test program verify them

-max- (author)  steveastrouk3 years ago

I have tested all the arduino inputs and outputs extensively with much simpler programs, and used the serial.print function to try to determine the issue. When I first wrote the code, it worked fine, but the names of some of the variables were not very self-explanatory, so I changed them. However, doing so has caused everything to go haywire, and I narrowed it down to the digitalReading of setVI, and it does not matter which pin, or what the integer is named, the issue with it persists.

-max- (author) 3 years ago
It is a Funduino, it was purchased off eBay quite awhile back, so I doubt it there is any technical support.