/elec/propeller-clock

To get this branch, use:
bzr branch http://bzr.ed.am/elec/propeller-clock

« back to all changes in this revision

Viewing changes to src/propeller-clock.ino

  • Committer: edam
  • Date: 2012-02-23 00:26:32 UTC
  • Revision ID: edam@waxworlds.org-20120223002632-kkwrdwijfmv45f0j
conrtol segment number from one place and reverse the order the segments are drawn (backwards clock!)

Show diffs side-by-side

added added

removed removed

 
1
/* -*- mode: c++; compile-command: "BOARD=pro5v make"; -*- */
1
2
/*
2
 
 * propeller-clock.pde
 
3
 * propeller-clock.ino
3
4
 *
4
 
 * Copyright (C) 2011 Tim Marston <edam@waxworlds.org>
 
5
 * Copyright (C) 2011 Tim Marston <tim@ed.am> and Dan Marston.
5
6
 *
6
7
 * This file is part of propeller-clock (hereafter referred to as "this
7
 
 * program"). See http://ed.am/software/arduino/propeller-clock for more
 
8
 * program"). See http://ed.am/dev/software/arduino/propeller-clock for more
8
9
 * information.
9
10
 *
10
11
 * This program is free software: you can redistribute it and/or modify
23
24
 
24
25
/******************************************************************************
25
26
 
26
 
  For a schematic, see propeller-clock.sch.
27
 
 
28
 
  Set up as follows:
29
 
 
30
 
  - a PC fan is wired up to the 12V supply.
31
 
 
32
 
  - the fan's SENSE (tachiometer) pin is connected to pin 2 on the
33
 
    arduino.
34
 
 
35
 
  - the pins 4 to 13 on the arduino should directly drive an LED (the
36
 
    LED on pin 4 is in the centre of the clock face and the LED on pin
37
 
    13 is at the outside.
38
 
 
39
 
  - if a longer hand (and a larger clock face) is desired, pin 4 can
40
 
    be used to indirectly drive (via a MOSFET) multiple LEDs which
41
 
    turn on and off in unison in the centre of the clock.
42
 
 
43
 
  - a button should be attached to pin 3 that grounds it when pressed.
44
 
 
45
 
  Implementation details:
46
 
 
47
 
  - the timing of the drawing of the clock face is recalculated with
48
 
    every rotation of the propeller (for maximum update speed).
49
 
 
50
 
  - pressing the button cycles between display modes
51
 
 
52
 
  - holding down the button for 2 seconds enters "set time" mode. In
53
 
    this mode, the fan must be held still and the LEDs will indicate
54
 
    what number is being entered for each time digit. Pressing the
55
 
    button increments the current digit. Holding it down moves to the
56
 
    next digit (or leaves "set time" mode when there are no more). In
57
 
    order, the digits (with accepted values) are: hours-tens (0 to 2),
58
 
    hours-ones (0 to 9), minutes-tens (0 to 5), minutes-ones (0 to 9).
 
27
Set up:
 
28
 
 
29
 * a PC fan is wired up to a 12V power supply
 
30
 
 
31
 * the fan's SENSE (tachiometer) pin connected to pin 2 on the
 
32
   arduino.
 
33
 
 
34
 * the pins 4 to 13 on the arduino should directly drive an LED (the
 
35
   LED on pin 4 is in the centre of the clock face and the LED on pin
 
36
   13 is at the outside.
 
37
 
 
38
 * if a longer hand (and a larger clock face) is desired, pin 4 can be
 
39
   used to indirectly drive a transistor which in turn drives several
 
40
   LEDs that turn on anf off in unison in the centre of the clock.
 
41
 
 
42
 * a button should be attached to pin 3 that grounds it when pressed.
 
43
 
 
44
 * A DS1307 remote clock is connected via I2C on analog pins 4 and 5.
 
45
 
 
46
Implementation details:
 
47
 
 
48
 * for a schematic, see ../project/propeller-clock.sch.
 
49
 
 
50
 * the timing of the drawing of the clock face is recalculated with
 
51
   every rotation of the propeller.
 
52
    
 
53
 * a PC fan actually sends 2 tachiometer pulses per revolution, so the
 
54
   software skips every other one. This means that the clock may
 
55
   appear upside-down if started with the propeller in the wrong
 
56
   position. You will need to experiment to dicsover the position that
 
57
   the propeller must be in when starting the clock.
 
58
    
 
59
Usage instructions:
 
60
 
 
61
 * pressing the button cycles between variations of the current
 
62
   display mode.
 
63
  
 
64
 * pressing and holding the button for a second cycles between display
 
65
   modes (e.g., analogue and digital).
 
66
 
 
67
 * pressing and holding the button for 5 seconds enters "time set"
 
68
   mode. In this mode, the following applies:
 
69
    - the field that is being set flashes
 
70
    - pressing the button increments the field currently being set
 
71
    - pressing and holding the button for a second cycles through the
 
72
      fields that can be set
 
73
    - pressing and holding the button for 5 seconds sets the time and
 
74
      exits "time set" mode
59
75
 
60
76
******************************************************************************/
61
77
 
62
78
 
63
79
#include <Bounce.h>
 
80
#include <DS1307.h>
 
81
#include <Wire.h>
64
82
 
65
83
//_____________________________________________________________________________
66
84
//                                                                         data
85
103
static bool inc_draw_mode = false;
86
104
 
87
105
// a bounce-managed button
88
 
static Bounce button( 3, 5 );
 
106
static Bounce button( 3, 50 );
89
107
 
90
108
// the time
91
109
static int time_hours = 0;
97
115
#define NUM_SECOND_SEGMENTS 5
98
116
#define NUM_SEGMENTS ( 60 * NUM_SECOND_SEGMENTS )
99
117
 
 
118
// clock direction
 
119
#define CLOCK_FORWARD 0
 
120
 
100
121
//_____________________________________________________________________________
101
122
//                                                                         code
102
123
 
143
164
}
144
165
 
145
166
 
 
167
// turn an led on/off
 
168
void ledOn( int num, bool on )
 
169
{
 
170
        if( num < 0 || num > 9 ) return;
 
171
 
 
172
        // convert to pin no.
 
173
        num += 4;
 
174
 
 
175
        // pin 4 needs to be inverted (it's driving a PNP)
 
176
        // NOTE: PIN 4 TEMPORARILY DISABLED
 
177
//      if( num == 4 ) on = true;
 
178
if( num == 4 ) on = !on;
 
179
 
 
180
        digitalWrite( num, on? HIGH : LOW );
 
181
}
 
182
 
 
183
 
146
184
// draw a segment for the test display
147
 
void drawNextSegment_test( bool reset )
 
185
void drawNextSegment_test( int segment )
148
186
{
149
 
        // keep track of segment
150
 
        static unsigned int segment = 0;
151
 
        if( reset ) segment = 0;
152
 
        segment++;
153
 
 
154
187
        // turn on inside and outside LEDs
155
 
        digitalWrite( 4, HIGH );
156
 
        digitalWrite( 13, HIGH );
 
188
        ledOn( 9, true );
157
189
 
158
190
        // display segment number in binary across in the inside LEDs,
159
191
        // with the LED on pin 12 showing the least-significant bit
160
 
        for( int a = 0; a < 8; a++ )
161
 
                digitalWrite( 12 - a, ( ( segment >> a ) & 1 )? HIGH : LOW );
 
192
        for( int a = 0; a < 9; a++ )
 
193
                ledOn( 8 - a, ( segment >> a ) & 1 );
162
194
}
163
195
 
164
196
 
165
197
// draw a segment for the time display
166
 
void drawNextSegment_time( bool reset )
 
198
void drawNextSegment_time( int segment )
167
199
{
168
 
        static unsigned int second = 0;
169
 
        static unsigned int segment = 0;
170
 
 
171
 
        // handle display reset
172
 
        if( reset ) {
173
 
                second = 0;
174
 
                segment = 0;
175
 
        }
 
200
        int second = segment / NUM_SECOND_SEGMENTS;
 
201
        int second_segment = segment % NUM_SECOND_SEGMENTS;
176
202
 
177
203
        // what needs to be drawn?
178
 
        bool draw_tick = !segment && second % 5 == 0;
179
 
        bool draw_second = !segment && second == time_seconds;
180
 
        bool draw_minute = !segment && second == time_minute;
181
 
        bool draw_hour = !segment && second == time_hour;
 
204
        bool draw_tick = !second_segment && second % 5 == 0;
 
205
        bool draw_second = !second_segment && second == time_seconds;
 
206
        bool draw_minute = !second_segment && second == time_minutes;
 
207
        bool draw_hour = !second_segment && second == time_hours;
182
208
 
183
209
        // set the LEDs
184
 
        digitalWrite( 13, HIGH );
185
 
        digitalWrite( 12, draw_tick || draw_minute );
186
 
        for( int a = 10; a <= 11; a++ )
187
 
                digitalWrite( a, draw_minute || draw_second );
188
 
        for( int a = 4; a <= 9; a++ )
189
 
                digitalWrite( 10, draw_minute | draw_second || draw_hour );
190
 
 
191
 
        // inc position
192
 
        if( ++segment >= NUM_SECOND_SEGMENTS ) {
193
 
                segment = 0;
194
 
                second++;
195
 
        }
 
210
        ledOn( 9, true );
 
211
        ledOn( 8, draw_tick || draw_minute );
 
212
        for( int a = 6; a <= 7; a++ )
 
213
                ledOn( a, draw_minute || draw_second );
 
214
        for( int a = 0; a <= 5; a++ )
 
215
                ledOn( a, draw_minute || draw_second || draw_hour );
196
216
}
197
217
 
198
218
 
201
221
{
202
222
        static int draw_mode = 0;
203
223
 
 
224
        // keep track of segment
 
225
#if CLOCK_FORWARD
 
226
        static int segment = 0;
 
227
        if( reset ) segment = 0;
 
228
#else
 
229
        static int segment = NUM_SEGMENTS - 1;
 
230
        if( reset ) segment = NUM_SEGMENTS - 1;
 
231
#endif
 
232
 
204
233
        // handle mode switch requests
205
234
        if( reset && inc_draw_mode ) {
206
235
                inc_draw_mode = false;
211
240
 
212
241
        // draw the segment
213
242
        switch( draw_mode ) {
214
 
        case 0: drawNextSegment_test( reset ); break;
215
 
        case 1: drawNextSegment_time( reset ); break;
 
243
        case 0: drawNextSegment_test( segment ); break;
 
244
        case 1: drawNextSegment_time( segment ); break;
216
245
        }
 
246
 
 
247
#if CLOCK_FORWARD
 
248
        segment++;
 
249
#else
 
250
        segment--;
 
251
#endif
217
252
}
218
253
 
219
254
 
291
326
 
292
327
        // set up mode-switch button on pin 3
293
328
        pinMode( 3, INPUT );
 
329
        digitalWrite( 3, HIGH );
 
330
 
 
331
        // get the time from the real-time clock
 
332
        int rtc_data[ 7 ];
 
333
        RTC.get( rtc_data, true );
 
334
        time_hours = rtc_data[ DS1307_HR ];
 
335
        time_minutes = rtc_data[ DS1307_MIN ];
 
336
        time_seconds = rtc_data[ DS1307_SEC ];
294
337
 
295
338
        // serial comms
296
339
        Serial.begin( 9600 );