4
// Testing to see if we can read all 8 channels, multiplexed together on to two
5
// interrupts (odd channels on one, and even on the other). We read the
6
// channels by measuring the pulse width.
8
// Ideally, it would be nice if we could read the raw PPM stream from the
9
// receiver. Sometimes you can open up your receiver and get to this stream,
10
// but we have been unable. And since this isn't guaranteed to ever be
11
// available, reading the analogue outputs is certainly more portable. So, we
12
// are multiplexing the separate channels to two streams of pulses, like this:
14
// ch1 ch3 ch5 ch7 ch2 ch4 ch6 ch8
18
// ___ | | | | | | | | ___
19
// GND ---|___|---+----+----+----+ +----+----+----+----|___|--- GND
21
// ____________________ | __ | _____________________
24
// (interrupt 0) (interrupt 1)
26
// The two resistors in the circuit are pull-down resistors (so, say 100kΩ).
27
// Without them, the Arduino is unable to read the pulse wave at all.
29
// (Note that on our receiver, and contrary to the above diagram, the channels
30
// are not actually sent in order. Channels 2 and 3 are reversed. To this end,
31
// the order that channels are received can be adjusted below.)
37
// minimum pulse width (in ms), used to weed out crappy signals
38
#define MIN_PULSE_WIDTH 1000UL
40
// maximum pulse width (in ms), used to weed out crappy signals
41
#define MAX_PULSE_WIDTH 2000UL
44
#define NUM_CHANNELS 8
46
// minimum frame gap time (in ms), used to check that the frame gap is where we
47
// expect it to be and that we have read the channels properly
48
#define MIN_FRAME_GAP_WIDTH ( 4000UL + MIN_PULSE_WIDTH )
50
// the width of the display of a single channel (in chars)
53
// the channel's expected range for use in drawing (should be similar to
54
// {MAX,MIN}_PULSE_WIDTH values)
55
#define GRAPH_MIN 1000
56
#define GRAPH_MAX 2000
59
// channel sequence order
60
const int channel_order_[] = { 1, 3, 2, 4, 5, 6, 7, 8 };
62
// set to the time of the last pulse edges
63
static unsigned long new_pulse_up_[2] = { 0, 0 };
64
static unsigned long new_pulse_down_ = 0;
65
static char new_pulse_interrupt_;
68
// ISR to handle the PPM signals
69
inline void signal_handler( int interrupt, int pin )
71
// record rising/falling edge
72
if( digitalRead( pin ) )
73
new_pulse_up_[ interrupt ] = micros();
75
new_pulse_down_ = micros();
77
// record which interrupt just had a falling edge
78
new_pulse_interrupt_ = interrupt;
81
void signal_handler_0()
83
signal_handler( 0, 2 );
85
void signal_handler_1()
87
signal_handler( 1, 3 );
93
// set up an interrupts
94
attachInterrupt( 0, signal_handler_0, CHANGE );
95
attachInterrupt( 1, signal_handler_1, CHANGE );
96
digitalWrite( 2, LOW );
97
digitalWrite( 3, LOW );
103
unsigned long calculate_duration( unsigned long then, unsigned long now )
108
return now + ( ULONG_MAX - then );
114
bool read_channels( unsigned long channel_values[] )
116
static unsigned long last_pulse_down = 0;
117
static int next_channel = 0;
119
// capture pulse values atomically
121
unsigned long pulse_up = new_pulse_up_[ new_pulse_interrupt_ ];
122
unsigned long pulse_down = new_pulse_down_;
123
char new_pulse_interrupt = new_pulse_interrupt_;
126
// if the amount of time that has passed since the last falling edge is
127
// greater than the frame gap, reset the next channel so that we can start
128
// reading them again
130
new_pulse_interrupt == 1 &&
131
calculate_duration( pulse_down, micros() ) > MIN_FRAME_GAP_WIDTH )
133
// reset the next channel (which restarts reading them)
137
// check for a new complete pulse
138
if( pulse_down != last_pulse_down )
140
// are there still pulses to read?
141
if( next_channel < NUM_CHANNELS )
143
unsigned long duration =
144
calculate_duration( pulse_up, pulse_down );
146
// does this pulse look ok?
147
if( duration >= MIN_PULSE_WIDTH &&
148
duration <= MAX_PULSE_WIDTH )
150
// store channel value
151
int channel = channel_order_[ next_channel ] - 1;
152
channel_values[ channel ] = duration;
158
// set invalid channel number (to indicate error)
159
next_channel = NUM_CHANNELS + 1;
163
last_pulse_down = pulse_down;
166
// if we've read a frame, invalidate the frame (so we don't report it a
167
// second time) and return true
168
if( next_channel == NUM_CHANNELS ) {
177
void draw_graph( unsigned long channel_values[] )
180
static char graph[ GRAPH_SIZE + 2 ];
181
static char inited_graph = false;
182
if( !inited_graph ) {
183
for( int a = 1; a < GRAPH_SIZE + 1; a++ )
186
graph[ GRAPH_SIZE + 1 ] = 0;
191
for( int a = 0; a < NUM_CHANNELS; a++ ) {
192
unsigned long value = max( 0,
193
min( channel_values[ a ], GRAPH_MAX ) - GRAPH_MIN );
194
int pos = ( GRAPH_SIZE ) * value / ( GRAPH_MAX - GRAPH_MIN );
195
graph[ pos + 1 ] = '^';
196
Serial.print( graph );
197
graph[ pos + 1 ] = '_';
199
Serial.println( "|" );
205
unsigned long channel_values[ NUM_CHANNELS ];
209
if( read_channels( channel_values ) )
210
draw_graph( channel_values );