/elec/propeller-clock

To get this branch, use:
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
}