My first program. A bit of a whopper for a first... Need some pointers...

Hello there, where do I begin?

I had an idea long ago to customise my motorbike a little bit and do an electronics project at the same time. I'm not afraid of electronics, but programming is completely new to me. My motorbike had only a speedo, and I thought that I would love to have RPM, oil temperature, oil pressure, air temperature, and a stopwatch + clock! Oh my kingdom for a clock!

It was then that I stumbled upon the Arduino and I was most interested. So I bought one :D.

I have now got the Arduino + 16x2 LCD sort of doing what I want them to do (although minus the stopwatch so far). Only problem is, I'm not a programmer, and I cobbled the program together only out of what I learnt from tutorials on the net (so a bit of praise, at least? Pleeeze?).

The sensors are all simulated for now by a pot, and I have them mapped pretty much how I want them to be.

My problems are as follows:

  1. The code is EXTREMELY clumsy. Of this I am sure. Can anyone give me some pointers for tidying it up?
  2. The stopwatch is missing from the time and date display. I want it shown to the right of the time, with a start/stop button and a reset button. Any hints? I'm going a bit "loop"y if you know what I mean.
  3. The button for changing the page is a bit temperamental. I suspect it's down to timing and my crap coding :blush:. You need to give it a quick tap to get to the clock page, but to get back to engine stats page you have to hold it down for longer than a second.

Here is a video of it in action so you know what I'm going on about:

Here is my, er, code... :blush:. And yes, there are no remarks in the code. Bad form :blush:. Sorry!

Thanks in advance.

int inPin = 7;   // pushbutton connected to digital pin 7
int val = 0;     // variable to store the read value

#include <DateTime.h>
#include <DateTimeStrings.h>

#define dt_SHORT_DAY_STRINGS
#define dt_SHORT_MONTH_STRINGS
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup()
{ 
  DateTime.sync(DateTime.makeTime(0, 3, 11, 6, 9, 2011)); // sec, min, hour, date, month, year // Replace this with the most current time
  pinMode (inPin, INPUT);
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("A");
  delay(100);
  lcd.setCursor(1, 0);
  lcd.print("r");
  delay(100);
  lcd.setCursor(2, 0);
  lcd.print("m");
  delay(100);
  lcd.setCursor(3, 0);
  lcd.print("s");
  delay(100);
  lcd.setCursor(4, 0);
  lcd.print("t");
  delay(100);
  lcd.setCursor(5, 0);
  lcd.print("r");
  delay(100);
  lcd.setCursor(6, 0);
  lcd.print("o");
  delay(100);
  lcd.setCursor(7, 0);
  lcd.print("n");
  delay(100);
  lcd.setCursor(8, 0);
  lcd.print("g");
  delay(100);
  lcd.setCursor(11, 0);
  lcd.print("M");
  delay(100);
  lcd.setCursor(12, 0);
  lcd.print("T");
  delay(100);
  lcd.setCursor(13, 0);
  lcd.print("5");
  delay(100);
  lcd.setCursor(14, 0);
  lcd.print("0");
  delay(100);
  lcd.setCursor(15, 0);
  lcd.print("0");
  delay(100);
  lcd.setCursor(2, 1);
  lcd.print("version 0.03");
  delay(3000);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  delay(50);
  lcd.scrollDisplayRight();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
  lcd.scrollDisplayLeft();
}

void loop()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("RPM:     Air:  C");
  lcd.setCursor(0, 1);
  lcd.print("Oil:   C     bar");
  do {
  val = digitalRead(inPin);
  int oilTempReading = analogRead(A0);
  int oilTemp = map(oilTempReading, 0, 1023, 0, 150);
  lcd.setCursor(4, 1);
  lcd.print(oilTemp);
  int rpmReading = analogRead(A1);
  int rpm = map(rpmReading, 0, 1023, 0, 8500);
  lcd.setCursor(4, 0);
  lcd.print(rpm);
  int airReading = analogRead(A2);
  int air = map(airReading, 0, 1023, 0, 60);
  lcd.setCursor(13, 0);
  lcd.print(air);
  int oilPressReading = analogRead(A3);
  int oilPress = map(oilPressReading, 0, 1023, 0, 5);
  lcd.setCursor(11, 1);
  lcd.print(oilPress);
  delay(160);
  lcd.setCursor(4, 1);
  lcd.print("   ");
  lcd.setCursor(4, 0);
  lcd.print("    ");
  lcd.setCursor(13, 0);
  lcd.print("  ");
  lcd.setCursor(11, 1);
  lcd.print(" ");
  }
  while (val == LOW);
  do {
  val = digitalRead(inPin);
  if(DateTime.available()) {
unsigned long prevtime = DateTime.now();
while( prevtime == DateTime.now() ) // wait for the second to rollover
;

DateTime.available(); //refresh the Date and time properties
digitalClockDisplay( ); // update digital clock
}
  }
  while (val == LOW);
}

void printDigits(byte digits){
// utility function for digital clock display: prints preceding colon and leading 0
lcd.print(":");
if(digits < 10)
lcd.print('0');
lcd.print(digits,DEC);
}



