Hi all,
My first post on the forum
I have been using the arduino (duemilanove) for a while now. Great piece of kit. I recently programmed some gps code that is displayed on a lcd screen. I use a button (5V --> switch --> resistor to gnd and other wire to input pin) to switch between the various screens. However, if I press the switch, I want to change the screen immediately and not like it is now, after a few seconds of holding the switch. I quit sure it has something to do with the fact that is caught in the loop and that I have to hold the button till the loop passes by. I probably need to think outside the box on this one but I have trouble finding 'the edge of the box'.
Here's the code:
// Include libraries
#include <SoftwareSerial.h>
#include <TinyGPS.h>
#include <LiquidCrystal.h>
#define rxPIN 1 //Serial info arrives here
#define txPIN 2 //Not used
const int buttonPin = 11; //Button input pin
int screen = 0; //Start screens of with No 0; the startup screen
int buttonState = 0; //record button state
int lastButtonState = 0; //record last button state
double lat = 0; //Get lat and lon as a double (instead of float)
double lon = 0;
long lastDebounceTime = 0; //debounce timer for switch
long debounceDelay = 50; //the delay to reduce noise
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
TinyGPS gps;
static bool feedgps();
static void gpsdump(TinyGPS &gps);
SoftwareSerial ss(0, 1);
void setup(){
lcd.begin(16,2); //LCD is 16 char by 2 lines
ss.begin(4800); //Make connection to GPS serial
Serial.begin(9600); //Should it be necessary to debug anything we start the serial
}
void loop(){
screenChange();
bool newdata = false;
unsigned long start = millis();
// Every second we print an update
while (millis() - start < 1000){
if (feedgps())
newdata = true;
}
gpsdump(gps);
}
//Define the gpsdump function
static void gpsdump(TinyGPS &gps){
float flat, flon;
int year;
byte month, day, hour, minute, second, hundredths;
unsigned long fix_age;
gps.f_get_position(&flat, &flon, &fix_age); //Get out lat, lon and the age
gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths);
//If the fix is invalid, we want to print the initializing (startup) screen
if (fix_age == TinyGPS::GPS_INVALID_AGE){
printStartUp();
}
//If the fix gets to old, we want to know by showing the lost sats screen
else if (fix_age > 5000){
lostSats();
}
//If the fix is valid and young enough, AND no other screen option has been chosen yet, say that option are available
else if (fix_age != TinyGPS::GPS_INVALID_AGE && fix_age < 5000 && screen != 1 && screen != 2 && screen != 3 && screen != 4){
chooseOption();
}
//If we push the button and the value is now 1, show coords
else if (screen == 1){
printCoordinates(flat, flon);
}
//If we push the button and the value is now 2, show speed
else if (screen == 2){
printSpeed();
}
//If we push the button and the value is now 3, show date and time
else if (screen == 3){
printDateTime(year, month, day, hour, minute, second);
}
//If we push the button and the value is now 4, show the 'number of satellite' screen
else if (screen == 4){
printSat();
}
}
//Define the option screen
void chooseOption(){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Data available,");
lcd.setCursor(0, 1);
lcd.print("push button");
}
//Define the coords screen (screen 1)
void printCoordinates(float flat, float flon){
//Value are printen in a N/S and E/W format, rather than a +ve or -ve value
double slat; //declare new doubles in case lat or lon are negative
double wlon;
lat = flat; //Assign value to the doubles
lon = flon;
lcd.clear();
lcd.setCursor(0, 0);
if (lat > 0){ //print of the lat if is a +ve value
lcd.print("Lat: ");
if (lat < 10){ //Usualy, the N/S format comes in xx.xxxx
lcd.print("0"); //We want a single 0 upfront when N/S is only a single digit
}
lcd.print(lat, 5);
lcd.setCursor(15, 0);
lcd.print("N"); //+ve are N(orth)
}
else{ //multipli by -1 for South value
slat = (lat * -1);
lcd.print("Lat: ");
if (slat < 10){
lcd.print("0");
}
lcd.print(slat, 5);
lcd.setCursor(15, 0);
lcd.print("S"); //initial -ve are S(outh)
}
lcd.setCursor(0, 1);
if (lon > 0){ //print of if it is a +ve value
lcd.print("Lon: ");
if (lon < 10){ //Usualy, the E/W format comes in xxx.xxxxx
lcd.print("00"); //We want double 0 upfront if E/W is only a single digit
}
else if (lon < 100){
lcd.print("0"); //We want a single 0 upfront if E/W is two digits
}
lcd.print(lon, 5);
lcd.setCursor(15, 1);
lcd.print("E"); //+ve are E(ast)
}
else{ // multipli by -1 for a West value
wlon = (lon * -1);
lcd.print("Lon: ");
if (wlon < 10){
lcd.print("00");
}
else if (wlon < 100){
lcd.print("0");
}
lcd.print(wlon, 5);
lcd.setCursor(15, 1);
lcd.print("W"); //initial -ve are W(est)
}
feedgps();
}
//Define the speed screen (screen 2)
void printSpeed(){
double currentSpd = gps.f_speed_kmph();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Speed: ");
lcd.print(currentSpd, 1);
lcd.print("km/h");
feedgps();
}
//Define the date and time screen (screen 3)
void printDateTime(int year, byte byteMonth, byte byteDay, byte byteHour, byte byteMinute, byte byteSecond){
int timeDiff = 2;
int month = (int) byteMonth;
int day = (int) byteDay;
int hour = (int) byteHour;
int minute = (int) byteMinute;
int second = (int) byteSecond;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Date: ");
if (day < 10){
lcd.print("0");
}
lcd.print(day);
lcd.print("/");
if (month < 10){
lcd.print("0");
}
lcd.print(month);
lcd.print("/");
lcd.print(year);
lcd.setCursor(0, 1);
int localHour = hour + timeDiff;
if (localHour < 0){
localHour = localHour + 24;
}
lcd.print("Time: ");
if (localHour < 10){
lcd.print("0");
}
lcd.print(localHour);
lcd.print(":");
if (minute < 10){
lcd.print("0");
}
lcd.print(minute);
feedgps();
}
//Define the 'number of satellite' screen (screen 4)
void printSat(){
int sat = gps.satellites();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Satellites: ");
lcd.print(sat);
}
//Define the 'feedgps' function
static bool feedgps(){
while (ss.available()){
if (gps.encode(ss.read()))
return true;
}
return false;
}
//Define the screen number
void screenChange(){
int reading = digitalRead(buttonPin); //Read button state
if (reading != lastButtonState){ //Check whether it has changed due to noise or switching
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay){ //Check whether it is noise or a switch
if (reading != buttonState){
buttonState = reading;
if (buttonState == HIGH){
if (screen < 4) //Check if 'screen' is below 4 since 4 is highest
screen++; //Yes, add 1 to the 'screen'
else {
screen = 1; //Otherwise return '1' as '0' is the setup screen
}
}
}
}
lastButtonState = reading;
}
//Define the startup screen
void printStartUp(){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Initializing,");
lcd.setCursor(0, 1);
lcd.print("please wait.....");
}
//Define the lost Sats screen
void lostSats(){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Satellites lost,");
lcd.setCursor(0, 1);
lcd.print("please wait.....");
}
It might not be the best code in the world but at least it works
I suspect I have to use either a 'while' function to read a buttonpress and process this immediately or the loop must be setup entirely different.
The loop starts of with calling for the void screenChange which processes button inputs and the gets the GPS data and processes it. As I said, all this probably is the cause of the whole delay as it takes a while to process all of the functions called forward...
Hope someone can shine some light on this...