Reading RC receiver pulses (using SX/B)
I know this sounds so simple but try as I might (2 days now), I have been unable to read receiver channels. I am left feeling like the monkey at the monolith in 2001! If I could get a byte variable representing channel position 1-2ms I would be pleased as punch. Anyone know the proper pulsin parameters and maybe pin configuration to do this?
Thanks in advance,
Rocky
Thanks in advance,
Rocky
Comments
Personally, I would poll RC receiver pin(s) in an interrupt, so that the last pulsewidth is always available "in the background", but the above should work. You might want to perform so error checking on the received value in case the pulsewidth is too long or too short (which could indicate that the transmitter is not on, or there is noise, etc).
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
I really was loosing hair over this one. My son's "drive by wire" (with daddy override and ultra sonic collision prevention for and aft) electric car can now be completed.
Ty thanks you too
=========================================================================
INTERRUPT NOPRESERVE 20_000_000
' =========================================================================
inc PWM_Count
IF MotorOut(0) > PWM_Count THEN
Out1 = 1
ELSE
Out1 = 0
ENDIF
IF MotorOut(1) > PWM_Count THEN
Out2 = 1
ELSE
Out2 = 0
ENDIF
IF MotorOut(2) > PWM_Count THEN
Out3 = 1
ELSE
Out3 = 0
ENDIF
IF MotorOut(3) > PWM_Count THEN
Out4 = 1
ELSE
Out4 = 0
ENDIF
inc rcrefresh
if rcrefresh <> 1000 then
goto over2
endif
rcrefresh = 0
PULSIN Speedchan, 1, RCSpeed1
IF RCSpeed1 < 1 THEN
goto over1
endif
RCSpeed = RCSpeed1
over1:
PULSIN SteerChan, 1, RCSteer1
IF RCSteer1 < 1 THEN
goto over2
endif
RCSteer = RCSteer1
over2:
RETURNINT
[noparse][[/noparse]Edit] As an educational exercise for myself I wrote the attached program which can measure a high pulse in 10 microsecond increments using the interrupt. You'll see that it's pretty easy and with a bit of copy/paste/edit you can add more channels. Note that it takes a simple approach: you can enable pulse measurement on a channel by clearing a flag; that flag will be set when the measurement is done, and further measurements will be ignored until that flag is cleared. Due to the simplicity of the code you can actually start the measurement in middle of a pulse. To get around that you could add a line to prevent it:
Post Edited (JonnyMac) : 7/31/2008 5:45:57 PM GMT
What JonnyMac said
What I meant, was you *could* "bit-bang" the pulsin in your ISR (which seems way too fast, btw, for what you doing; hardly any time for ISR work and it'll run on every other instruction from the main program, that along w/the pulsin in the ISR and I would expect jitter -- remember that pulsin is gonna site there and *wait* for the pulse for eons -- relatively). I would check out the Nuts N Volts column JonnyMac posted for motor control -- it has ready unroll PWM outs and the ISR ready serial code if this project needs to communicate w/the outside world. My little snippet below is all SX/B, not assembly, but the PWM is similar to JonnyMac's (older) posted methods.
e.g.
This is not an ideal way to do it, but maybe it makes things clear -- the interrupt is very short, just setting the PWM pins high when the "speed" from 0-255 rolls over. On rollover the desired PWM width is reloaded into the counter(s). The Recvr counters just measure the width of the high going pulse. A weakness here is that this isr presumes the mainline will check the pulsecounters often enough that the next pulse won't have started, but again I was going for clarity.
The main line just blazes through checking for the falling edge of an RC pulse and setting the speed.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
This last code looks the part. I being both an asm AND an SX/B moron, will of course need a little time to digest it's operation but at a glance it looks pretty slick.
I will need to modify the PWM to pulse two different outputs for each of my two motors (one for each direction). Originally I was going to run 8 bit PWM in locked anti-phase by placing an inverter between the forward and reverse H-bridge inputs. This would have made a PWM output of 128 neutral, but I feared reduced battery life from current flowing at zero speed. My H bridges are in an ancient Vantec 80's vintage T03 bipolar based dual motor unit. I am using one of course to drive this little car forward and backwards and another to drive the steered wheels back and forth. I plan to close the loop on the steering gearhead with a 5K pot. (So here I go with more I need to learn) Also I am mounting a 10K joystick pot for the kid to drive with until he runs into danger where I will take control with the radio unit. I have an SRF08 I think is the model sonar I will want to at least place on the front so as to have the car stop before any collisions.
I am off to the garage as I have tie-rods to mount and a chair to craft etc...
Much thanks, with you guys "helping" (read "doing my hard work for me") I am going to be able to give little Ty a lot nicer surprise than I could do on my own.
Is 15mons too young for a 1st car?
Yes
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
He already has one of those red Vee Duhb push cars and will run and jump into it if you walk anywhere near it! And this thing with a joystick he need only push it in the direction he wants to go, I think he will love it.
Can never be too young, skinny or rich.
:P
' =========================================================================
'
' File...... Pulse_To_PWM.SXB
' Purpose...
' Author.... Jon Williams, EFX-TEK
' Copyright (c) 2008 EFX-TEK
' Some Rights Reserved
' -- see http://creativecommons.org/licenses/by/3.0/
' E-mail.... jwilliams@efx-tek.com
' Started...
' Updated...
'
'
'
' Device Settings
'
DEVICE SX28, OSCXT2, TURBO, STACKX, OPTIONX, BOR42
FREQ 20_000_000
ID "PulsePWM"
'
' I/O Pins
'
Mtr1Pwm PIN RB.0 OUTPUT ' Drive motor forward speed
Mtr2Pwm PIN RB.1 OUTPUT ' Drive motor reverse speed
Mtr3Pwm PIN RB.2 OUTPUT ' Steering motor right speed
Mtr4Pwm PIN RB.3 OUTPUT ' Steering motor left speed
Ch1In PIN RA.0 INPUT ' Drive motor RC chan
Ch2In PIN RA.1 INPUT ' Steering motor RC chan
'
' Constants
'
Yes CON 1
No CON 0
'
' Variables
'
flags VAR Byte
isrFlag VAR flags.0
ch1Active VAR flags.1 ' 1 = measuring now
ch1Ready VAR flags.2 ' 1 = measurement done
ch2Active VAR flags.3 ' 1 = measuring now
ch2Ready VAR flags.4 ' 1 = measurement done
chan1 VAR Byte ' pulse input width
chan2 VAR Byte ' pulse input width
m1Speed VAR Byte ' motor speed
m1Acc VAR Byte ' acc for PWM
m2Speed VAR Byte ' motor speed
m2Acc VAR Byte ' acc for PWM
m3Speed VAR Byte ' motor speed
m3Acc VAR Byte ' acc for PWM
m4Speed VAR Byte ' motor speed
m4Acc VAR Byte ' acc for PWM
tmpW1 VAR Word ' for subs/funcs
tmpB1 VAR Byte
watch chan1
watch chan2
watch m1speed
watch m2speed
watch m3speed
watch m4speed
' =========================================================================
INTERRUPT NOPRESERVE 100_000 ' 10 microseconds
' =========================================================================
Mark_ISR:
ASM
BANK flags
SETB isrFlag
ENDASM
' Measure high-going pulse in 10 us increments
' -- clear ch1Ready bit to start measurement
Ch1_Check:
ASM
JB ch1Ready, Ch1_Exit ' exit if already measured
JB ch1Active, Ch1_Measure ' update if active
JNB Ch1In, Ch1_Exit ' exit if no pulse
Ch1_Init:
SETB ch1Active ' we're measureing
MOV chan1, #1 ' initialize width
JMP Ch1_Exit
Ch1_Measure:
ADDB chan1, Ch1In ' update pulse timing
MOVB ch1Active, Ch1In ' update status
SB Ch1In ' exit if still measuring
SETB ch1Ready ' mark measurement ready
Ch1_Exit:
ENDASM
Ch2_Check:
ASM
JB ch2Ready, Ch2_Exit ' exit if already measured
JB ch2Active, Ch2_Measure ' update if active
JNB Ch2In, Ch2_Exit ' exit if no pulse
Ch2_Init:
SETB ch2Active ' we're measureing
MOV chan2, #1 ' initialize width
JMP Ch2_Exit
Ch2_Measure:
ADDB chan2, Ch2In ' update pulse timing
MOVB ch1Active, Ch2In ' update status
SB Ch2In ' exit if still measuring
SETB ch2Ready ' mark measurement ready
Ch2_Exit:
ENDASM
' fixed period PWM by Guenther Daubach
' -- PWM frequency is 390 Hz @ 10 uS interrupt
M1_PWM:
ASM
SETB Mtr1Pwm ' preset output
CSB m1Acc, m1Speed ' if pwm level reached
CLRB Mtr1Pwm ' clear output
INC m1Acc ' increment accumulator
MOV W, ++m1Acc ' check for max
SNZ ' end reached?
CLR m1Acc ' yes, reset
ENDASM
M2_PWM:
ASM
SETB Mtr2Pwm ' preset output
CSB m2Acc, m2Speed ' if pwm level reached
CLRB Mtr2Pwm ' clear output
INC m2Acc ' increment accumulator
MOV W, ++m2Acc ' check for max
SNZ ' end reached?
CLR m2Acc ' yes, reset
ENDASM
M3_PWM:
ASM
SETB Mtr3Pwm ' preset output
CSB m3Acc, m3Speed ' if pwm level reached
CLRB Mtr3Pwm ' clear output
INC m3Acc ' increment accumulator
MOV W, ++m3Acc ' check for max
SNZ ' end reached?
CLR m3Acc ' yes, reset
ENDASM
M4_PWM:
ASM
SETB Mtr4Pwm ' preset output
CSB m4Acc, m4Speed ' if pwm level reached
CLRB Mtr4Pwm ' clear output
INC m4Acc ' increment accumulator
MOV W, ++m4Acc ' check for max
SNZ ' end reached?
CLR m4Acc ' yes, reset
ENDASM
RETURNINT
' =========================================================================
PROGRAM Start
' =========================================================================
'
' Subroutine / Function Declarations
'
DELAY_MS SUB 1, 2 ' replaces PAUSE
SET_Drive_Motor SUB 1 ' set Drive PWM control
SET_Steering_Motor SUB 1 ' set Steering PWM control
'
' Program Code
'
Start:
PLP_A = %00000011 ' enable select pull-ups
PLP_B = %00001111
PLP_C = %00000000
Main:
\ JB Ch1In, $ ' wait until no pulse
\ CLRB ch1Ready ' allow new measurement
SET_Drive_Motor chan1 ' update motor speed/dir
\ JB Ch2In, $
\ CLRB ch2Ready ' allow new measurement
SET_Steering_Motor chan2
GOTO Main
'
' Subroutine / Function Code
'
' Use: DELAY_MS duration
' -- replaces PAUSE
' -- uses interrupt timing
SUB DELAY_MS
IF __PARAMCNT = 1 THEN ' if byte parameter
__WPARAM12_MSB = 0 ' clear MSB
ENDIF
DO WHILE __WPARAM12 > 0 ' while running
__PARAM3 = 100 ' load 1ms timer
DO WHILE __PARAM3 > 0 ' while 1ms timer running
ASM
CLRB isrFlag ' clear isr flag
JNB isrFlag, $ ' wait for next
DEC __PARAM3 ' update 1ms timer
ENDASM
LOOP
DEC __WPARAM12 ' update duration timer
LOOP
ENDSUB
'
' Use: SET_Drive_Motor
' -- speeds is 100 to 200, 150 = stopped
' -- speed < 150 = reverse
' -- has small deadband
SUB SET_Drive_Motor
tmpB1 = __PARAM1 MAX 200 ' limit range
tmpB1 = tmpB1 MIN 100
IF tmpB1 < 148 THEN ' set to reverse
m1Speed = 150 - tmpB1 ' set reverse speed
m2Speed = 0
ELSEIF tmpB1 > 152 THEN ' set to forward
m1Speed = 0
m2Speed = tmpB1 - 150 ' set forward speed
ELSE
m1Speed = 0
m2Speed = 0
ENDIF
' multiply speed by 5 to fit into byte
tmpB1 = m1Speed << 2 ' x4
m1Speed = tmpB1 + m1Speed ' +1 = x5
tmpB1 = m2Speed << 2 ' x4
m2Speed = tmpB1 + m2Speed ' +1 = x5
ENDSUB
'
' Use: SET_Steering_Motor
' -- speeds is 100 to 200, 150 = straight
' -- speed < 150 = Left
' -- has small deadband
SUB SET_Steering_Motor
tmpB1 = __PARAM1 MAX 200 ' limit range
tmpB1 = tmpB1 MIN 100
IF tmpB1 < 148 THEN ' set to reverse
m3Speed = 150 - tmpB1 ' set reverse speed
m4Speed = 0
ELSEIF tmpB1 > 152 THEN ' set to forward
m3Speed = 0
m4Speed = tmpB1 - 150 ' set forward speed
ELSE
m3Speed = 0
m4Speed = 0
ENDIF
' multiply speed by 5 to fit into byte
tmpB1 = m3Speed << 2 ' x4
m3Speed = tmpB1 + m3Speed ' +1 = x5
tmpB1 = m4Speed << 2 ' x4
m4Speed = tmpB1 + m4Speed ' +1 = x5
ENDSUB
'
' User Data
'
I don't know how to just attach a file here. This program posting sure does fill screens fast
Thanks
Rocky
You're updating the status bit from channel 1.
Another ID10T error Oh boy!
Now on to learnin how to read pots.
Oh and I2C for the sonar.