4
* Copyright (C) 2011 Tim Marston <edam@waxworlds.org>
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
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.
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.
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/>.
24
//_____________________________________________________________________________
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
31
static unsigned long new_pulse_at = 0;
33
// the time (in microseconds) when the last fan pulse occurred
34
static unsigned long last_pulse_at = 0;
36
// duration (in microseconds) that a segment should be displayed
37
static unsigned long segment_step = 0;
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;
47
//_____________________________________________________________________________
51
// ISR to handle the pulses from the fan's tachiometer
52
void fanPulseHandler()
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;
62
// set a new pulse time
63
new_pulse_at = micros();
68
// draw a particular segment
69
void drawNextSegment( bool reset )
71
static unsigned int segment = 0;
72
if( reset ) segment = 0;
75
for( int a = 0; a < 10; a++ )
76
digitalWrite( a + 4, ( ( segment >> a ) & 1 )? HIGH : LOW );
80
// calculate time constants when a new pulse has occurred
81
void calculateSegmentTimes()
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 )
87
// new segment stepping times
88
unsigned long delta = new_pulse_at - last_pulse_at;
89
segment_step = delta / NUM_SEGMENTS;
91
segment_step_sub_step = delta % NUM_SEGMENTS;
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;
101
// wait until it is time to draw the next segment or a new pulse has
103
void waitTillNextSegment( bool reset )
105
static unsigned long end_time = 0;
109
end_time = last_pulse_at;
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;
120
while( micros() < end_time && !new_pulse_at );
127
// set up an interrupt handler on pin 2 to nitice fan pulses
128
attachInterrupt( 0, fanPulseHandler, RISING );
129
digitalWrite( 2, HIGH );
131
// set up output pins (4 to 13) for the led array
132
for( int a = 4; a < 14; a++ )
133
pinMode( a, OUTPUT );
136
Serial.begin( 9600 );
143
// if there has been a new pulse, we'll be resetting the display
144
bool reset = new_pulse_at? true : false;
147
drawNextSegment( reset );
149
// do we need to recalculate segment times?
151
calculateSegmentTimes();
153
// wait till it's time to draw the next segment
154
waitTillNextSegment( reset );