/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 propeller-clock/propeller-clock.pde

  • Committer: edam
  • Date: 2011-11-17 13:05:46 UTC
  • Revision ID: edam@waxworlds.org-20111117130546-by4v2vm98emidlrk
updated propeller-clock code, added GPL text and renamed fan-test

Show diffs side-by-side

added added

removed removed

1
 
//
2
 
// propeller-clock.pde
3
 
//
4
 
// A propeller clock.
5
 
 
6
 
void setup()
7
 
{
8
 
  // set up an interrupt handler on pin 2 to nitice fan pulses
9
 
  attachInterrupt( 0, fanPulseHandler, RISING );
10
 
  digitalWrite( 2, HIGH );
11
 
  
12
 
  // set up output pins (4 to 13) for the led array
13
 
  for( int a = 4; a < 14; a++ )
14
 
    pinMode( a, OUTPUT );
15
 
 
16
 
  // serial comms
17
 
  Serial.begin( 9600 );
18
 
}
19
 
 
20
 
// when non-zero, the time (in microseconds) of a new fan pulse that has just
21
 
// occurred, which means that segment drawing needs to be restarted
 
1
/*
 
2
 * propeller-clock.pde
 
3
 *
 
4
 * Copyright (C) 2011 Tim Marston <edam@waxworlds.org>
 
5
 *
 
6
 * 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
 * information.
 
9
 *
 
10
 * This program is free software: you can redistribute it and/or modify
 
11
 * it under the terms of the GNU Lesser General Public License as published
 
12
 * by the Free Software Foundation, either version 3 of the License, or
 
13
 * (at your option) any later version.
 
14
 *
 
15
 * This program is distributed in the hope that it will be useful,
 
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 * GNU Lesser General Public License for more details.
 
19
 *
 
20
 * You should have received a copy of the GNU Lesser General Public License
 
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
22
 */
 
23
 
 
24
//_____________________________________________________________________________
 
25
//                                                                         data
 
26
 
 
27
 
 
28
// when non-zero, the time (in microseconds) of a new fan pulse that
 
29
// has just occurred, which means that segment drawing needs to be
 
30
// restarted
22
31
static unsigned long new_pulse_at = 0;
23
32
 
24
 
// interrupt handler to count the number of fan pulses
 
33
// the time (in microseconds) when the last fan pulse occurred
 
34
static unsigned long last_pulse_at = 0;
 
35
 
 
36
// duration (in microseconds) that a segment should be displayed
 
37
static unsigned long segment_step = 0;
 
38
 
 
39
// remainder after divisor and a tally of the remainders for each segment
 
40
static unsigned long segment_step_sub_step = 0;
 
41
static unsigned long segment_step_sub = 0;
 
42
 
 
43
// display mode
 
44
static
 
45
 
 
46
 
 
47
//_____________________________________________________________________________
 
48
//                                                                         code
 
49
 
 
50
 
 
51
// ISR to handle the pulses from the fan's tachiometer
25
52
void fanPulseHandler()
26
53
{
27
 
  // ignore every other pulse
28
 
  static bool ignore = true;
29
 
  ignore = !ignore;
30
 
  if( !ignore )
31
 
  {
32
 
    // set a new pulse time
33
 
    new_pulse_at = micros();
34
 
  }
35
 
}
36
 
 
37
 
// wait until it is time to draw the next segment or a new pulse has occurred
38
 
void endOfSegmentDelay()
39
 
{
40
 
  while( micros() < next_segment_at && !new_pulse_at );
41
 
}
42
 
 
 
54
        // the fan actually sends two pulses per revolution. These pulses
 
55
        // may not be exactly evenly distributed around the rotation, so
 
56
        // we can't recalculate times on every pulse. Instead, we ignore
 
57
        // every other pulse so timings are based on a complete rotation.
 
58
        static bool ignore = true;
 
59
        ignore = !ignore;
 
60
        if( !ignore )
 
61
        {
 
62
                // set a new pulse time
 
63
                new_pulse_at = micros();
 
64
        }
 
65
}
 
66
 
 
67
 
 
68
// draw a particular segment
 
69
void drawNextSegment( bool reset )
 
70
{
 
71
        static unsigned int segment = 0;
 
72
        if( reset ) segment = 0;
 
73
        segment++;
 
74
 
 
75
        for( int a = 0; a < 10; a++ )
 
76
                digitalWrite( a + 4, ( ( segment >> a ) & 1 )? HIGH : LOW );
 
77
}
 
78
 
 
79
 
 
80
// calculate time constants when a new pulse has occurred
 
81
void calculateSegmentTimes()
 
82
{
 
83
        // check for overflows, and only recalculate times if there isn't
 
84
        // one (if there is, we'll just go with the last pulse's times)
 
85
        if( new_pulse_at > last_pulse_at )
 
86
        {
 
87
                // new segment stepping times
 
88
                unsigned long delta = new_pulse_at - last_pulse_at;
 
89
                segment_step = delta / NUM_SEGMENTS;
 
90
                segment_step_sub = 0;
 
91
                segment_step_sub_step = delta % NUM_SEGMENTS;
 
92
        }
 
93
 
 
94
        // now we have dealt with this pulse, save the pulse time and
 
95
        // clear new_pulse_at, ready for the next pulse
 
96
        last_pulse_at = new_pulse_at;
 
97
        new_pulse_at = 0;
 
98
}
 
99
 
 
100
 
 
101
// wait until it is time to draw the next segment or a new pulse has
 
102
// occurred
 
103
void waitTillNextSegment( bool reset )
 
104
{
 
105
        static unsigned long end_time = 0;
 
106
 
 
107
        // handle reset
 
108
        if( reset )
 
109
                end_time = last_pulse_at;
 
110
 
 
111
        // work out the time that this segment should be displayed until
 
112
        end_time += segment_step;
 
113
        semgment_step_sub += semgment_step_sub_step;
 
114
        if( semgment_step_sub >= NUM_SEGMENTS ) {
 
115
                semgment_step_sub -= NUM_SEGMENTS;
 
116
                end_time++;
 
117
        }
 
118
 
 
119
        // wait
 
120
        while( micros() < end_time && !new_pulse_at );
 
121
}
 
122
 
 
123
 
 
124
// main setup
 
125
void setup()
 
126
{
 
127
        // set up an interrupt handler on pin 2 to nitice fan pulses
 
128
        attachInterrupt( 0, fanPulseHandler, RISING );
 
129
        digitalWrite( 2, HIGH );
 
130
  
 
131
        // set up output pins (4 to 13) for the led array
 
132
        for( int a = 4; a < 14; a++ )
 
133
                pinMode( a, OUTPUT );
 
134
 
 
135
        // serial comms
 
136
        Serial.begin( 9600 );
 
137
}
 
138
 
 
139
 
 
140
// main loop
43
141
void loop()
44
142
{
45
 
  static int led = 4;
46
 
 
47
 
  unsigned long loop_start_time = micros();
48
 
 
49
 
  // wait till it's time to draw the next segment
50
 
  
 
143
        // if there has been a new pulse, we'll be resetting the display
 
144
        bool reset = new_pulse_at? true : false;
 
145
 
 
146
        // draw this segment
 
147
        drawNextSegment( reset );
 
148
 
 
149
        // do we need to recalculate segment times?
 
150
        if( reset )
 
151
                calculateSegmentTimes();
 
152
 
 
153
        // wait till it's time to draw the next segment
 
154
        waitTillNextSegment( reset );
51
155
}