Nigel, did you read my post? If you're capture servo signals from a single RC receiver they will never overlap, and there will be a longer gap than normal between two pulses which will be the frame boundary, it's especially easy with a transmitter doing less than 6 channels because the frame gap is quiet long. However if you have the available I/O and are willing to code for it a single I/O line each is just as good. Personally I'd fish around on the receivers PC board for the decoder chips input and tap the baseband signal.
even the Mk1 BASIC STAMPS can do it (which ran incredibly slowly), and it was a very common application for them.
Hi, Nigel
The problem is ... Basic stamps and generally basic compilers have Pulsin and RCTime commands that DO NOT USE any timer ...
Basically the sequence then is :
Pulsin Ch1
RCTime Ch2
RCTime ch3
RCTime ch 4
....
BUT "C" Compilers do not offer the equivalent " full software " commands ... that might be "customer included" as pure assembler functions ( nice piece of cake, eh ??? ...).
as an info ... the time between Ch1 falling edge and Ch2 rising edge is about the 10 Nanoseconds ... of course for CMOS decoder chips. if decoder is a µP ... consider 200-500 Nano secs, which is far too short for inputs Polling.
For last systems ... channel output can be 2 per 2 , 3 per 3 or all together ...
so, the only way is to catch the serial frame @ the output of the receiver part ...
Alain
Yes I know, why would you want to use a timer?.
It would be trivial to write a 'pulsein' commend in C, just as it is in assembler.
BASIC STAMP's manage it, 12F sries manage it, 12 series amange it as well - there's loads of time for polling.
Funny how there's loads of amateur and commercial PIC based products which happily read the individual servo outputs.
Probably Trivial ... never saw such piece of code, but lots of threads asking for it ...
NO, Nigel ... with Basic , or polling you read the first channel of the first frame, then the 2nd channel of the SECOND frame, etc, etc ... PULSIN needs some µs ( I measured 4 µs @ 4 Mhz ) to " re-arm " its leading edge detector ... polling also need time between edges ...
//Basic configureation of chip periferials
#include <timers.h>
#include <p18f2550.h>
#pragma FOSC = INTI0, WDT = OFF, LVP = OFF
//setup pins for PWM input
#define ReceiverPin PORTBbits.RB3
#define ReceiverTris TRISBbits.TRISB3
//PWM capture variables
unsigned int PWM1RiseTime = 0; //timer value at rising edge capture
unsigned int PWM1Width = 0; //calculated width
char PWM1Edge = 1; //edge currently being monitored 1 = rising, 0 = falling
//set up interrupt
void low_ISR(void);//prototype
#pragma code low_vector = 0x08
void low_interrupt (void){
_asm goto low_ISR _endasm
}
#pragma code
#pragma interrupt low_ISR
//debug stuff
char test1 = 0;
char test2 = 0;
void main(void)
{
unsigned int MotorCount = 1;
unsigned char MotorOn;
OSCCON = 0x72; //8MHz clock
while(!OSCCONbits.IOFS); //Wait for OSC to become stable
//configure timer1
OpenTimer1(0b10010101);
PIE1bits.TMR1IE = 1; //periferial interupt register, 1 = timer 1 interupt enabled
PIR1bits.TMR1IF = 0; //clears the timer 1 interupt flag
//configure CCP1
CCP1CON = 0b0000101; //configure CCP1 for capture, rising edge
INTCONbits.PEIE=1; //enable peripheral interrupts
PIE1bits.CCP1IE=1; //enabled CCP1 interrupt
INTCONbits.GIE=1; //enable branching to interrupt
ReceiverTris = 1; //set RB3 for input so the capture can work.
//configure ports
ADCON1 = 0xff; //all digital
INTCON2bits.RBPU = 0; //port b weak pullups on
//configure control bits for output
TRISBbits.TRISB5 = 0;
TRISBbits.TRISB4 = 0;
TRISAbits.TRISA4 = 0;
//enable bit
LATAbits.LATA4 = 1; //Enable bit for cl298
LATBbits.LATB5 = 1;//testing
LATBbits.LATB4 = 0;
while(1)
{
}
}
void low_ISR(void)
{
test1 = 1;
//ccp interrupt
if(PIR1bits.CCP1IF == 1)
{
PIR1bits.CCP1IF = 0; //clear the flag
if(PWM1Edge == 1)//if detecting rising
{
PWM1RiseTime = CCPR1;//save the low timer value for the rise time
CCP1CON = 0b0000100;//switch to detect falling edge
PWM1Edge = 0;//switch to indicate falling edge is next
}
else //detecting falling
{
PWM1Width = CCPR1 - PWM1RiseTime;
CCP1CON = 0b0000101;//switch to detect rising edge
PWM1Edge = 1;//switch to indicate rising edge is next
}
//This stuff is just for testing
if(PWM1Width > 1800)
{
LATBbits.LATB4 = 0;
LATBbits.LATB5 = 1;
}
if(PWM1Width < 1400)
{
LATBbits.LATB4 = 1;
LATBbits.LATB5 = 0;
}
if(PWM1Width > 1400 && PWM1Width < 1800)
{
LATBbits.LATB4 = 1; //should be 0 if not testing
LATBbits.LATB5 = 0;
}
}
}
Here you go:
.
//must be global
unsigned char Previous;
unsigned int T1High,T1Period;
void low_ISR(void)
{
unsigned char Changed,Port,NewHigh,NewLow;
unsigned int Time;
Time=TMR1L; //read low byte and latch high
Time+=TMR1H<<8; //read latched high byte
Port=PORTB; //read the port
if(INTCONbits.RBIF) //Must be this but check anyway
{
Changed=Previous^Port; //see which bits have changed
NewHigh=Changed&Previous; //and which are new highs
NewLow=Changed&~Previous; //also new lows
if(NewHigh&0x10){ //did B4 go high
T1High=Time; //yes, so store time
}
if(NewLow&0x10){ //did B4 go low
T1Period=Time-T1High; //yes, so calculate period
}
//repeat for B5,B6 and B7 as required
Previous=Port; //store current state of PortB
INTCONbits.RBIF = 0; //reset interrupt flag
}
}
NewHigh=Changed&Previous; //and which are new highs
NewLow=Changed&~Previous; //also new lows
NewHigh=Changed&~Previous; //and which are new highs
NewLow=Changed&Previous; //also new lows
NewHigh=Changed&Port; //and which are new highs
NewLow=Changed&Previous; //also new lows
//Basic configureation of chip periferials
#pragma config OSC = INTIO2, WDT = OFF, LVP = OFF
#include <p18f1320.h>
#include <delays.h>
#include<timers.h>
//setup pins for PWM input
#define ReceiverPin PORTBbits.RB3
#define ReceiverTris TRISBbits.TRISB3
//PWM capture variables
unsigned int PWM1RiseTime = 0; //timer value at rising edge capture
unsigned int PWM1FallTime = 0; //timer value at falling edge capture
unsigned int PWM1Width = 0; //calculated width
unsigned int channel1_width = 0;
unsigned int channel2_width = 0;
unsigned int channel3_width = 0;
unsigned int PWMGap = 0; //calculated gap between pulses
char PWM1Edge = 1; //edge currently being monitored 1 = rising, 0 = falling
unsigned char Channel_Being_Captured = 1; //this will record which channel is being watched
//set up interrupt
void low_ISR(void);//prototype
#pragma code low_vector = 0x08 //0X08 IS LOW 0X18 IS HIGH
void low_interrupt (void){
_asm goto low_ISR _endasm
}
#pragma code
#pragma interrupt low_ISR
void main(void)
{
OSCCON = 0x72; //8MHz clock
while(!OSCCONbits.IOFS); //Wait for OSC to become stable
//configure timer1
//OpenTimer1(0b10010101);
//PIE1bits.TMR1IE = 1; //periferial interupt register, 1 = timer 1 interupt enabled
PIR1bits.TMR1IF = 0; //clears the timer 1 interupt flag
T1CONbits.TMR1ON = 1; //turn on timer
T1CONbits.T1CKPS1 = 0; //set prescaler
T1CONbits.T1CKPS0 = 0; //set prescaler
//setup timer2
OpenTimer2(TIMER_INT_ON);
PIR1bits.TMR2IF = 0; //clears the timer 2 interupt flag
PR2 = 20;
T2CON = 0b00000100; //(-)always 0 (----) postscale (-)on/off (--) prescale
//configure CCP1
CCP1CON = 0b0000101; //configure CCP1 for capture, rising edge
INTCONbits.PEIE=1; //enable peripheral interrupts
PIE1bits.CCP1IE=1; //enabled CCP1 interrupt
INTCONbits.GIE=1; //enable branching to interrupt
ReceiverTris = 1; //set RB3 for input so the capture can work.
TRISBbits.TRISB2 = 1; //set rb2 for in so it can be used to differentiate channels
//configure ports
ADCON1 = 0xff; //all digital
INTCON2bits.RBPU = 0; //port b weak pullups on
//configure control bits for output
TRISAbits.TRISA0 = 0;
TRISAbits.TRISA6 = 0;
//controll bits for second motor
TRISAbits.TRISA1 = 0;
TRISAbits.TRISA4 = 0;
while(1)
{
}
}
void low_ISR(void)
{
//Timer 2 flag
if(PIR1bits.TMR2IF == 1)
{
PIR1bits.TMR2IF = 0; //clears the timer 1 interupt flag
}
//ccp interrupt
if(PIR1bits.CCP1IF == 1)
{
PIR1bits.CCP1IF = 0; //clear the flag
if(PWM1Edge == 1)//if detecting rising
{
CCP1CON = 0b0000100;//switch to detect falling edge
PWM1Edge = 0;//switch to indicate falling edge is next
PWMGap = CCPR1 - PWM1FallTime; //calculate gap between pulse starts
PWM1RiseTime = CCPR1;//save the low timer value for the rise time
if(PWMGap < 10000){channel2_width = PWMGap;}
//if (PWMGap>25000){Channel_Being_Captured = 1;}
}
else //if detecting falling
{
CCP1CON = 0b0000101;//switch to detect rising edge
PWM1Edge = 1;//switch to indicate rising edge is next
PWM1Width = CCPR1 - PWM1RiseTime; //(pwm rise time is the time that the pwm rise occured)
PWM1FallTime = CCPR1;//save the low timer value for the fall time
if(PWMGap > 10000){channel1_width = PWM1Width;}
if(PWMGap < 10000){channel3_width = PWM1Width;}
}
}
}
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?