SOLVED! Use a button to change LCD characters

See Post 8 For New Details
I am making a program that enhances the Servo Knob example and reports the degree reading to the LCD. I somehow cannot move the cursor to the second line of my LCD (Electronic Components and Parts Search | DigiKey Electronics). I am new to arduino so help would be greatly appreciated. I can get the setcursor LCD example to work but not mine. Please Help.

My code:

#include <SoftwareServo.h>

#include <LiquidCrystal.h>

int potpin = 5;
int servopin = 9;
int val;
int val2;
int row = 1;
int col = 0;
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
SoftwareServo myservo;

void setup()
{
lcd.begin(2,16);
myservo.attach(9);
pinMode(potpin,OUTPUT};
void loop()
{
lcd.home();
val = analogRead(potpin);
val= map (val, 0, 1023, 0, 179);
myservo.write(val);
lcd.print("Servo Position");
lcd.setCursor(1,0);
lcd.write(val);
lcd.setCursor(1,3);
lcd.print("Degrees");
SoftwareServo::refresh();
}

It's column,row. :wink:

Thank you very much. Now how can I get val to output as a number on the LCD. Thanks!

How about:

lcd.print(val);

Ok. Now that works but after 30 seconds or so the LCD turns to all black bricks on the top screen and my whole program in unresponsive.
My updated code:

#include <SoftwareServo.h>

#include <LiquidCrystal.h>

int potpin = 5;
int servopin = 9;
int val;
int val2;
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
SoftwareServo myservo;

void setup()
{
lcd.begin(2,16);
myservo.attach(9);
pinMode(potpin,OUTPUT);
}
void loop()
{
lcd.clear();
val = analogRead(potpin);
val= map (val, 0, 1023, 0, 179);
myservo.write(val);
lcd.print("Servo Position");
lcd.setCursor(0,1);
lcd.print(val);
lcd.setCursor(3,1);
lcd.print("Degrees");
SoftwareServo::refresh();
}

#include <SoftwareServo.h>

#include <LiquidCrystal.h>

How are you powering that LCD and servo? If you're running them off the Arduino's +5V, there's a very good chance you're overtaxing the supply, and causing the system to glitch or reset itself.

Ran

That's a good suggestion. The only thing else I can see is that in the example they have a 15 ms delay after the write, which you don't have.

The way the LCD is behaving does sound like a power glitch though.

I fixed the issue by making the degree area of the display change. I am powering everything off of the arduino but this code seems to work.

#include <SoftwareServo.h>

#include <LiquidCrystal.h>

int potpin = 5;
int servopin = 9;
int button = 8;
int val;
int val2;
int bval;
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
SoftwareServo myservo;

void setup()
{
lcd.begin(2,16);
myservo.attach(9);
pinMode(button,INPUT);
lcd.print("Servo Position");
lcd.setCursor(4,1);
lcd.print("Degrees");
}
void loop()
{
lcd.home();
bval = digitalRead(button)
val = analogRead(potpin);
val= map (val, 0, 1023, 0, 179);
myservo.write(val);
delay(10);
if (val < 100)
{
lcd.setCursor(0,1);
lcd.print(" ");
}
lcd.setCursor(0,1);
lcd.print(val);
SoftwareServo::refresh();
}

Thanks!
But now, I want to make it so if I press a button, the sketch will jump to a different void loop() area (named button) and repeat until the button is pressed again. Is this possible? Thank You!

If (bval == high) //button pressed
{
Goto void  button() //how would I do this part
}

void button()
{
val = analog.Read(potentiometer)
lcd.setCursor(0,1) //Second row of LCD
lcd.write(val)
digital.Read(button)
if (button == HIGH)
{
myservo.Write(val)
delay(500)
goto void loop() //how do I do this?

That's pretty spooky. I had written a post last night that suggested that you handle the LCD updating almost exactly like you did but deleted it at the last minute as it seemed ill advised to change too many things at once.

You could consider using the "degrees" symbol:

lcd.setCursor(0,1);
lcd.print("    "); // 4 spaces
lcd.print(val);
lcd.print(223,BYTE); // degrees symbol

One way to handle the other issue is to declare a variable that keeps track of the state of the button. Every time you press the button, you invert the state of the variable, for example, TRUE => FALSE => TRUE =>... then use "if" to select the function to call based on the state of that variable.

Thank you! I appear to have a small power issue. If I turn the potentiometer to erratically for a while, it uses more power and goes to the black bricks. I will just work around it for now. So I updated my sketch with the button part but the arduino just runs through the whole sketch and seemingly ignores the IF statements because it is displaying "Servo Position" and "Jump to Position" on top of eachother on the top row. How do I make it work how I want it to? For the button I am using a pull-down circuit.
My new code:

#include <SoftwareSerial.h>

#include <SoftwareServo.h>

#include <LiquidCrystal.h>

int potpin = 5;
int servopin = 9;
int button = 7;
int val;
int val2;
int bval;
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
SoftwareServo myservo;

void setup()
{
lcd.begin(2,16);
myservo.attach(9);
pinMode(button,INPUT);
lcd.print("Servo Position");
Serial.begin(9600);
}
void loop()
{
bval = digitalRead(button);
Serial.println(bval);
if (bval == HIGH);
{
lcd.clear();
lcd.print("Jump To Position");
lcd.setCursor(0,1);
val = analogRead(potpin);
val= map (val, 0, 1023, 0, 179);
if (val < 100)
{
lcd.print(" ");
lcd.setCursor(0,1);
}
lcd.write(val);
lcd.setCursor(0,4);
lcd.print(223,BYTE);
bval = digitalRead(button);
delay(20);
if (bval == HIGH);
{
lcd.home();
lcd.print("Servo Position");
myservo.write(val);
}

}
bval = digitalRead(button);
if (bval == LOW);
{
lcd.home();
val = analogRead(potpin);
val= map (val, 0, 1023, 0, 179);
myservo.write(val);
delay(10);
if (val < 100)
{
lcd.setCursor(0,1);
lcd.print(" ");
}
lcd.setCursor(0,1);
lcd.print(val);
lcd.print(223,BYTE); // degrees symbol
delay(20);
SoftwareServo::refresh();
}
}

Describe exactly what you mean by "pull-down circuit". How is the switch wired and how is the resistor wired.

Just like this except the button is connected to pin 7.


(from ladyada.net arduino tutorial)

Okay, so when you press the button, you get HIGH else you get LOW. Typical manic-depressive cycle. :slight_smile:

I suggest you write a new sketch just to play around with the button presses. Until we get you up to interrupt routines, you are going to press and hold the button until something happens on your LCD then release it until something else happens. This is because without doing something more complex in the code, there is no way for the state of the switch to be stored until the program loops around to look at it.

Pseudocode for your program would be like this:

int switchState = false; // this variable will always contain the current state of your button
// instantiate LCD

void setup()
{
//Initialize Digital pin as Input
//Initialize LCD
// etc
}

void loop()
{
// digitalRead button
// if button is HIGH switchState = true else switchState = false
// if (switchState == true) write "Switch Pressed" to LCD else write "Switch Released"
}

When you get that to work, write functions to do the "Switch Pressed" and Switch Released" tasks and call them from the appropriate places in loop(). By the time all that works you will be ready to use interrupts to capture your button presses no mater what your program is doing at the time.

Thank you very much. With a little bit of work I finished my code. Here it is ;D

#include <SoftwareSerial.h>

#include <SoftwareServo.h>

#include <LiquidCrystal.h>

int potpin = 5;
int servopin = 9;
int button = 7;
int val;
int val2;
int txtval;
int buttonState = false;
int bval;
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
SoftwareServo myservo;

void setup()
{
lcd.begin(2,16);
myservo.attach(9);
pinMode(button,INPUT);
lcd.print("Servo Position");
Serial.begin(9600);
}
void loop()
{
bval = digitalRead(button);
Serial.println(bval);
if (bval == HIGH)
{
buttonState = true;
}
else
{
buttonState = false;
}

if (buttonState == true)
{
lcd.clear();
lcd.print("Jump To Position");
txtval = 1;
lcd.setCursor(0,1);
val = analogRead(potpin);
val= map (val, 0, 1023, 0, 179);
if (val < 100)
{
lcd.print(" ");
lcd.setCursor(0,1);
}
lcd.print(val);
lcd.print(223,BYTE);
bval = digitalRead(button);
delay(20);
SoftwareServo::refresh();

}
else
{
if (txtval = 1)
{
lcd.home();
lcd.print("Servo Position");
txtval = 0;
}
myservo.write(val);
val = analogRead(potpin);
val= map (val, 0, 1023, 0, 179);
myservo.write(val);
delay(10);
if (val < 100)
{
lcd.setCursor(0,1);
lcd.print(" ");
}
lcd.setCursor(0,1);
lcd.print(val);
lcd.print(223,BYTE); // degrees symbol
delay(20);
SoftwareServo::refresh();
}
}

Thank you very much!

Very good! You can test if your button state has changed at the top of your loop and just loop until you get a new value if you want instead of toggling "textval" to keep from rewriting the same information if you like.

What you have is great! I think the LadyAda tutorial you are reading will eventually address interrupt on pin change which will simplify things a bit. You'll end up putting things in functions too to make the code easier to follow.

Have fun!