/*
* Simple RTC Analog Watch
*
* Demonstrates the use of the Arduino Time library and Arduino Zero Real-Time-Clock (RTC) library to make a simple digital
* and simulated analog clock. The digits are displayed to the left, the round analog clock face to the right.
*
* Uses Arduino Time library http://playground.arduino.cc/code/time
* Maintained by Paul Stoffregen https://github.com/PaulStoffregen/Time
*
* Uses Arduino Zero RTC library https://www.arduino.cc/en/Reference/RTC
* Maintained by Arturo Guadalupi https://github.com/arduino-libraries/RTCZero
*
* This code is for the TinyScreen+ board by TinyCircuits used by O Watch http://tiny-circuits.com
*
* This example is based on the Simple Watch code created by O Watch on 6 March 2016 http://theowatch.com
* Modified to use RTC, to set the display brightness based on time of day, and to use __DATE__ and __TIME__
* to preset the watch's date and time by J Koger 13 March 2016
* Modified to also display a round analog clock by J Koger 14 March 2016
*
*/
#include <TinyScreen.h> //include TinyScreen library
#include <TimeLib.h> //include the Arduino Time library
#include <RTCZero.h> //include the Arduino Zero's Real Time Clock library
#include <stdio.h> // include the C++ standard IO library
/* Create an rtc object */
RTCZero rtc;
// We'll dynamically change these values to set the current initial time
// No need to change them here.
byte seconds = 0;
byte minutes = 45;
byte hours = 9;
// We'll dynamically change these values to set the current initial date
// The preset values are only examples.
byte days = 13;
byte months = 3;
byte years = 16;
int brightness = 15; // We'll set it, 3 - 15 based on time of day
TinyScreen display = TinyScreen(TinyScreenPlus); //Create the TinyScreen object
void setup()
{
char s_month[5];
int tmonth, tday, tyear, thour, tminute, tsecond;
static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
display.begin(); //Initializes TinyScreen board
display.setFlip(1); //Flips the TinyScreen rightside up for O Watch
display.on(); //Turns TinyScreen display on
display.fontColor(TS_8b_White,TS_8b_Black); //Set the font color, font background
rtc.begin(); // initialize RTC
// Set the time and date. Change this to your current date and time.
// setTime(16,19,00,12,3,2016); //values in the order hr,min,sec,day,month,year
// Let's be lazy and let the compiler set the current date and time for us.
// This will be a few seconds off due to the time it takes to compile the
// .ino file and upload the app. But pretty close.
// __DATE__ is a C++ preprocessor string with the current date in it.
// It will look something like 'Mar 13 2016'.
// So we need to pull those values out and convert the month string to a number.
sscanf(__DATE__, "%s %d %d", s_month, &tday, &tyear);
// Similarly, __TIME__ will look something like '09:34:17' so get those numbers.
sscanf(__TIME__, "%d:%d:%d", &thour, &tminute, &tsecond);
// Find the position of this month's string inside month_names, do a little
// pointer subtraction arithmetic to get the offset, and divide the
// result by 3 since the month names are 3 chars long.
tmonth = (strstr(month_names, s_month) - month_names) / 3;
months = tmonth + 1; // The RTC library expects months to be 1 - 12.
days = tday;
years = tyear - 2000; // The RTC library expects years to be from 2000.
hours = thour;
minutes = tminute;
seconds = tsecond;
rtc.setTime(hours, minutes, seconds);
rtc.setDate(days, months, years);
}
// Draw a circle. Slow but works. Taken from the O-Watch TinyScreen tutorial.
// http://www.theowatch.com/learn/o-watch-tinyscreen-programming/learn-tinyscreen-demo/
//
void drawCircle(int x0, int y0, int radius, uint8_t color)
{
int x = radius;
int y = 0;
int radiusError = 1-x;
while(x >= y)
{
//drawPixel(x,y,color);//set pixel (x,y) to specified color. This is slow because we need to send commands setting the x and y, then send the pixel data.
display.drawPixel(x + x0, y + y0, color);
display.drawPixel(y + x0, x + y0, color);
display.drawPixel(-x + x0, y + y0, color);
display.drawPixel(-y + x0, x + y0, color);
display.drawPixel(-x + x0, -y + y0, color);
display.drawPixel(-y + x0, -x + y0, color);
display.drawPixel(x + x0, -y + y0, color);
display.drawPixel(y + x0, -x + y0, color);
y++;
if (radiusError<0)
{
radiusError += 2 * y + 1;
}
else
{
x--;
radiusError += 2 * (y - x) + 1;
}
}
}
// Draw a line from a given start point at a given angle for a given length.
//
// Don't use any floating point math such as the sine() function because it
// takes a long time to run and eats battery life on a computer without
// a floating point processor, like the Arduino Zero in the O-Watch.
// Instead, use a good old-fashioned hard-coded sine lookup table and
// a couple of integer math tricks.
//
// The underlying idea from a geometry standpoint is that we need to figure
// out the equivalent X,Y endpoint of a line that goes from the center of the
// circle (0,0) out to a length of radius 1.0 (the 'unit circle') at a given
// angle and multiply the length of our hand by that X,Y endpoint, then slide
// both the center of the circle and the enpoint over so that they match our actual.
// circle's coordinates.
// The sine and cosine of the unit circle are the X,Y endpoint that we need.
//
// Modified from: https://codebender.cc/example/glcd/clockFace#AnalogClock.cpp
void drawHand(int xStart, int yStart, int angle, int radius, unsigned char color)
// xStart, yStart are starting point of hand (center of clock face)
// angle is location of hand on dial (0-60)
// radius is length of hand
{
// Sines for hand positions from 0 to 15 minutes. All of the other
// hand position sines can be determined by flipping x and y. These
// are all multiplied by 256 so that we can use integers to store them.
// Cosines can be also be determined by taking the sine of the angle minus
// 15 degrees and flipping x and y.
static int sine[16] = {0, 27, 54, 79, 104, 128, 150, 171, 190, 201, 221, 233, 243, 250, 254, 255};
int xEnd, yEnd, quadrant, x_flip, y_flip;
// calculate which quadrant the hand lies in
quadrant = angle/15 ;
// We could have a bigger table of sine values that handle every hand position from 0 to 60,
// but we can avoid using that memory by doing some quick reflections and rotations.
switch ( quadrant )
{
case 0 : x_flip = 1 ; y_flip = -1 ; break ;
case 1 : angle = abs(angle-30) ; x_flip = y_flip = 1 ; break ;
case 2 : angle = angle-30 ; x_flip = -1 ; y_flip = 1 ; break ;
case 3 : angle = abs(angle-60) ; x_flip = y_flip = -1 ; break ;
default: x_flip = y_flip = 1; // this should not happen
}
xEnd = xStart;
yEnd = yStart;
// OK, here's the tricky part. Look up the sine for the hand
// angle, then multiply it by the hand length. Then, because
// our sine table values are all pre-multiplied by 256 so we
// can store them as integers, we need to divide by 256 to
// correct for that. Which is, in integer math, the same as
// saying that we'll shift the values right by 8 bit positions.
// Doing a shift-right is faster than doing an integer divide by 256
// (the compiler is probably smart enough to turn that
// divide by 256 into a right shift anyway, but let's do
// an explicit shift because it's cool).
//
// The equivalent floating-point call would look something like:
// xEnd = sine(angle) * radius;
xEnd += (x_flip * (( sine[angle] * radius ) >> 8));
yEnd += (y_flip * (( sine[15-angle] * radius ) >> 8));
display.drawLine(xStart, yStart, xEnd, yEnd, color);
}
void displayTime()
{
display.on(); //Turns TinyScreen display on
// Draw the circle for the analog clock. According to the TinyScreen
// tutorial http://www.theowatch.com/learn/o-watch-tinyscreen-programming/
// the TinyScreen is 96 pixels wide by 64 high, with (0,0) in the
// upper-left corner, and (95,63) in the lower right.
// This is the only part of the time display that doesn't need to be redrawn
// as long as the hands stay inside the circle.
//
// We want a nice big clock face, so the circle should be 64 pixels tall,
// and thus 64 pixels wide, with a radius of 32 pixels. Well, that ends up drawing
// the edges of the circle slightly off the screen, so we'll make the circle
// a little smaller, let's say 60 pixels in diameter, or 30 radius. To give a little
// room for text to the left, we'll put the circle all the way to the right
// of the TinyScreen, so put its center at 95 - 30 = 65. The center needs
// to be halfway down the screen, or 63 / 2 = 32.
//
// Since this is a sporty watch, we'll give it a red circle.
//
// Let's figure out the hands while we're at it. The minute hand should
// just fit within the circle, maybe a little shorter than that, so let's
// give it a length (radius) of 28 pixels. The hour hand should be much
// shorter than the minute hand, so how about 18 pixels. The second hand
// can be the same size as the minute hand, but a different color, how
// about a nice sporty yellow.
enum
{
clockCenterX = 65,
clockCenterY = 32,
clockCircleRadius = 30,
clockCircleColor = TS_8b_Red,
clockMinuteHandLength = 28,
clockMinuteHandColor = TS_8b_White,
clockHourHandLength = 18,
clockHourHandColor = TS_8b_White,
clockSecondHandLength = 28,
clockSecondHandColor = TS_8b_Yellow
};
drawCircle(clockCenterX, clockCenterY, clockCircleRadius, clockCircleColor);
for (int i = 1; i < 15; i++) // Display for 15*1000 milliseconds (15 seconds), update display each second
{
// To correctly handle switching date at midnight while the time display is on,
// update -everything-, not just the seconds.
display.setFont(liberationSansNarrow_12ptFontInfo); //Set the font type
// Get the complete date and time now since they're used for the weekday
// and brightness calculations.
months = rtc.getMonth();
days = rtc.getDay();
years = rtc.getYear();
hours = rtc.getHours();
minutes = rtc.getMinutes();
seconds = rtc.getSeconds();
// First draw the clock hands, to minimize them flickering.
// The hour is 0 - 23. But we need it
// to be an 'angle' of 0 - 59. So
// convert 24-hour time to 12 hour time,
// and then multiply by 60 / 12 = 5.
int hourAngle;
if (hours >= 12)
hourAngle = hours - 12;
else
hourAngle = hours;
hourAngle *= 5;
// To give the hour hand a real
// analog-clock feel, it shouldn't point
// straight at the hour, but should move between
// the hours as the minute hand sweeps around.
// So, let's nudge it forward a smidge by
// the minutes scaled down to the space within 1 hour, or
// divide them by 12.
hourAngle += minutes / 12;
drawHand(clockCenterX, clockCenterY, hourAngle, clockHourHandLength, clockHourHandColor);
drawHand(clockCenterX, clockCenterY, minutes, clockMinuteHandLength, clockMinuteHandColor);
drawHand(clockCenterX, clockCenterY, seconds, clockSecondHandLength, clockSecondHandColor);
if (hours <= 12)
brightness = hours + 3; // 0 hours = 3 brightness, noon = 15
else if (hours >= 18)
brightness = (24 - hours) * 2 + 2; // 23 hours = 4 brightness, 18 hours = 14
else
brightness = 15; // full brightness all afternoon
if (brightness < 3)
brightness = 3;
if (brightness > 15)
brightness = 15;
display.setBrightness(brightness); //Set display brightness 0 - 15
// Print date in US format MM:DD:YY (Switch the order in which day, month, year that you like to use)
display.setCursor(0,8); //Set the cursor where you want to start printing the date
if(months < 10) display.print(0); //print a leading 0 if hour value is less than 0
display.print(months);
display.print("/");
days = rtc.getDay();
if (days < 10) display.print(0);
display.print(days);
// display.print("/");
// display.print(years);
display.setCursor(0,25); //Set the cursor where you want to start printing the date
setTime(hours,minutes,seconds,days,months,2000 + years); //values in the order hr,min,sec,day,month,year
char wkday[16];
strcpy(wkday, dayStr(weekday()));
wkday[3] = ' '; wkday[4] = '\0';
display.print(wkday); // To keep the text compact, only print the first 3 letters.
display.setFont(liberationSansNarrow_12ptFontInfo); //Set the font type
// display time in HH:MM:SS 24 hour format
display.setCursor(0,45); //Set the cursor where you want to start printing the time
if(hours < 10) display.print(0); //print a leading 0 if hour value is less than 0
display.print(hours);
display.print(":");
if(minutes < 10) display.print(0); //print a leading 0 if minute value is less than 0
display.print(minutes);
// display.print(":");
// if(seconds < 10) display.print(0); //print a leading 0 if seconds value is less than 0
// display.print(seconds);
// display.print(" "); //just a empty space after the seconds
delay(1000); //display for 1 seconds
// Now erase the clock hands by drawing them in black.
drawHand(clockCenterX, clockCenterY, hourAngle, clockHourHandLength, TS_8b_Black);
drawHand(clockCenterX, clockCenterY, minutes, clockMinuteHandLength, TS_8b_Black);
drawHand(clockCenterX, clockCenterY, seconds, clockSecondHandLength, TS_8b_Black);
}
display.off(); //Turns TinyScreen display off
}
void loop()
{
if (display.getButtons())
{
displayTime();
}
}
Comments