Saturday, 3 June 2017

Time... still waiting

Developing the theme a bit from the last post, I decided that rather than just showing the elapsed time from when the sketch started, maybe I should try and show the real time instead.

That raised an issue - how to actually initialise the time at the start of the sketch.  Two methods sprang to mind - firstly to just simply type the time in to the Serial Monitor to set it going (yes - as well as being very handy to write output data on, the monitor also has an input function), and the second was to have a couple of buttons connected along with the display, and use them to shift numbers up and down until the time is right.  However - that presupposes I actually have the display to use - which I don't... yet.  Yes, it's been over 6 weeks now - thankfully, the seller has agreed to send a replacement.  Once the display eventually arrives, I may revisit this topic and give you more detail on that solution (once I have given it some more thought...)

OK - so back to the Serial Monitor input method. I read numerous forum posts and explanations, but I must confess - while the concept seems simple enough, I still don't really understand the details of reading data from the monitor into a sketch.  It all looks quite confusing when trying to understand it sufficiently to be able to write my own code from scratch.  Luckily, I don't need to re-invent this particular wheel...

I was able to find an example of almost exactly what I want to do.  It is from this 'Instructable' article, detailing how to use the Serial Monitor to set the time and date for an Arduino project using a Real Time Clock (RTC) module called a DS1307.  The article is uncredited, so I can't thank the author or credit them here either - but my thanks go out to him or her.

Firstly, what I was aiming to do was to use the Time.h library, which has lots of time and date functionality built into it, and allows simple access to every element of the time and date for display purposes, as well as date and time calculations, etc.  The first Time method I want to use is setTime, which has the following format
setTime(hour,minute,second,year,month,monthday);
For my purposes, the date portion is irrelevant, and can be set to any date at all.  I am only interested in hours, minutes and seconds.  This reduced the amount of Serial Monitor input processing (and also the time taken to actually initialise my clock) considerably.

Here is the code that I hacked from the Instructable article, that sends prompts to the Serial Monitor, and accepts input back again.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// initialise Serial Comms
  Serial.begin(9600);

// Get initial Time and date from Serial Monitor (set to NewLine line endings)
  //Serial.print("Please enter the current year, 00-99. - ");
  //byte year = readByte();
  //Serial.println(year);
  //Serial.print("Please enter the current month, 1-12. - ");
  //byte month = readByte();
  //Serial.println(month);
  //Serial.print("Please enter the current day of the month, 1-31. - ");
  //byte monthday = readByte();
  //Serial.println(monthday);
  //Serial.println("Please enter the current day of the week, 1-7.");
  //Serial.print("1 Sun | 2 Mon | 3 Tues | 4 Weds | 5 Thu | 6 Fri | 7 Sat - ");
  //byte weekday = readByte();
  //Serial.println(weekday);
  Serial.print("Please enter the current hour in 24hr format, 0-23. - ");
  byte hour = readByte();
  Serial.println(hour);
  Serial.print("Please enter the current minute, 0-59. - ");
  byte minute = readByte();
  Serial.println(minute);
  byte second = 0;
  Serial.println("The data has been entered.");

As you can see, I have commented out all the stuff related to the input of the date, and just left the hours and minutes, and defaulted seconds to 0.  The key bits of code here are lines 19, 22, and 24.  Each of these lines assigns a value to the relevant variable.  Note that the variables are all byte data types... The byte data type is exactly what you might expect - a single byte of data - made up of 8 bits, each of which can hold either a zero or a one.  That gives a byte a total of 256 possible different combinations of ones and zeros, so a byte can store an integer (whole number) with a value of 0 to 255.  An ideal choice for hours, minutes and seconds with a maximum value of 24, 60, and 60 respectively.

Now the other part of lines 19 and 22, is a call to a function called readByte().  THIS is where the Arduino is listening out on the serial line, waiting for characters to arrive from the Serial Monitor.  And THIS is where my understanding faltered, took a few steps backwards, looked again from a safer distance, and then turned and walked away with its head hung low in shame.  I haven't a clue how this code actually functions at the moment - all I know is that it works.  I am sure that I will keep revisiting it and chipping away until I do understand - but for now, I am treating it like the code that is stored in the various libraries (or my car engine).  I don't need to know exactly how it works, just as long as it does...

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
byte readByte() {
  while (!Serial.available()) delay(10);
  byte reading = 0;
  byte incomingByte = Serial.read();
  while (incomingByte != '\n') {
    if (incomingByte >= '0' && incomingByte <= '9')
      reading = reading * 10 + (incomingByte - '0');
    else;
    incomingByte = Serial.read();
  }
  Serial.flush();
  return reading;
}

The last part of the puzzle is to use the data input from the monitor, to set the time.  So - we need to make sure we have the Time.h library included at the beginning of the sketch...  The Master Library I found on github actually generates two include statements when you build it into a sketch.  I don't know why, but for know my sketches are small enough that I don't need to worry about excessive memory usage, so will leave them both there...
#include <Time.h>
#include <TimeLib.h>
...and then of course is the setTime command
setTime(hour,minute,second,2017,6,3);
You can see I've used the time parameters, but hard-coded today's date as it is simply not required for my quickie LM35 test sketch.

By the way, actually using the input ability of the Serial Monitor utilises the single line panel at the bottom of the monitor.  Note there is the option to describe how you will signal the end of each data item - in this instance, I used the 'newline ending' option suggested in the Instructable article.

Now that the functionality in the Time library has a starting point and can 'keep' time, we can access the time at any point, and it will be stored in a special 'customised' data type, called time_t.  This data type contains all the elements of the date and time in a way that can be accessed by a number of other functions in the library.  For example...

time_t t = now();
stores the the time NOW in a variable of the time_t data type, called t.

Serial.print(hour(t));
will print the hour component of the current time.

So that's the basics of using the Serial Monitor to initialise values for use in a sketch - it doesn't have to be time and date values, it could be setting a seed value to use for random number generation, or... well anything - the sky's the limit!


No comments:

Post a Comment