arduino clock control code

19 views
Skip to first unread message

genzaichi

unread,
Jul 16, 2009, 5:29:00 PM7/16/09
to Birmingham Hack Space
I thought I'd have another look at the clock code I started with at
the hack session last night (http://www.cibomahto.com/2008/03/
controlling-a-clock-with-an-arduino/)

I've got it wired up to a LED rather than the clock and the LED is
indeed flashing at what looks like second intervals
... but only 15 times and then it stops!

If I change startTime += 1000; to 2000 then it'll flash 7 times
If I change startTime += 1000; to 500 then it'll flash 31 times

What's going on? Smells like a software thing to me, rather than
hardware, but what bit of the code's limiting it to 15 seconds of
activity?

nikki


// Clock Tick Demonstration
//
// By Matt Mets, completed in 2008
//
// This code is released into the public domain. Attribution is
appreciated.
//
// This is a demonstration on how to control a cheapo clock mechanism
with an Arduino.
// The clock mechanism works by using an electromagnet to pull a
little fixed magnet,
// similar to how a DC motor works. To control this with the Arduino,
we need to hook a
// wire up to each side of the electromagnet (disconnect the exisiting
clock circuity if
// possible). Then, hook each of the wires to pins on the Arduino. I
chose pins 2 and 3
// for my circuit. It is also a good idea to put a resistor (I chose
500 ohms) in series
// (between one of the wires and an Arduino pin), which will limit the
amount of current
// that is applied. Once the wires are hooked up, you take turns
turning on one or the
// other pin momentarily. Each time you do this, the clock 'ticks'
and moves forward one
// second. I have provided a doTick() routine to do this
automatically, so it just needs
// to be called each time you want the clock to tick.
//


////// Board
Setup /////////////////////////////////////////////////////////////////////////
extern unsigned long timer0_overflow_count;

int clockA = 2; // Set these to the pin numbers you have
attached the clock wires
int clockB = 3; // to. Order is not important.

int tickPin = clockA; // This keeps track of which clock pin should
be fired next.


// Initialize the IO ports
void setup()
{
pinMode(clockA, OUTPUT);
pinMode(clockB, OUTPUT);

digitalWrite(clockA, LOW);
digitalWrite(clockB, LOW);

Serial.begin(9600);
}


// Move the second hand forward one position (one second on the clock
face).
void doTick() {

// Energize the electromagnet in the correct direction.
digitalWrite(tickPin, HIGH);
delay(10);
digitalWrite(tickPin, LOW);

// Switch the direction so it will fire in the opposite way next
time.
if (tickPin == clockA)
{
tickPin = clockB;
} else {
tickPin = clockA;
}
}


// Main loop
void loop()
{
unsigned long startTime = millis();
unsigned long temp;

// Pretend to be a regular clock, and tick once a second.
while (true)
{
startTime += 500;

// Wait until a second has passed. Note that this will do ugly
things when millis()
// runs over, so we only have about 9 hours before this version
will stop working.
while (startTime - millis() > 0) {}

doTick();
}
}

Trevor White

unread,
Jul 16, 2009, 6:17:52 PM7/16/09
to birmingham...@googlegroups.com
Okay, the led only flashes every other second? As the motor is toggled?

Thus the counter is reaching approx. 30000. int is 16 bits and 65k value
max. But a signed int is + or - 32k. With you system, the int gets to
32000 and the rolls over. You will need to set it to a

unsigned long startTime

That should sort it. There are better ways to do it but that will get
things working for now.

Trev

G Bulmer

unread,
Jul 16, 2009, 9:35:54 PM7/16/09
to Birmingham Hack Space
On Jul 16, 11:17 pm, Trevor White <trevor.white...@googlemail.com>
wrote:
> Okay, the led only flashes every other second? As the motor is toggled?
>
> Thus the counter is reaching approx. 30000. int is 16 bits and 65k value
> max. But a signed int is + or - 32k. With you system, the int gets to
> 32000 and the rolls over. You will need to set it to a
>
> unsigned long startTime
>
> ...
>

