bzr branch
http://bzr.ed.am/elec/propeller-clock
13
by edam
updated propeller-clock code, added GPL text and renamed fan-test |
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 |
|
11
by Dan
added initial propeller clock code |
31 |
static unsigned long new_pulse_at = 0; |
32 |
||
13
by edam
updated propeller-clock code, added GPL text and renamed fan-test |
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 |
|
11
by Dan
added initial propeller clock code |
52 |
void fanPulseHandler() |
53 |
{ |
|
13
by edam
updated propeller-clock code, added GPL text and renamed fan-test |
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 |
|
11
by Dan
added initial propeller clock code |
141 |
void loop() |
142 |
{ |
|
13
by edam
updated propeller-clock code, added GPL text and renamed fan-test |
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 ); |
|
11
by Dan
added initial propeller clock code |
155 |
} |