void digitalClockDisplay(){
lcd.clear();
lcd.begin(16,2);
lcd.setCursor(0,1);

//lcd.print(DateTimeStrings.dayStr(DateTime.DayofWeek));
if(DateTime.Day <10)
lcd.print('0');
lcd.print(DateTime.Day,DEC);
lcd.print("/");

//lcd.print(DateTimeStrings.monthStr(DateTime.Month));
if(DateTime.Month <10)
lcd.print('0');
lcd.print(DateTime.Month,DEC);
lcd.print("/");
lcd.print((DateTime.Year,DEC)+2000);

//lcd.print(" ");
if(DateTime.Hour <10)
lcd.setCursor(1,0);
lcd.setCursor(0,0);

// digital clock display of current time
lcd.setCursor(0,0);
lcd.print(DateTime.Hour,DEC);
printDigits(DateTime.Minute);
printDigits(DateTime.Second);
}

just one note, unless you leave the arduino powered 24/7 or have another clock source you will need to set the time everytime you start the arduino up. Even keeping the arduino powered up all the time the clock will drift a little. If you want it to be accurate and be able to power off the arduino you might want to look into something like a chronodot http://macetech.com/store/index.php?main_page=product_info&cPath=5&products_id=8&zenid=256fd53f62a06665b1adb7ff989ecda6.

for your display you may want to restructure how it changes screens. something like:

void loop(){
  val = digitalRead(inPin);
  if(val == HIGH){
    // if the button was pushed toggle the screen
    currentScreen == 0 ? currentScreen = 1 : currentScreen = 0;
  }

  if(currentScreen == 0){
    //code to display the sensors
  }

  if(currentScreen == 1){
    //code to display the time
  }
}

you may also want to look into debouncing the button if it doesn't behave how you expect http://www.arduino.cc/en/Tutorial/Debounce

Thanks for the tips iggykoopa :slight_smile:

I probably won't bother with the chronodot, although i have bookmarked it. The clock doesn't have to be super accurate. Fair point about the keeping it awake though. I was hoping I could get the arduino to sleep or go to a low power state? would it keep the time? If not, then that chronodot is looking tempting...

And thanks a lot for the code too, that's really helped me out XD

Colin

Couple recommendations:

  1. Utilize your own functions to make code more readable.
  2. Utilize looping control structures to eliminate repetitive code.

If you compress all those repetitive lines of code the program would only be about 10 lines long :slight_smile:

For example

for (int i = 0; i < 20; i++) 
  lcd.scrollDisplayRight();
  delay(50);
}

is better than

  lcd.scrollDisplayRight();
  delay(50);

20 times.

The printing of "Armstrong..." could also be compressed to about 3 lines.


Rob

The IDE has a handy tool called auto-format (ctrl-T) - it indents your code for you, making it easier for you (and us) to read.

Thank you all very much for your time and your helping hands.

jraskell: I need to learn more about looping, bear with me - I'm getting there! Defining my own functions? I'm going to have to look that one up...

Graynomad: Thanks for that snippet - you've taught me something. How would I get printing 'Armstrong' into 3 lines of code? :astonished: Is it something to do with strings, and printing the string one character at a time?

AWOL: Wow, I didn't know that. I do now! That makes things a lot easier...

Back to the code... I'll repost soon if anyone's interested :sleeping:

namtip:
jraskell: I need to learn more about looping, bear with me - I'm getting there! Defining my own functions? I'm going to have to look that one up...

Hey, we were all where you are at one point. As long as you take the initiative, it's all good.

namtip:
How would I get printing 'Armstrong' into 3 lines of code? :astonished: Is it something to do with strings, and printing the string one character at a time?

Yup, but I'd personally use a char array myself. I'm not a fan of Arduino's String class at all. I never recommend using it. In fact, I expressly recommend not using it.

char name = "Armstrong  MT500";
byte i = 0;
while(name[i] != NULL)
{
  lcd.setCursor(i, 0);
  lcd.print(name[i]);
  delay(100);
  i++;
}

jraskell:
I'd personally use a char array myself. I'm not a fan of Arduino's String class at all. I never recommend using it. In fact, I expressly recommend not using it.

char name = "Armstrong  MT500";

byte i = 0;
while(name[i] != NULL)
{
  lcd.setCursor(i, 0);
  lcd.print(name[i]);
  delay(100);
  i++;
}

Strong views! Why is that may I ask?

Also, when I inserted your code, I get an error: "invalid conversion from 'const char*' to 'char'

Thanks,

Colin

Strong views! Why is that may I ask?

The String class uses malloc() under the covers to handle memory allocation for strings. If you don't know what you're doing, you can easily right code with the String class that quickly fragments memory to the point of failure, and a failure that can be hard to diagnose.

In order to understand how to use the String class to avoid these issues, you have to understand how malloc() and C style char strings work, and once you understand that, there's little reason to utilize the String class anymore. That's just my opinion anyways. And I don't think it's a bias. I use C++ strings on computer platforms all the time, and in fact heavily utilize the entire STL when writing code on computer platforms.

I get an error: "invalid conversion from 'const char*' to 'char'

First line of code should be: char name[] = "Armstrong MT500";

My bad. I actually did compile and test it using the Serial class, and had to fix that one error, but forgot to transfer the fix to my post.

Thanks! Works perfectly now :slight_smile:

Youtube is full of useful tutorials, especially for the problem you are getting with the bounce on the switch....

:astonished: