- Blog entry posted in 'Uncategorised', June 08, 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:
//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;}
}
}
}
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.Comments