1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

New method using new data

Blog entry posted in 'Uncategorised', Jun 7, 2010.

Since my last post I have gotten a chance to use an oscilloscope on the transmitter to see what exactly it is putting out. It turns out that like most things this is not as simple as it seems. Some transmitters put out pulses with evenly spaced start times, independent of the widths of the other pulses, a common example would be one with 10 ms spacing between the start of each pulse, then a 40 ms gap between the last pulse and when the first one happens again. The receiver would use the long gap as a reference to calibrate it's self and count each pulse as the correct channel. A pic programmer wishing to read the signal with one port could do the same. The other (the kind that my traxxas reciever is) sends all the pulses stacked together, I found a novel method of reading them all. Just look at pulse 1 and 3 (mine is 3 channel and i left 2 disconnected) record each low time width and each pulse time width, then get the first channel by taking the pulse after the long gap, the second channel by taking the short gap, and the third channel is the pulse after the short gap. This works because since they are stacked, the gap between channels 1 and 3 is the width of channel 2! Here is the code:

Code (text):

//Basic configureation of chip periferials
 #pragma config OSC = INTIO2, WDT = OFF, LVP = OFF
 #include <p18f1320.h>
 #include <delays.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
    //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
    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;  


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;}

If you have a transmitter that starts them on equal intervals then a method of counting up the channel with each pulse and resetting on the long pulse would work. If you had a stacking transmitter with an even number of channels then some other clever trick would be needed, but I have no such transmitter so I can't develop such a solution. The solution that would work for all is to capture each channel on its own pin, which is a method I am exploring now.