for my first post here is what I've done :
I changed the code of the Sparkfun UBW project :
I added a new function (PP) that put the ubw in PPM mode drived by simple serial command over USB.
this way I'm able to drive the servo using a joystick like PCTx do.
;)
Comments
this is also why I'll only put source code and no hex.
well, here we go :
download the UBW source code :
then open user.c and do the following modifications :
//after :
near unsigned char g_RC_timing_ptr;
//add :
near unsigned char g_RC_ptr;
near unsigned char g_RC_next_ptr2;
//after :
near unsigned char A_cur_channel;
//add :
near unsigned int P_tick_counter;
//after :
volatile unsigned int g_RC_value[kRC_DATA_SIZE]; // Stores reload values for TMR0
//add :
volatile unsigned int g_RC_Tmp; //300µs-400µs for ppm start
//after :
BOOL g_ack_enable;
//add :
BOOL g_ppm_enable;
//after :
void parse_CU_packet (void); // CU configures UBW (system wide parameters)
//add :
void parse_PP_packet (void); // PP Send RC throught PPM
//in void low_ISR(void) replace :
if (kWAITING == g_RC_state[g_RC_next_ptr])
{
// If the value is zero, then shut this pin off
// otherwise, prime it for sending a pulse
if (0 == g_RC_value[g_RC_next_ptr])
{
g_RC_state[g_RC_next_ptr] = kOFF;
}
else
{
// Set the bit high
if (g_RC_next_ptr < 8)
{
bitset (LATA, g_RC_next_ptr & 0x7);
}
else if (g_RC_next_ptr < 16)
{
bitset (LATB, g_RC_next_ptr & 0x7);
}
else
{
bitset (LATC, g_RC_next_ptr & 0x7);
}
// Set the state to primed so we know to do next
g_RC_state[g_RC_next_ptr] = kPRIMED;
// And remember which pin is primed
g_RC_primed_ptr = g_RC_next_ptr;
}
}
// And always advance the main pointer
// NOTE: we need to skip RA6, RA7, and RC3, RC4, and RC5
// (Because UBW doesn't bring those pins out to headers)
g_RC_next_ptr++;
if (6 == g_RC_next_ptr)
{
g_RC_next_ptr = 8;
}
else if (19 == g_RC_next_ptr)
{
g_RC_next_ptr = 22;
}
else if (kRC_DATA_SIZE == g_RC_next_ptr)
{
g_RC_next_ptr = 0;
}
if (kPRIMED == g_RC_state[g_RC_primed_ptr])
{
// This is easy, throw the value into the timer
TMR0H = g_RC_value[g_RC_primed_ptr] >> 8;
TMR0L = g_RC_value[g_RC_primed_ptr] & 0xFF;
// Then make sure the timer's interrupt enable is set
INTCONbits.TMR0IE = 1;
// And be sure to clear the flag too
INTCONbits.TMR0IF = 0;
// Turn on Timer0
T0CONbits.TMR0ON = 1;
// And set this pin's state to timing
g_RC_state[g_RC_primed_ptr] = kTIMING;
// Remember which pin is now timing
g_RC_timing_ptr = g_RC_primed_ptr;
}
//by :
if(g_ppm_enable)
{
if(P_tick_counter==22)
{
g_RC_next_ptr2=0;
if (kWAITING == g_RC_state[g_RC_next_ptr2])
{
// If the value is zero, then shut this pin off
// otherwise, prime it for sending a pulse
// Set the bit high
if (g_RC_ptr < 8)
{
bitclr (LATA, g_RC_ptr & 0x7);
}
else if (g_RC_ptr < 16)
{
bitclr (LATB, g_RC_ptr & 0x7);
}
else
{
bitclr (LATC, g_RC_ptr & 0x7);
}
// Set the state to primed so we know to do next
g_RC_state[g_RC_next_ptr2] = kPRIMED;
// And remember which pin is primed
//g_RC_primed_ptr = g_RC_next_ptr2;
}
// And always advance the main pointer
// NOTE: we need to skip RA6, RA7, and RC3, RC4, and RC5
// (Because UBW doesn't bring those pins out to headers)
//g_RC_next_ptr2++;
/*if (9 == g_RC_next_ptr2)
{
g_RC_next_ptr2 = 0;
}*/
//if (kPRIMED == g_RC_state[g_RC_primed_ptr])
//{
// This is easy, throw the value into the timer
TMR0H = g_RC_Tmp >> 8;
TMR0L = g_RC_Tmp & 0xFF;
// Then make sure the timer's interrupt enable is set
INTCONbits.TMR0IE = 1;
// And be sure to clear the flag too
INTCONbits.TMR0IF = 0;
// Turn on Timer0
T0CONbits.TMR0ON = 1;
// And set this pin's state to timing
//g_RC_state[g_RC_primed_ptr] = kTIMING;
// Remember which pin is now timing
//g_RC_timing_ptr = g_RC_primed_ptr;
//}
P_tick_counter=0;
}
else
{
P_tick_counter++;
}
}
else
{
if (kWAITING == g_RC_state[g_RC_next_ptr])
{
// If the value is zero, then shut this pin off
// otherwise, prime it for sending a pulse
if (0 == g_RC_value[g_RC_next_ptr])
{
g_RC_state[g_RC_next_ptr] = kOFF;
}
else
{
// Set the bit high
if (g_RC_next_ptr < 8)
{
bitset (LATA, g_RC_next_ptr & 0x7);
}
else if (g_RC_next_ptr < 16)
{
bitset (LATB, g_RC_next_ptr & 0x7);
}
else
{
bitset (LATC, g_RC_next_ptr & 0x7);
}
// Set the state to primed so we know to do next
g_RC_state[g_RC_next_ptr] = kPRIMED;
// And remember which pin is primed
g_RC_primed_ptr = g_RC_next_ptr;
}
}
// And always advance the main pointer
// NOTE: we need to skip RA6, RA7, and RC3, RC4, and RC5
// (Because UBW doesn't bring those pins out to headers)
g_RC_next_ptr++;
if (6 == g_RC_next_ptr)
{
g_RC_next_ptr = 8;
}
else if (19 == g_RC_next_ptr)
{
g_RC_next_ptr = 22;
}
else if (kRC_DATA_SIZE == g_RC_next_ptr)
{
g_RC_next_ptr = 0;
}
if (kPRIMED == g_RC_state[g_RC_primed_ptr])
{
// This is easy, throw the value into the timer
TMR0H = g_RC_value[g_RC_primed_ptr] >> 8;
TMR0L = g_RC_value[g_RC_primed_ptr] & 0xFF;
// Then make sure the timer's interrupt enable is set
INTCONbits.TMR0IE = 1;
// And be sure to clear the flag too
INTCONbits.TMR0IF = 0;
// Turn on Timer0
T0CONbits.TMR0ON = 1;
// And set this pin's state to timing
g_RC_state[g_RC_primed_ptr] = kTIMING;
// Remember which pin is now timing
g_RC_timing_ptr = g_RC_primed_ptr;
}
}
//and replace :
if (INTCONbits.TMR0IF)
{
// Turn off Timer0
T0CONbits.TMR0ON = 0;
// Clear the interrupt
INTCONbits.TMR0IF = 0;
// And disable it
INTCONbits.TMR0IE = 0;
if (kTIMING == g_RC_state[g_RC_timing_ptr])
{
// All we need to do is clear the pin and change its state to kWAITING
if (g_RC_timing_ptr < 8)
{
bitclr (LATA, g_RC_timing_ptr & 0x7);
}
else if (g_RC_timing_ptr < 16)
{
bitclr (LATB, g_RC_timing_ptr & 0x7);
}
else
{
bitclr (LATC, g_RC_timing_ptr & 0x7);
}
g_RC_state[g_RC_timing_ptr] = kWAITING;
}
}
//by :
if (INTCONbits.TMR0IF)
{
// Turn off Timer0
T0CONbits.TMR0ON = 0;
// Clear the interrupt
INTCONbits.TMR0IF = 0;
// And disable it
INTCONbits.TMR0IE = 0;
// Only do our stuff if the pin is in the proper state
if(g_ppm_enable)
{
if(g_RC_state[g_RC_next_ptr2] == kTIMING)
{
g_RC_state[g_RC_next_ptr2] = kWAITING;
if(g_RC_next_ptr2==6)
{
g_RC_next_ptr2=0;
}
else
{
g_RC_next_ptr2++;
g_RC_state[g_RC_next_ptr2] = kPRIMED;
// Set the bit high
if (g_RC_ptr < 8)
{
bitclr (LATA, g_RC_ptr & 0x7);
}
else if (g_RC_ptr < 16)
{
bitclr (LATB, g_RC_ptr & 0x7);
}
else
{
bitclr (LATC, g_RC_ptr & 0x7);
}
TMR0H = g_RC_Tmp >> 8;
TMR0L = g_RC_Tmp & 0xFF;
// Then make sure the timer's interrupt enable is set
INTCONbits.TMR0IE = 1;
// And be sure to clear the flag too
INTCONbits.TMR0IF = 0;
// Turn on Timer0
T0CONbits.TMR0ON = 1;
}
}
else if (g_RC_state[g_RC_next_ptr2] == kPRIMED )//after 300µS
{
// All we need to do is clear the pin and change its state to kWAITING
if (g_RC_ptr < 8)
{
bitset (LATA, g_RC_ptr & 0x7);
}
else if (g_RC_ptr < 16)
{
bitset (LATB, g_RC_ptr & 0x7);
}
else
{
bitset (LATC, g_RC_ptr & 0x7);
}
g_RC_state[g_RC_next_ptr2] = kTIMING;
TMR0H = g_RC_value[g_RC_next_ptr2] >> 8;
TMR0L = g_RC_value[g_RC_next_ptr2] & 0xFF;
// Then make sure the timer's interrupt enable is set
INTCONbits.TMR0IE = 1;
// And be sure to clear the flag too
INTCONbits.TMR0IF = 0;
// Turn on Timer0
T0CONbits.TMR0ON = 1;
}
}
else
{
if (kTIMING == g_RC_state[g_RC_timing_ptr])
{
// All we need to do is clear the pin and change its state to kWAITING
if (g_RC_timing_ptr < 8)
{
bitclr (LATA, g_RC_timing_ptr & 0x7);
}
else if (g_RC_timing_ptr < 16)
{
bitclr (LATB, g_RC_timing_ptr & 0x7);
}
else
{
bitclr (LATC, g_RC_timing_ptr & 0x7);
}
g_RC_state[g_RC_timing_ptr] = kWAITING;
}
}
}
//in void UserInit(void) after :
g_ack_enable = TRUE;
//add :
g_ppm_enable = FALSE;
P_tick_counter = 0;
g_RC_next_ptr2 = 0;
g_RC_Tmp=60779;//300µS 65535-3567
//in void parse_packet(void) after :
case ('C' * 256) + 'U':
{
// For configuring UBW
parse_CU_packet ();
break;
}
//add :
case ('P' * 256) + 'P':
{
// PP send rc ppm
parse_PP_packet ();
break;
}
//after :
parse_CU_packet(){}
//add :
//Send 9 channel througt ppm
// PP,B,1,500,500,500,500,500,500,500,500,500\r\n
void parse_PP_packet (void)
{
unsigned char port;
unsigned char pin;
unsigned int value;
unsigned int i;
port = extract_number (kUCASE_ASCII_CHAR);
pin = extract_number (kUCHAR);
g_ppm_enable=TRUE;
if (pin > 7)
{
bitset (error_byte, kERROR_BYTE_PARAMATER_OUTSIDE_LIMIT);
return;
}
if ('A' == port)
{
port = 0;
}
else if ('B' == port)
{
port = 8;
}
else if ('C' == port)
{
port = 16;
}
else
{
bitset (error_byte, kERROR_BYTE_PARAMATER_OUTSIDE_LIMIT);
return;
}
g_RC_ptr=pin + port;
for(i=0;i<9;i++)
{
value = extract_number (kUINT);
// Bail if we got a conversion error
if (error_byte)
{
return;
}
// Max value user can input. (min is zero)
if (value > 29725)//2.5ms
{
bitset (error_byte, kERROR_BYTE_PARAMATER_OUTSIDE_LIMIT);
return;
}
if(value < 5945)//0.5ms
{
bitset (error_byte, kERROR_BYTE_PARAMATER_OUTSIDE_LIMIT);
return;
}
// Now get Value in the form that TMR0 needs it
// TMR0 needs to get filled with values from 65490 (1ms) to 53600 (2ms)//5945=0.5ms
value=65535-(value-(65535-g_RC_Tmp));
// Store the new RC time value
g_RC_value[i] = value;
// Only set this state if we are off - if we are already running on
// this pin, then the new value will be picked up next time around (19ms)
if (kOFF == g_RC_state[i])
{
g_RC_state[i] = kWAITING;
}
}
print_ack ();
}
then compile and upload your file in the ubw.
;)
Just been working all night, brain befuddled....i forget that things get lost in translation..
keep up the passion...erm...work...
Mike. :~)
it was a joke, dont take it personally, just my dry english humour (i forget that irony is wasted most of the time)
More importantly, what you are doing is very good, and yes know the PCTx system, and figured that if somone has found a work-around, then MANY here are interested for sure.
I for one, want to get away from the Tx system, so ...
Please inform us of what your Open Source Hack is capable of, and the code so we can try this also.
The effort you put in here, comes back to you with the support of summet like 10k members (last time i looked (Moderator)) taking everything to the next level, and the next etc...
There are some very clever sauseges in this community!
Mike,
well it'll work for you, same as my spektrum signal.
I'm sure there'll be lot of people following, in one hand you have a PCTx at 50$ on the other an 25$ interface that'll do the same... and even more.
You going to share your toys with the rest of the children? :~)
Mike.
Gampad -> PC/laptop ->Tx
Open source all the way!
Mike,.