Created
November 29, 2017 17:18
-
-
Save S-Bartfast/97a20c25165cec84c73ec849e77a44e7 to your computer and use it in GitHub Desktop.
Arduino Sketch that combines multiple PPM streams into one single stream.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This code is released under the WTFPL and is here by considered to be in the public domain. | |
*/ | |
int OUT_PIN = 7; | |
int LED_PIN = 13; | |
int blip_us = 300; // Length of blip (in microseconds) | |
#define NUM_SOURCES 2 // Number of sources to combine (only two interrupts available on Arduino UNO) | |
#define CHANNELS_PER_SOURCE 4 // Number of channels to read from each source | |
#define MIN_LENGTH 500 // Full negative deflection on servo (0.5ms) | |
#define DEFAULT_LENGTH 1500 // Zero position on servo (1.5ms) | |
#define MAX_LENGTH 2500 // Full positive deflection on servo (2.5ms) | |
#define FRAME_LENGTH 22500; // Total length of entire frame (including all channels plus the frame separating gap), 22.5ms | |
int channels[CHANNELS_PER_SOURCE * NUM_SOURCES]; // Array containing the length used for watch channel | |
int PPM_1_in = 2; // Interrupt pin for first PPM input | |
int PPM_2_in = 3; // Interrupt pin for second PPM input | |
unsigned long last_pulse[2]; // Array used to 'remember' at what time the last 'blip' was read for each source | |
int current_channel[2]; // The channel currently being read for each source | |
void setup() | |
{ | |
// Set mid-range value for all channels to begin with | |
for (int i=0 ; i<CHANNELS_PER_SOURCE*NUM_SOURCES ; i++) | |
channels[i] = DEFAULT_LENGTH; | |
// Initialize digital pin OUT_PIN which the combined PPM signal will be sent out of. | |
pinMode(OUT_PIN, OUTPUT); | |
// Set the default position of the 'read' pins to he 'HIGH' as the pulses are 'falling edge synchronised'. | |
pinMode(PPM_1_in, INPUT_PULLUP); | |
pinMode(PPM_2_in, INPUT_PULLUP); | |
// Assign interrupts for all the sources (only two available on Arduino UNO) | |
attachInterrupt(digitalPinToInterrupt(PPM_1_in), blipped_1, FALLING); | |
attachInterrupt(digitalPinToInterrupt(PPM_2_in), blipped_2, FALLING); | |
// Initialise with 'current time'. | |
last_pulse[1] = last_pulse[0] = micros(); | |
} | |
// the loop function runs over and over again forever | |
void loop() | |
{ | |
printFrame(); | |
} | |
// Interrupt called for PPM input 1 | |
void blipped_1() | |
{ | |
blipped(0); | |
} | |
// Interrupt called for PPM input 2 | |
void blipped_2() | |
{ | |
blipped(1); | |
} | |
// Determine if current channel is in range (note we probably only actually need to check the 'upper-bound'). | |
boolean chanelInRange(int source) | |
{ | |
int lower_bound = source * CHANNELS_PER_SOURCE; | |
int upper_bound = (source + 1) * CHANNELS_PER_SOURCE; | |
return lower_bound <= current_channel[source] && current_channel[source] < upper_bound; | |
} | |
// Process received 'blip' | |
void blipped(int source) | |
{ | |
unsigned long this_pulse = micros(); | |
unsigned long pulse_width = this_pulse - last_pulse[source]; | |
if (pulse_width < MIN_LENGTH) | |
{ | |
// Probably just 'bouncing' noise | |
return; | |
} | |
else if (pulse_width < MAX_LENGTH) | |
{ | |
// Record the channels length | |
if (chanelInRange(source)) | |
channels[current_channel[source]] = pulse_width; | |
current_channel[source]++; | |
} | |
else // pulse_width > 2500 | |
{ | |
// End of frame | |
current_channel[source] = source * CHANNELS_PER_SOURCE; | |
} | |
last_pulse[source] = this_pulse; | |
} | |
// Print a blip to output pin | |
void blip() | |
{ | |
digitalWrite(OUT_PIN, LOW); | |
delayMicroseconds(blip_us); | |
digitalWrite(OUT_PIN, HIGH); | |
} | |
void printFrame() | |
{ | |
unsigned long remainingWindow = FRAME_LENGTH; | |
// Open the frame | |
blip(); | |
remainingWindow -= blip_us; | |
// Print each of the channels | |
for (int i=0 ; i<CHANNELS_PER_SOURCE * NUM_SOURCES ; i++) | |
{ | |
delayMicroseconds(channels[i] - blip_us); | |
blip(); | |
remainingWindow -= channels[i]; | |
} | |
// Add trailing space to deliniate the end of the frame. | |
// Max value that can be sent to 'delayMicroseconds(...)' is 16383 so we must use regular 'delay(...)' first then "finish off" with MicroSec. | |
delay(remainingWindow/1000); | |
delayMicroseconds(remainingWindow%1000); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment