the only working sketch I found to generate PPM is for Arduino and use timer interrupt:
Code: Select all
//https://forum.arduino.cc/index.php/topic,163199.msg1220724.html#msg1220724
// Started 18 Apr 2013 - the loco chassis is more or less ready for testing.
//
// This is a test program to drive a loco on R/C channel 1 based on the position of a potentiometer.
//
// The centre connection of the pot is connected to pin A2
// The control signal from the Arduino to the transmitter is on Pin D7.
//
// I intend that parts of this program will be used in the computer controlled version.
//
// The R/C receiver is programmed to treat the centre value (128?) as off with 0 and 255 representing
// full forward and full reverse. Some experimentation will probably be necessary to determine the
// correct 0 point.
// The transmitter can receive a sequence of pulses for 2 to 7 channels. For this program pulses will be
// prepared for 7 channels with channels 2 to 7 being values that correspond to centre off.
// The receiver would not work with only 3 channels - it needs at least 4..
//
// The Transmitter expects a sequence of pulses each of whose width (duration) conveys the
// speed setting. The pulse lengths must vary between 1.0 and 2.0 millisecs with 1.5ms representing
// centre off. Each pulse must be separated by a short pulse of 0.3ms and there must be a long pulse
// to separate the groups of pulses. Ideally the group of pulses should repeat every 22ms
// So, 2.0 + 0.3ms for 7 pulses takes 16.1ms thus requiring a separating pulse of 5.9ms.
//
// The pulses are generated by timer1 (16 bit) interrupts and to simpify matters when the computer is
// controlling things the numbers needed to produce the sequence of pulse lengths will be stored
// in an array. At each interrupt the next value in the array is used to set the duration for the
// following interrupt. For this program the values in the array position corresponding to channel 3
// will be derived from the potentiometer position. (The Rx seems to be programmed to drive the motor
// on ch3).
//
// Timer1 is used because the longer periods afforded by the 16bits are needed. The prescaler is set
// to divide the CPU clock by 64 giving a timer clock of 250khz or 4 microsecs (4us).
// On that basis 0.3ms requires a delay of 75 clock steps
// 1.0 250
// 1.5 375
// 2.0 500
// 5.9 1475
// 15.1 3775
//
// This program only communicates with the PC for program testing.
// Data variables
unsigned int ppm[16]; // the array of values for the timer1 interrupt timings
unsigned int potVal; // value read from potemtiometer
int curPpm = 0; // the position in the array of timings
byte curPpmMax; // the actual number of timer steps
char pulsePin = 7; // the digital pin for sending pulses to the transmitter
char debugPin = 13; // something to watch to check things are working
char potPin = 2; // the analog pin for the potentiometer
byte loopCount = 0; // a crude substitute for delay()
int analogIn; // for reading potentiometer position
boolean testing = true;
void setup() {
if (testing) {
Serial.begin(9600);
Serial.println("Starting TrainRadioPot");
}
// set the pin directions
pinMode(pulsePin, OUTPUT);
// pinMode(debugPin, OUTPUT);
// set the timing values
ppm[0] = 1475; //3775; // long pulse - see notes above
ppm[1] = 75; // short dividing pulse
ppm[2] = 305; // loco1 ch1
ppm[3] = 75; // short
ppm[4] = 305; // loco2 ch2
ppm[5] = 75; // short
ppm[6] = 305; // loco3 ch3
ppm[7] = 75; // short
ppm[8] = 305; // loco4 ch4
ppm[9] = 75; // short
ppm[10] = 305; // loco5 ch5
ppm[11] = 75; // short
ppm[12] = 305; // loco6 ch6
ppm[13] = 75; // short
ppm[14] = 305; // loco7 ch7
ppm[15] = 75; // short
curPpmMax = 16; // the number of timer values
curPpm = 0; // the starting position in the array of timings
// setup and start timer interrupts
// ppm is achieved by sending different delays to the timer interrupt
noInterrupts();
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
// set compare match register to desired timer count:
OCR1A = 1000; // It works by causing an interrupt when TCNT2 counts up to this number
// This number will be set from the ppm array when the program is running
digitalWrite(pulsePin, 0); // start with pin low
// turn on CTC mode: Clear Timer on Compare
bitSet(TCCR1B, WGM12);
// Set CS10 and CS11 bits for 64 prescaler: 10, 12 = 1024
bitSet(TCCR1B, CS10);
bitSet(TCCR1B, CS11);
bitClear(TCCR1B, CS12);
// enable timer compare A interrupt:
bitSet(TIMSK1, OCIE1A);
interrupts();
}
void loop() {
if (loopCount == 1) {
analogIn = analogRead(potPin);
// the reading must be converted from the range 0 - 1023 to the range 250 - 500
// which means dividing by 4 and adding 180 to give 305 at the centre
potVal = (analogIn >> 2) + 180;
// if (potVal > 302 && potVal < 308) {
if (potVal > 280 && potVal < 320) {
potVal = 305; // to create an off space without jitter
}
// ppm[2] = potVal;
// ppm[8] = potVal;// } CH4 ROL STABE
// ppm[4] = potVal; // CH2 PAN STABE YAW
ppm[6] = potVal; // CH3 TILT STABE PICH
}
// loopCount = 0; // for testing - so analog read is ignored
loopCount = loopCount + 1; // it will roll over to zero automatically
// the purpose of loopCount is so that the pot isn't read every loop
}
// interrupt routine that is triggered when the timer counts up to the preset value
ISR(TIMER1_COMPA_vect) {
noInterrupts();
digitalWrite(pulsePin, !digitalRead(pulsePin)); // change the state of the pin
OCR1A = ppm[curPpm]; // set the value for the next time interval
curPpm = ((curPpm + 1) % curPpmMax); // move the index on
// the modulus operator makes the index roll over to the start
interrupts();
}
Code: Select all
//this programm will put out a PPM signal
//////////////////////CONFIGURATION///////////////////////////////
#define chanel_number 8 //set the number of chanels
#define default_servo_value 1500 //set the default servo value
#define PPM_FrLen 22500 //set the PPM frame length in microseconds (1ms = 1000µs)
#define PPM_PulseLen 300 //set the pulse length
#define onState 1 //set polarity: 1 is positive, 0 is negative
#define sigPin 10 //set PPM signal pin on the arduino
//////////////////////////////////////////////////////////////////
/*this array holds the servo values for the ppm signal
change theese values in your code (usually servo values are between 1000 and 2000)*/
int ppm[chanel_number];
void setup(){
//initiallize default ppm values
for(int i=0; i<chanel_number; i++){
ppm[i]= default_servo_value;
}
pinMode(sigPin, OUTPUT);
digitalWrite(sigPin, !onState); //set the PPM signal pin to the default state (off)
}
void loop(){
//put main code here
ppmWrite();
}
void ppmWrite(){ //generate PPM signal
static unsigned long lastFrLen;
static unsigned long lastServo;
static unsigned long lastPulse;
static boolean PPM_run;
static boolean pulse;
static boolean pulseStart = true;
static byte counter;
static byte part = true;
if(micros() - lastFrLen >= PPM_FrLen){ //start PPM signal after PPM_FrLen has passed
lastFrLen = micros();
PPM_run = true;
}
if(counter >= chanel_number){
PPM_run = false;
counter = 0;
pulse = true; //put out the last pulse
}
if(PPM_run){
if (part){ //put out the pulse
pulse = true;
part = false;
lastServo = micros();
}
else{ //wait till servo signal time (values from the ppm array) has passed
if(micros() - lastServo >= ppm[counter]){
counter++; //do the next channel
part = true;
}
}
}
if(pulse){
if(pulseStart == true){ //start the pulse
digitalWrite(sigPin, onState);
pulseStart = false;
lastPulse = micros();
}
else{ //will wait till PPM_PulseLen has passed and finish the pulse
if(micros() - lastPulse >= PPM_PulseLen){
digitalWrite(sigPin, !onState);
pulse = false;
pulseStart = true;
}
}
}
}
I'm trying to merge the first sketch with a timer interrupt sketch for esp32
Code: Select all
volatile int interruptCounter;
int totalInterruptCounter;
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timerMux);
interruptCounter++;
portEXIT_CRITICAL_ISR(&timerMux);
}
void setup() {
Serial.begin(115200);
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
// timerAlarmWrite(timer, 1000000, true);
timerAlarmWrite(timer, 22000, true); PER IL PPM ?? ??
timerAlarmEnable(timer);
}
void loop() {
if (interruptCounter > 0) {
portENTER_CRITICAL(&timerMux);
interruptCounter--;
portEXIT_CRITICAL(&timerMux);
totalInterruptCounter++;
Serial.print("An interrupt as occurred. Total number: ");
Serial.println(totalInterruptCounter);
}
}