Here is the code i use:
//Serial to PPM based on Ian´s:
//// RC Joystick 430mHz
//// For use with Arduino Nano V3.0
//// Ian Johnston 28/04/2010
////
//// If you would like to help support future projects like these then please
//// make a small PayPal donation via my website www.ianjohnston.com
//// Thanks!
////
//// Ver 1.6 - Now using Timer1 to set 22mS refresh for PPM output.
//// Dual rates are implemented but need custom setup.
//// Trimming is not working.
//// Battery monitor sub tweaked
//// Adjusted timing off various subs
//// Various tweaks to LCD & battery monitor
////
// Serial to PPM ??? SEND: S010800 to set Channel 1 to Pos 800
int tick = 0; // Used for various timing of subs
int tick2 = 0; // Used for various timing
int slowflag;
int CH1= 700;
int CH2 = 700;
int CH3 = 700;
int CH4 = 700;
int CH5 = 700;
int CH6 = 700;
int RatesHIMIDLO = 2; // Default is MID rates
int TrimSetting = 0;
int Fixed_uS = 300; // PPM frame fixed LOW phase
int pulseMin = 700; // pulse minimum width in uS
int pulseMax = 1700; // pulse maximum width in uS
int outPinTEST = 8; // digital pin 8
int outPinPPM = 10; // digital pin 10
//*** Serial COM&Comand
const int MSG_LENGTH = 7; // message is char 'S' followed by 6 digits
const char HEADER = 'S';
//***
ISR(TIMER1_COMPA_vect) {
ppmoutput(); // Jump to ppmoutput subroutine
tick = tick + 1; // update timing tick for subs
tick2 = tick2 + 1; // update tick
}
void setup() {
// setup I/O
pinMode(outPinPPM, OUTPUT); // sets the digital pin as output
// ** SERIAL SETUP
Serial.begin(57600); // connect to the serial port
Serial.println("Serial to PPM");
//****
// Setup timer
TCCR1A = B00110001; // Compare register B used in mode '3'
TCCR1B = B00010010; // WGM13 and CS11 set to 1
TCCR1C = B00000000; // All set to 0
TIMSK1 = B00000010; // Interrupt on compare B
TIFR1 = B00000010; // Interrupt on compare B
OCR1A = 22000; // 22mS PPM output refresh
OCR1B = 1000;
}
void loop() { // Main loop
processSerial();
//readanainputsmap(); // Run sub - read ana inputs & map
checklimits(); // Run sub - check individual channel PPM limits
//
// if (tick >= 11) { // only run certain subs every 1/4 sec or so (22mS * 11 = 242mS)
// tick = 0;
// //switchesRates(); // Run sub - read panel switches
// //batterymonitor(); // Run sub - check battery
// }
//
// // generate slow changing flag, about 2sec on/off
// if (tick2 <= 50) {
// slowflag = 0;
// }
// if (tick2 >= 50 && tick2 <=100) {
// slowflag = 1;
// }
// if (tick2 >= 100) {
// slowflag = 0;
// tick2 = 0;
// }
}
void processSerial() {
// Process a message available on serial port
while(Serial.available() >= MSG_LENGTH ) // process messages when all characters are received: "S" as start indicator, 2 digits as channel number, 4 digits for the value
{
if(Serial.read() == HEADER ) //Serial.Read() will "use up" the chars, so we can forget about the "S" now...
{
int val = 0;
int sval =0;
//First 2 digits are the Channel...
for(int i =0; i < MSG_LENGTH-5; i++)//7-5=2
{
char ch = Serial.read();
if(ch >= '0' && ch <= '9'){ // is ch a number?
sval = sval * 10 + ch - '0'; // yes, accumulate the value
}
}
Serial.print("CH: ");
Serial.println(sval); // For debug
//Next 4 Digits should be the position/
for(int i =0; i < MSG_LENGTH-3; i++) // 7-3=4 ... 2+4=6 ... S-12-3456
{
char ch = Serial.read();
if(ch >= '0' && ch <= '9'){ // is ch a number?
val = val * 10 + ch - '0'; // yes, accumulate the value
}
}
Serial.print("POS: ");
Serial.println(val); // for debug
Serial.flush();//clear buffer, there might be some rubbish inside...
//Serial.println(sval);
//Serial.println(val);
// For now its just Channel 1 which will get its new value.
if (sval==1){
CH1=val;
Serial.print("CH1 Set to ");
Serial.println(CH1);
}
}
}
}
void checklimits() { // check limits sub
if (CH1 < 700) CH1 = 700; // Min
if (CH1 > 1700) CH1 = 1700; // Max
if (CH2 < 700) CH2 = 700; // Min
if (CH2 > 1700) CH2 = 1700; // Max
if (CH3 < 700) CH3 = 700; // Min
if (CH3 > 1700) CH3 = 1700; // Max
if (CH4 < 700) CH4 = 700; // Min
if (CH4 > 1700) CH4 = 1700; // Max
if (CH5 < 700) CH5 = 700; // Min
if (CH5 > 1700) CH5 = 1700; // Max
if (CH6 < 700) CH6 = 700; // Min
if (CH6 > 1700) CH6 = 1700; // Max
}
void ppmoutput() { // PPM output sub
// test pulse - used to trigger scope
//digitalWrite(outPinTEST, LOW);
//delayMicroseconds(100); // Hold
// digitalWrite(outPinTEST, HIGH);
// Channel 1 - Aeleron
digitalWrite(outPinPPM, LOW);
delayMicroseconds(Fixed_uS); // Hold
digitalWrite(outPinPPM, HIGH);
delayMicroseconds(CH1); // Hold for Aeleron_uS microseconds
// Channel 2 - Elevator
digitalWrite(outPinPPM, LOW);
delayMicroseconds(Fixed_uS); // Hold
digitalWrite(outPinPPM, HIGH);
delayMicroseconds(CH2); // Hold for Elevator_uS microseconds
// Channel 3 - Throttle
digitalWrite(outPinPPM, LOW);
delayMicroseconds(Fixed_uS); // Hold
digitalWrite(outPinPPM, HIGH);
delayMicroseconds(CH3); // Hold for Throttle_uS microseconds
// Channel 4 - Rudder
digitalWrite(outPinPPM, LOW);
delayMicroseconds(Fixed_uS); // Hold
digitalWrite(outPinPPM, HIGH);
delayMicroseconds(CH4); // Hold for Rudder_uS microseconds
// Channel 5 - TI Switch
digitalWrite(outPinPPM, LOW);
delayMicroseconds(Fixed_uS); // Hold
digitalWrite(outPinPPM, HIGH);
delayMicroseconds(CH5); // Hold for TIsw_uS microseconds
// Channel 6 - TI pot
digitalWrite(outPinPPM, LOW);
delayMicroseconds(Fixed_uS); // Hold
digitalWrite(outPinPPM, HIGH);
delayMicroseconds(CH6); // Hold for TI_uS microseconds
// Synchro pulse
digitalWrite(outPinPPM, LOW);
delayMicroseconds(Fixed_uS); // Hold
digitalWrite(outPinPPM, HIGH); // Start Synchro pulse
}