I'm not sure that is the explanation.
The code in Nikki's email defines startTime as:
> // Main loop
> void loop()
> {
> unsigned long startTime = millis();

I think there is another problem:
> while (startTime - millis() > 0) {}

millis() is defined as:
unsigned long millis()

So a question is, what happens when two unsigned numbers are
subtracted?
Well, for A-B when
A > B: +result
A == B: 0
A < B: +result!!

So the only way out of that loop is when millis() equals startTime.

Try this code:
void setup() // run once, when the sketch starts
{
Serial.begin(9600);
}

void loop() // run over and over again
{
unsigned long a = 1000;

unsigned long b = 999;
unsigned long c = 1000;
unsigned long d = 1001;

Serial.print("a: "); Serial.println(a);
Serial.print("b: "); Serial.println(b);
Serial.print("c: "); Serial.println(c);
Serial.print("d: "); Serial.println(d);

Serial.print("a-b: "); Serial.println(a-b);
Serial.print("a-c: "); Serial.println(a-c);
Serial.print("a-d: "); Serial.println(a-d);

while (a-d>0) {}
}

What do you think it will print?
Answer:
a: 1000
b: 999
c: 1000
d: 1001
a-b: 1
a-c: 0
a-d: 4294967295

It is then stuck forever.

So, if you are unlucky, and millis() fails to equal startTime, but
instead gets bigger, it will stick for roughly 4,294,967,295 milli
seconds.
As I think has been explained on the internet, the way the uderlying
arduino timer works, it actually increments in a unit of time
sliughtly lnger than one milli-second, and this is corrected by adding
a leap milli-second, which would jump milis() from N to N+2, and lock
into the loop.

A better loop would be:
// Main loop
void loop()
{
while (true)
{
delay(500);
doTick();
}
}

That way it works ("a good thing" TM:), and it is the Arduino library
developers to deal with the wrap around of delay() !-)

BTW, unless I have missed something, the wrap around of millis()
happens at the transition from 4,294,967,295 to 4,294,967,296 milli-
seconds (which won't fit in 32 bits, and so wraps around to 0).

According to my calculator, there are 86,400 seconds in a day, or
86,400,000 milli-seconds in a day, so the wrap around happens after
49.71 days.

HTH
GB-)

G Bulmer

unread,
Jul 16, 2009, 10:13:17 PM7/16/09
to Birmingham Hack Space
On Jul 17, 2:35 am, G Bulmer <gbul...@gmail.com> wrote:
> ...
> That way it works ("a good thing" TM:), and it is the Arduino library
> developers to deal with the wrap around of delay() !-)

PS - I should add, currently (Arduino-0016) the delay() function
doesn't fully correct for that wrap around, but the library developers
are smart folks, and might get around to it.
To be fair to them, if I have understood it, it is quite sneaky - it
could return from delay() and not get stuck (at least in some cases)
when the clock wraps, which is very well done.

Assuming the calculation (number of mili-seconds before wrap) is
correct, and the wrap around only happens after 49.7 days, it probably
isn't a high priority for them.

GB-)

Trevor White

unread,
Jul 17, 2009, 3:29:39 AM7/17/09
to birmingham...@googlegroups.com
Ooops, my mistake. Sorry. Well done G.

nikki

unread,
Jul 17, 2009, 6:07:14 PM7/17/09
to Birmingham Hack Space
I've just got the clock ticking from the arduino!
On a delay of 200ms it's truly the stuff of nightmares...

Thanks for your help, G and T

n

Trevor White

unread,
Jul 17, 2009, 6:19:25 PM7/17/09
to birmingham...@googlegroups.com
Cool. So have you got it moving in both directions? I like the idea of
the clock ticking backwords. We could make a special face plate that is
mirrored so the time appears correct when moving in an anit-clockwise
direction.

Trev

G Bulmer

unread,
Jul 17, 2009, 6:39:33 PM7/17/09
to Birmingham Hack Space
On Jul 17, 11:07 pm, nikki <genzai...@googlemail.com> wrote:
> I've just got the clock ticking from the arduino!
> On a delay of 200ms it's truly the stuff of nightmares...
Could you post a picture or two?

Where did you get the mechanism? I might like to try.

It'd amuse me (but be a bit cruel) to put one in the room I use with
the school children, and have it vary widely. The first 15 minutes (on
the clock) might pass in 5 minutes (real), and the last 5 minutes (on
the clock) might last 15 minutes (real)
But I'm not very mature :-)

>
> Thanks for your help, G and T
You're welcome. Glad to be of help.

GB-)

(... After a moment, another minute passed. I waited a minute while a
minute passed quickly past. And then, a minute which seemed to last an
hour but was only a minute... passed ...)

nikki

unread,
Jul 18, 2009, 4:40:39 AM7/18/09
to Birmingham Hack Space
Initial proddings so far make me suspect things are set up so it only
works in the forwards direction, but I've not yet looked at it in
detail and I need to mark up the gears so I can properly see what's
happening.

I did get a bit of backwards when I set the interval really short, but
that might just have been the gears jumping around because I don't
have the back of the case on at the moment.

<bigspender> Then mechanism is one from a packet of two alarm clocks I
bought from poundland</bigspender>
I've got a few pricier mechanisms from years back that I was going to
mount inside of some ceramic sculptures once, I might investigate
those soon...

I'll probably get some video sorted out, but my upload allowance on
vimeo doesn't reset for a day or two and I've already maxed out on it
this week. Used the last of it on this rag'n'bone man :) http://www.vimeo.com/5623400

G Bulmer

unread,
Jul 18, 2009, 5:21:42 AM7/18/09
to Birmingham Hack Space
On Jul 18, 9:40 am, nikki <genzai...@googlemail.com> wrote:
> Initial proddings so far make me suspect things are set up so it only
> works in the forwards direction, but I've not yet looked at it in
> detail and I need to mark up the gears so I can properly see what's
> happening.
Forward is okay!
I was thinking of just moving the hands at different rates, which is
unexpected.

Something like this (not tested, and no guarantees to run in an hour
[in fact, I don't think it will] :-)

#define Minutes0_15 (900)
#define Minutes15_45 (Minutes0_15+1800)
#define Minutes45_60 (Minutes15_45+900)

// Main loop
void loop()
{
while (true)
{
int t;
// each time round the loop is one second
for (t=0; t<Minutes0_15; ++t) { // move clock faster
delay(1000/3);
doTick();
delay(1000/3);
doTick();
delay(1000/3+1000%3);
doTick();
}
// each time round the loop is one second
for (t=Minutes0_15+1; t<Minutes15_45; ++t) { // move at normal
speed
delay(1000/2);
doTick();
delay(1000/2);
doTick();
}
// each time round the loop is one second
for (t=Minutes15_45+1; t<Minutes45_60; ++t) { // move clock
slowler
delay(1000);
doTick();
}
}
}

>
> ...
>
> <bigspender> Then mechanism is one from a packet of two alarm clocks I
> bought from poundland</bigspender>

Brilliant! I'll have a look.

> I've got a few pricier mechanisms from years back that I was going to
> mount inside of some ceramic sculptures once, I might investigate
> those soon...
>
> I'll probably get some video sorted out, but my upload allowance on
> vimeo doesn't reset for a day or two and I've already maxed out on it
> this week. Used the last of it on this rag'n'bone man :)http://www.vimeo.com/5623400
>

No problem, time is all about waiting :-)

GB-)

G Bulmer

unread,
Jul 18, 2009, 9:10:55 AM7/18/09
to Birmingham Hack Space
I've simplified the code for the case where someone wants to start
with a regular clock.
I removed the doTick function, and the while(true), so I hope this is
a bit easier to understand.
This only contains ideas that are in the introductory blink example.

// ---- snip snip -----------------
/* Clock01 - inspired by
* Nikki's Arduino clock at
http://groups.google.com/group/birmingham-hack-space/browse_thread/thread/3d7a5e6a3bad6055/a9481d1f74f6ca18?hl=en#a9481d1f74f6ca18
*
* Garry Bulmer 2009
*/

int clockA = 2; // Set these to the pin numbers you have
attached to the clock wires
int clockB = 3; // Order is not important.

void setup()
{
pinMode(clockA, OUTPUT);
pinMode(clockB, OUTPUT);
digitalWrite(clockA, LOW);
digitalWrite(clockB, LOW);
}



// Main loop lasts approximately 1 second
void loop()
{
digitalWrite(clockA, HIGH);
delay(10);
digitalWrite(clockA, LOW);

delay(490);

digitalWrite(clockB, HIGH);
delay(10);
digitalWrite(clockB, LOW);

delay(490);
}

// --- snip snip -----------
This is NOT exactly accurate, because the Arduino delay isn't, but
it's a simple starting point for anyone wanting to experiment.

GB-)

nikki

unread,
Jul 18, 2009, 10:19:33 AM7/18/09
to Birmingham Hack Space

I've sorted out a few strategic holes in the casing and the back panel
is back on now keeping everything in place. (Down side though is that
the ticking's not so loud - I was starting to like it!)

I've also been fiddling around with the timings (see below for the
code I'm using) and for a small range of short durations I can make
the clock go backwards (@Trevor). Nice!

I think I'd perhaps like to make this into some sort of generative
sound-making device. Next steps: a) find out how much weight the hands
can tolerate and b) figure out the electrical contacts.



////// Board
Setup /////////////////////////////////////////////////////////////////////////
extern unsigned long timer0_overflow_count;

int clockA = 2; // Set these to the pin numbers you have
attached the clock wires
int clockB = 3; // to. Order is not important.

int tickPin = clockA; // This keeps track of which clock pin should
be fired next.


int interval = 50; // interval between start of each doTick
int duration = 17; // length of doTick pulse
//9 - 15 for reverse direction, nice random
movements just below 9

// Initialize the IO ports
void setup()
{
pinMode(clockA, OUTPUT);
pinMode(clockB, OUTPUT);

digitalWrite(clockA, LOW);
digitalWrite(clockB, LOW);

Serial.begin(9600);
}


// Move the second hand forward one position (one second on the clock
face).
void doTick() {

// Energize the electromagnet in the correct direction.
digitalWrite(tickPin, HIGH);
delay(duration);
digitalWrite(tickPin, LOW);

// Switch the direction so it will fire in the opposite way next
time.
if (tickPin == clockA)
{
tickPin = clockB;
} else {
tickPin = clockA;
}
}


// Main loop
void loop()
{
while (true)
{
delay(interval-duration);
doTick();
}
}
Reply all
Reply to author
Forward
0 new messages