# PIC16F84A RC Skid Steer Mixer

Status
Not open for further replies.

#### niak32

##### New Member
Old PIC, simple PIC and I'm learning so im still on the most basic one that i could find documentation for.

What I am trying to do is measure and mix the signals from a 2 channel RC unit receiver to operate a skid steer (tank) with the one stick. Like a wheel chair but with analogue control, or at least kind of.

For a "go or no" set up, i think its easy, if both channels are maxed that means that its full throttle in one direction, ie forward left or back right depending on how its set up. if the first is maxed and the second is in the middle position its full forward.

What I would like to do is to add speed control to the equation but im stumped how i am going to do that unless I add another channel and use my pic output speed control with the timer perhaps (meh)

Since my code got stuffed, I reverted back to an older code which measures the output of 2 channel RC unit and uses the LEDS to display the result from each channel on its side of the pic in binary.

Can someone suggest where i can go next with my code to make this work please?

EDIT: Wow this is old code, I won't be using the channel error checking as im using a 2.4ghz digital reciever which "should" be better with noise.
err quick run down on the code.

Check if pin0 is high on portA, when it is high, count to 1ms then start incrementing a counter till the pin goes low or the max is reached,
repeat for pin1 then apply the outputs. output should be 1 to 255 if memory serves, doesn't need to be any where near that fine tuned.

Code:
;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
;written by: D.J.K                  /
;date:  01/06/09                    \
;version:  1.						/
;file saved as: ESC01.asm		    \
;for PIC: P16F84A                   /
;clock frequency:5mhZ  				\
;XT:  20mhz HS                      /
;                                   \
;\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
;PROGRAM NOTES : mesure two chanel from RC reciever and display
;pulse width as leds on portB

list	P=16F84A
include	"p16f84a.inc"
;=============
;Declarations:
__config _HS_OSC & _WDT_OFF & _PWRTE_ON

cblock 0Ch
CH1V
WST0
WST1
WST2
WST3
CH1T1
CH1T2
CH1T3
CH1T4
CHSELECT
CH1T21
CH1T22

CH2V
CH2T1
CH2T2
CH2T3
CH2T4
CH2T21
CH2T22
endc

org	000h
goto	Start
;	org	004h
;	goto	Inturupt
org	100h

;==============
;Program start
Start:
goto	Init

Init:
clrf	PORTA		;resets input/output ports
clrf	PORTB
bsf		STATUS,RP0 	;select bank 1
movlw	b'00000011'	;pin 0 as input
movwf	TRISA		;
movlw	b'00000000'	;all port B as Outputs
movwf	TRISB
movlw	b'00000000'	;no prescaling
movwf	OPTION_REG	;
bcf		STATUS,RP0	;selects bank 0
movlw	b'00000000'	;no interupts
movwf	INTCON
clrf	WST0
clrf	WST1
clrf	WST2

Main:
;	btfss	CHSELECT,0
goto	CH1Start
;	goto	CH2Start

CH1Start:
bsf		CHSELECT,0
btfss	PORTA,0		;wait for pulse to start
goto	CH1Start	;loop till pin is high
call	Waste1ms	;Wait nearly 1ms
clrf	CH1V
goto	CH1			;count after 1ms
CH1:
;	movlw	b'01111110'
;	movwf	CH1V
btfss	PORTA,0		;is the pin still high?
goto	CH2Start	;no, output the number to leds
call	Waste		;wait nearly 1/128th of signal range
incfsz	CH1V,f		;yes, increase the count
goto	CH1
decf	CH1V,f
goto	CH1

CH2Start:
bcf		CHSELECT,0
btfss	PORTA,1		;wait for pulse to start
goto	CH2Start 	;loop till pin is high
call	Waste1ms2	;Wait nearly 1ms
clrf	CH2V
goto	CH2			;count after 1ms
CH2:
;	movlw	b'10000000'
;	movwf	CH2V

btfss	PORTA,1		;is the pin still high?
goto	CH1set		;no, Output the number to leds
call	Waste5		;wait nearly 1/128th of signal range
incfsz	CH2V,f		;yes, increase the count
goto	CH2
decf	CH2V,f
goto	CH2

CH1set:
;	movlw	B'00110011'
;	movwf	CH1V

movf	CH1T3,W		;keep the last 4 signals in banks
movwf	CH1T4		;take the first 2 numbers from each other
movwf	CH1T22		;then take the results from each other
movf	CH1T2,W		;if there is nothing left for both equations
movwf	CH1T3		;then put the consifmed signal to PORTB
movf	CH1T1,W
movwf	CH1T2
movwf	CH1T21
movf	CH1V,W
movwf	CH1T1

movf	CH1T1,w
subwf	CH1T22,f
btfss	STATUS,Z
goto	CH2Set
movf	CH1T3,w
subwf	CH1T21,f
btfss	STATUS,Z
goto	CH2Set
movf	CH1T21,w
btfss	STATUS,Z	;check if remainder is zero
goto	CH2Set		;if last 4 signals are not the same, look for a new signal
goto	Output1
movf	CH1V,w		;move variable to working
movwf	PORTB		;output number to leds PORTB = binary display
goto	CH2Set

Waste:
movlw	d'3'		;rest time between incrementing signal
movwf	WST0		;variable, 10 leaves with range of 199 to 128
Waste2:					;with RC unit tested
decfsz	WST0,f		;4 with 6 gives 17 to 250
goto	Waste2
Return

Waste1ms:
movlw	d'6'		;rest time before counting signal
movwf	WST2
Waste1:
decfsz	WST1,f
goto	Waste1
decfsz	WST2,f
goto	Waste1
Return

Output1:
btfsc	CH1V,7
goto	Ovr128
btfsc	CH1V,6
goto	Ovr64
btfsc	CH1V,5
goto	Ovr32
btfsc	CH1V,4
goto	Out16
goto	Out0

Ovr32
btfsc	CH1V,4
goto	Out48	;+16?
goto	Out32	;then start number
Ovr64
btfsc	CH1V,5	;+32?
goto	Ovr96
btfsc	CH1V,4	;+16?
goto	Out80
goto	Out64	;then start number

Ovr96
btfsc	CH1V,4	;+16?
goto	Out112
goto	Out96	;then start number
Ovr128
btfsc	CH1V,6	;+64?
goto	Ovr192
btfsc	CH1V,5	;+32?
goto	Ovr160
btfsc	CH1V,4	;+16?
goto	Out144
goto	Out128	;then start number

Ovr160
btfsc	CH1V,4	;+16?
goto	Out176
goto	Out160		;then start number
Ovr192
btfsc	CH1V,5	;+32?
goto	Ovr224
btfsc	CH1V,4	;+16?
goto	Out208
goto	Out192	;then start number
Ovr224
btfsc	CH1V,4
goto	Out240	;+16?
goto	Out224	;then start number

Out0
bcf		PORTB,0
bcf		PORTB,1
bcf		PORTB,2
bcf		PORTB,3
;	movlw	b'00000000'
;	movwf	PORTB
goto	CH2Set
Out16
bsf		PORTB,1
bcf		PORTB,1
bcf		PORTB,2
bcf		PORTB,3
;	movlw	b'00000001'
;	movwf	PORTB
goto	CH2Set
Out32
bcf		PORTB,0
bsf		PORTB,1
bcf		PORTB,2
bcf		PORTB,3
;	movlw	b'00000010'
;	movwf	PORTB
goto	CH2Set
Out48
bsf		PORTB,0
bsf		PORTB,1
bcf		PORTB,2
bcf		PORTB,3
;	movlw	b'00000011'
;	movwf	PORTB
goto	CH2Set
Out64
bcf		PORTB,0
bcf		PORTB,1
bsf		PORTB,2
bcf		PORTB,3
;	movlw	b'00000100'
;	movwf	PORTB
goto	CH2Set
Out80
bsf		PORTB,0
bcf		PORTB,1
bsf		PORTB,2
bcf		PORTB,3
;	movlw	b'00000101'
;	movwf	PORTB
goto	CH2Set
Out96
bcf		PORTB,0
bsf		PORTB,1
bsf		PORTB,2
bcf		PORTB,3
;	movlw	b'00000110'
;	movwf	PORTB
goto	CH2Set
Out112
bsf		PORTB,0
bsf		PORTB,1
bsf		PORTB,2
bcf		PORTB,3
;	movlw	b'00000111'
;	movwf	PORTB
goto	CH2Set
Out128
bcf		PORTB,0
bcf		PORTB,1
bcf		PORTB,2
bsf		PORTB,3
;	movlw	b'00001000'
;	movwf	PORTB
goto	CH2Set
Out144
bsf		PORTB,0
bcf		PORTB,1
bcf		PORTB,2
bsf		PORTB,3
;	movlw	b'00001001'
;	movwf	PORTB
goto	CH2Set
Out160
bcf		PORTB,0
bsf		PORTB,1
bcf		PORTB,2
bsf		PORTB,3
;	movlw	b'00001010'
;	movwf	PORTB
goto	CH2Set
Out176
bsf		PORTB,0
bsf		PORTB,1
bcf		PORTB,2
bsf		PORTB,3
;	movlw	b'00001011'
;	movwf	PORTB
goto	CH2Set
Out192
bcf		PORTB,0
bcf		PORTB,1
bsf		PORTB,2
bsf		PORTB,3
;	movlw	b'00001100'
;	movwf	PORTB
goto	CH2Set
Out208
bsf		PORTB,0
bcf		PORTB,1
bsf		PORTB,2
bsf		PORTB,3
;	movlw	b'00001101'
;	movwf	PORTB
goto	CH2Set
Out224
bcf		PORTB,0
bsf		PORTB,1
bsf		PORTB,2
bsf		PORTB,3
;	movlw	b'00001110'
;	movwf	PORTB
goto	CH2Set
Out240
bsf		PORTB,0
bsf		PORTB,1
bsf		PORTB,2
bsf		PORTB,3
;	movlw	b'00001111'
;	movwf	PORTB
goto	CH2Set

CH2Set:
;	movlw	B'00110011'
;	movwf	CH2V

movf	CH2T3,W		;keep the last 4 signals in banks
movwf	CH2T4		;take the first 2 numbers from each other
movwf	CH2T22		;then take the results from each other
movf	CH2T2,W		;if there is nothing left for both equations
movwf	CH2T3		;then put the consifmed signal to PORTB
movf	CH2T1,W
movwf	CH2T2
movwf	CH2T21
movf	CH2V,W
movwf	CH2T1

movf	CH2T1,w
subwf	CH2T22,f
btfss	STATUS,Z
goto	Main
movf	CH2T3,w
subwf	CH2T21,f
btfss	STATUS,Z
goto	Main
movf	CH2T21,w
btfss	STATUS,Z	;check if remainder is zero
goto	Main		;if last 4 signals are not the same, look for a new signal
goto	Output2
movf	CH2V,w		;move variable to working
movwf	PORTB		;Output number to leds PORTB = binary display
goto	Main

Waste5:
movlw	d'3'		;rest time between incrementing signal
movwf	WST0		;variable, 10 leaves with range of 199 to 128
Waste4:					;with RC unit tested
decfsz	WST0,f		;4 with 6 gives 17 to 250
goto	Waste4
Return

Waste1ms2:
movlw	d'6'		;rest time before counting signal
movwf	WST2
Waste3:
decfsz	WST1,f
goto	Waste1
decfsz	WST2,f
goto	Waste3
Return

Output2:
btfsc	CH2V,7
goto	Ovr2128
btfsc	CH2V,6
goto	Ovr264
btfsc	CH2V,5
goto	Ovr232
btfsc	CH2V,4
goto	Out216
goto	Out20

Ovr232
btfsc	CH2V,4
goto	Out248	;+16?
goto	Out232	;then start number
Ovr264
btfsc	CH2V,5	;+32?
goto	Ovr296
btfsc	CH2V,4	;+16?
goto	Out280
goto	Out264	;then start number

Ovr296
btfsc	CH2V,4	;+16?
goto	Out2112
goto	Out296	;then start number
Ovr2128
btfsc	CH2V,6	;+64?
goto	Ovr2192
btfsc	CH2V,5	;+32?
goto	Ovr2160
btfsc	CH2V,4	;+16?
goto	Out2144
goto	Out2128	;then start number

Ovr2160
btfsc	CH2V,4	;+16?
goto	Out2176
goto	Out2160		;then start number
Ovr2192
btfsc	CH2V,5	;+32?
goto	Ovr2224
btfsc	CH2V,4	;+16?
goto	Out2208
goto	Out2192	;then start number
Ovr2224
btfsc	CH2V,4
goto	Out2240	;+16?
goto	Out2224	;then start number

Out20
bcf		PORTB,7
bcf		PORTB,6
bcf		PORTB,5
bcf		PORTB,4
;	movlw	b'00000000'
;	movwf	PORTB
goto	Main
Out216
bsf		PORTB,7
bcf		PORTB,7
bcf		PORTB,6
bcf		PORTB,5
;	movlw	b'10000000'
;	movwf	PORTB
goto	Main
Out232
bcf		PORTB,7
bsf		PORTB,6
bcf		PORTB,5
bcf		PORTB,4
;	movlw	b'01000000'
;	movwf	PORTB
goto	Main
Out248
bsf		PORTB,7
bsf		PORTB,6
bcf		PORTB,5
bcf		PORTB,4
;	movlw	b'11000000'
;	movwf	PORTB
goto	Main
Out264
bcf		PORTB,7
bcf		PORTB,6
bsf		PORTB,5
bcf		PORTB,4
;	movlw	b'00100000'
;	movwf	PORTB
goto	Main
Out280
bsf		PORTB,7
bcf		PORTB,6
bsf		PORTB,5
bcf		PORTB,4
;	movlw	b'10100000'
;	movwf	PORTB
goto	Main
Out296
bcf		PORTB,7
bsf		PORTB,6
bsf		PORTB,5
bcf		PORTB,4
;	movlw	b'01100000'
;	movwf	PORTB
goto	Main
Out2112
bsf		PORTB,7
bsf		PORTB,6
bsf		PORTB,5
bcf		PORTB,4
;	movlw	b'11100000'
;	movwf	PORTB
goto	Main
Out2128
bcf		PORTB,7
bcf		PORTB,6
bcf		PORTB,5
bsf		PORTB,4
;	movlw	b'00010000'
;	movwf	PORTB
goto	Main
Out2144
bsf		PORTB,7
bcf		PORTB,6
bcf		PORTB,5
bsf		PORTB,4
;	movlw	b'10010000'
;	movwf	PORTB
goto	Main
Out2160
bcf		PORTB,7
bsf		PORTB,6
bcf		PORTB,5
bsf		PORTB,4
;	movlw	b'01010000'
;	movwf	PORTB
goto	Main
Out2176
bsf		PORTB,7
bsf		PORTB,6
bcf		PORTB,5
bsf		PORTB,4
;	movlw	b'11010000'
;	movwf	PORTB
goto	Main
Out2192
bcf		PORTB,7
bcf		PORTB,6
bsf		PORTB,5
bsf		PORTB,4
;	movlw	b'00110000'
;	movwf	PORTB
goto	Main
Out2208
bsf		PORTB,7
bcf		PORTB,6
bsf		PORTB,5
bsf		PORTB,4
;	movlw	b'10110000'
;	movwf	PORTB
goto	Main
Out2224
bcf		PORTB,7
bsf		PORTB,6
bsf		PORTB,5
bsf		PORTB,4
;	movlw	b'01110000'
;	movwf	PORTB
goto	Main
Out2240
bsf		PORTB,7
bsf		PORTB,6
bsf		PORTB,5
bsf		PORTB,4
;	movlw	b'11110000'
;	movwf	PORTB
goto	Main
END

Last edited:

#### Nigel Goodwin

##### Super Moderator
Dump the antique obselete 84, and choose a PIC with two hardware PWM channels, the 16F876 is one such choice.

This makes speed control absolutely trivial to do, and there's an example (for skid steering) in my tutorials.

#### niak32

##### New Member
Dump the antique obselete 84, and choose a PIC with two hardware PWM channels, the 16F876 is one such choice.

This makes speed control absolutely trivial to do, and there's an example (for skid steering) in my tutorials.
Thanks Nigel.
I was about to object and say how much i love using the 84 but i actually have a 16F877 handy so that's no issue.

Looking over your code for the skid steer, by the looks of it your tank dances in the main loop? If that's right, I think i do understand how most of it works.

Am I also right (I don't think i saw it anywhere) but you are using the PWM channels as the power switch for your H-Bridges? Can't see anything really descriptive for the PWM so I'm assuming that its that simple.

Looks like that will solve my speed control problem if it's like i think it is.

One down, one to go

Please comment if you have any ideas about mixing the 2 channels.

#### Nigel Goodwin

##### Super Moderator
The 'tutorial' is just a demonstration of how to do two channel PWM for a small robot - as I got tired of people repeatedly asking how to do it.

It gives 127 speeds in each direction, with the eighth bit signifying the direction - and each PWM channel also has two output pins for selecting the motor direction, controlled from the eighth bit. By providing two pins, it covers all types of H-bridge.

I did recently post example code here somewhere for exactly what you wanted, running on a 16F876, but written using my own unreleased BASIC compiler.

#### niak32

##### New Member
Finally got time to build a test board using a simple program to test PORTB inputs 4-7 and display as LEDS on PORTB 0-3.

I had no trouble emulating in MPLAB but when i used the pic nothing happened till I used Nigels config

Code:
;original config line from PIC16F84A didn't work
;	__config _HS_OSC & _WDT_OFF & _PWRTE_OFF

;copied config code that did work
__CONFIG    0x393A
I couldn't find anything in the datasheet for the pic and limited information in the help file. Can someone suggest where is the best reading for understanding the config please?

#### 3v0

##### Coop Build Coordinator
Forum Supporter
The processor datasheet should have config information. It may be scattered to some degree. For example the config info about the oscillator will be in the oscillator section.

I expect the bit definition for the _HS_OSC and such are found int the processor include file.

#### Nigel Goodwin

##### Super Moderator
I expect the bit definition for the _HS_OSC and such are found in the processor include file.
You would be perfectly correct, and it's that description which provides the numerical value that the assembler replaces the label with.

I would suggest checking the include file, rather than the datasheet - the datasheet may mention it, but it may not, it may also have been changed in a later include file (particularly for an antique like the 84).

#### niak32

##### New Member
I will try to do as much of the settings in binary as its easier for me to see (If I can use a 13 digit binary number opposed to a hex)

Code:
    __CONFIG    0x393A ; = 11100100111010
;bit 13 - 1 = code protection off
;bit 12 - 1 =unimplemented
;bit 11 - 1 = circuit debug disabled
;bit 9 - 10 - 00 = Wite protection on for 0000h to 0FFFh
;bit 8 - 1 = Data EEPROM code protection off
;bit 7	- 0 = low voltage programing disabled
;bit 6	- 0 = brown out reset disbled
;bit 4 & 5 - 11 = unimplemented default
;bit 3	- 1 = Power up timer diabled
;bit 2	- 0 = Watch dog timer disabled
;bit 0 & 1 - 10 = HS Oscillator
Not really sure why I am posting this but if anyone else wanted to know, here is what I figured out, Still trying to figure out the PWM register to make a pulse. Nigel, your tutorial shows exactly how to do it. I only really understand binary as i can count along and see the switch's set for each register in each part so I'm trying to convert all the hex to binary and understand each part before I move onto the next bit.

#### Nigel Goodwin

##### Super Moderator
Not really sure why I am posting this but if anyone else wanted to know, here is what I figured out, Still trying to figure out the PWM register to make a pulse. Nigel, your tutorial shows exactly how to do it. I only really understand binary as i can count along and see the switch's set for each register in each part so I'm trying to convert all the hex to binary and understand each part before I move onto the next bit.
The whole point of hex is that it's very easy to understand and simple to convert to and from binary just 'in your head' - spilt hex numbers into individual characters, each one is 4 bits - easy to visualise as binary.

#### niak32

##### New Member
Back to it.

I've had a lot of fun with playing with PWM. I am stuck though with my coding.

More though, I'm stuck with the general idea, not really the coding.
For the PWM in Nigel's tutorial, I look at the example code at the start listed below and I am trying to figure out how to get my numbers in there.

Code:
MainLoop:
MOVLW	d'64'
CALL	SpeedL		;both half speed forwards
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'64'
CALL	SpeedL		;left half speed forwards
MOVLW	d'192'
CALL	SpeedR		;right half speed reverse
CALL	Long_Delay

MOVLW	d'10'
CALL	SpeedL		;slow speed forwards
MOVLW	d'228'
CALL	SpeedR		;fast speed reverse
CALL	Long_Delay

MOVLW	d'228'
CALL	SpeedL		;fast speed reverse
MOVLW	d'10'
CALL	SpeedR		;slow speed forwards
CALL	Long_Delay

GOTO	MainLoop
I changed this routine to start at d'10', wait a second and then increment the counter, 20, 30 etc till 255 and left it loop at 255 as show below

Code:
	MOVLW	d'10'
CALL	SpeedL		;just on,
CALL	SpeedR		;
CALL	Long_Delay

MOVLW	d'20'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'30'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'40'
CALL	SpeedL		;getting bigger
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'50'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'60'
CALL	SpeedL		;halfish
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'70'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'80'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'90'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'100'
CALL	SpeedL		;nearly there
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'110'
CALL	SpeedL		;
CALL	SpeedR		;
CALL	Long_Delay

MOVLW	d'120'
CALL	SpeedL		;nearly maxed out
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'130'
CALL	SpeedL		;hardly on
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'140'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'150'
CALL	SpeedL		;starting to go back up more
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'160'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'170'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'180'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'190'
CALL	SpeedL		;about half way i think
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'200'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'210'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'220'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'230'
CALL	SpeedL		;nearly full
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'240'
CALL	SpeedL		;
CALL	SpeedR
CALL	Long_Delay

MOVLW	d'250'
CALL	SpeedL		;Maxed out
CALL	SpeedR
CALL	Long_Delay
ending:

MOVLW	d'255'
CALL	SpeedL		;stay maxed out
CALL	SpeedR
CALL	Long_Delay

GOTO	ending
When it hit 120, the output was nearly 100% duty cycle? and reset when it got to 130 down to about 5% duty cycle (hope that is the right word).
after 130 it went up again till it looped at 255 which maxed the output at 100%.

I have my pic test a pin and report from 0 to 252 (as i remove the lower 2 bits so its never maxed out and can reach 0 instead of 1 with some room to spare).

When I apply this, I get the same result as above, the PWM max's out twice.

What I would like to be able to do is have the PWM duty cycle at 0% when I get 126 +- 2 or a little more and nearly maxed at 252 and 0.

I "Thought" I could achieve this by having my test routine counting up and also counting another register down at the same time, then using the most significant bit to determine which number should be used, but that ended up being what i had really.

in a nut shell what i am trying to do is make the following numbers the speeds,
126 to 130 is stop,
0 and 252 is max speed
64 and 96 or so is half speed

Can't seem to figure this one out, any help would be appreciated.

Last edited:

#### niak32

##### New Member
Happy man !! Unless I get in trouble for double posting

Figured out how to do this and I was on the right track, posting code below. Using a PIC16F877A as suggested by Nigel

Code:
MainLoop:

call	CH1Start
call	CH1
;	call	CH2Start
call	CH2
call 	Output1
;	call	Output2
GOTO	MainLoop

CH1Start:
btfss	PORTB,7		;wait for pulse to start
goto	CH1Start	;loop till pin is high
call	Waste1ms	;Wait nearly 1ms
clrf	CH1V		;resets counter to count up
clrf	CH1V1		;resets counter to count down
decf	CH1V1,f
return				;count after 1ms

CH1:

btfss	PORTB,7		;is the pin still high?
return				;no, go back to main
call	Waste128	;yes, waste some time and
incfsz	CH1V,f		;increase the count, skip if max (0 again)
goto	CH1inc		;sub routine to inc count and dec counter count
decf	CH1V,f		;dec count if max, keep at max
return

CH1inc:
decf	CH1V1,f		;dec CH1 down count
goto	CH1

Output1
;movf	CH1V,w
btfss	CH1V,7
goto	Output1up
goto	Output1dn
Output1up
movf	CH1V1,w
goto	SpeedL

Output1dn
movf	CH1V,w
goto	SpeedL

Waste128:
movlw	d'1'		;rest time between incrementing signal
movwf	WST0		;variable, 10 leaves with range of 199 to 128
Waste2:					;with RC unit tested
decfsz	WST0,f		;4 with 6 gives 17 to 250
goto	Waste2
Return

Waste1ms:
movlw	d'7'		;rest time before counting signal
movwf	WST2
Waste1:
decfsz	WST1,f
goto	Waste1
decfsz	WST2,f
goto	Waste1
Return

SpeedL:				;use value in W to set speed (0-127)

MOVWF	temp
bcf		temp,0
bcf		temp,1
bcf		temp,2
BTFSC	temp, 7		;if more than 128 set speed in reverse
CALL	ReverseL	;so '1' is very slow forward
BTFSS	temp, 7		;and '129' is very slow reverse
CALL	ForwardL
ANDLW	0x7F
MOVWF   CCPR1L
RETURN

ReverseL:
BSF	PORTC,0	;set pins for reverse
BCF	PORTC,1
RETURN

ReverseR:
BSF	PORTC,3
BCF	PORTC,4
RETURN

etc etc
the next bit to do is try and fit channel 2 back in, it was messing with channel 1, not sure if that is my electronics skills or in my code.

EDIT Rather than Double post, I'll just edit this one.

Finished code, still some old code left in. Had to move the direction code into the code that I had already as it was not choosing a direction since it didn't see the numbers it used to in the working register to temp.

Code:
; 16F877A PWM example code changed into RC skid steer system
; Thanks to Nigel Goodwin for supplying a good chunk of the code, your rock!
; Device 16F877A
; PortB 6&7 are inputs from RC unit
; PORTB 0-3 are output LEDS for direction
; PORTB 0-3 LEDS will flash randomly when stand still
; this will be the output aswell, might cause a problem
; or 2, not sure as yet

LIST P=16F877A, W=2, X=ON, R=DEC
#INCLUDE P16F876.INC
__CONFIG    0x393A

cblock	0x20	;start of general purpose registers
count		;used in delay routine
count1		;used in delay routine
counta		;used in delay routine
countb		;used in delay routine
Timing1
Timing1c
Timing1cv
temp		;temp storage
WST0		;used in delay routines
WST1		;used in delay routines
WST2		;used in delay routines
WST3		;used in delay routines

CH1V		;Variable for channel 1 up counter
CH1V1		;Variable for channel 1 down counter
CH2V		;Variable for channel 2 up counter
CH2V1		;Variable for channel 2 down counter
endc

ORG	0x0000
NOP
NOP
GOTO	START
ORG	0x0010

Initialise:	;routine moved to start for visual flow through
bsf		STATUS,RP0	;change to bank 1
movlw	b'00000110'

movlw	b'00000000' ;RA as outputs
movwf	TRISA
movlw	b'11000000'	;RB as inputs for 6 & 7
movwf	TRISB
movlw	b'00000000'	;RC all as outputs
movwf	TRISC
bcf	STATUS,RP0	;change to bank 0
clrf	PORTA
clrf	PORTB
clrf	PORTC

MOVF     CCP1CON,W	;set CCP1 as PWM
ANDLW    0xF0
IORLW    0x0C
MOVWF    CCP1CON
MOVF     CCP2CON,W	;set CCP2 as PWM
ANDLW    0xF0
IORLW    0x0C
MOVWF    CCP2CON
MOVLW    126		;set highest PWM value
BANKSEL  PR2		;over this (127) is permanently on
MOVWF    PR2
BANKSEL  TMR2
MOVF     T2CON,W	;set prescaler to 16
ANDLW    0xF8		;PWM at 2500HZ
IORLW    0x02
MOVWF    T2CON
MOVF     T2CON,W	;set postscaler to 1
ANDLW    0x07
IORLW    0x00
MOVWF    T2CON

CLRF	CCPR1L		;set PWM to zero
CLRF	CCPR2L

BSF      T2CON, TMR2ON	;and start the timer running
movlw	d'50'
movwf	Timing1
movlw	d'178'
movwf	Timing1c
movf	Timing1,w
incf	Timing1,w
movwf	Timing1cv
movlw	b'00001111'		;turns off LEDS on PORTB
movwf	PORTB
RETURN

START
CALL	Initialise
goto	MainLoop

MainLoop:

call	CH1Start	;start ch1 timing
call	CH1			;collect output of RC1
call	CH2Start	;start ch2 timing
call	CH2			;collect output of RC2
call 	Output1		;choose ch1 direction and speed
call	Output2		;choose ch2 direction and speed
GOTO	MainLoop	;loop back and wait for signal

CH1Start:
btfss	PORTB,7		;wait for pulse to start
goto	CH1Start	;loop till pin is high
call	Waste1ms	;Wait nearly 1ms
clrf	CH1V		;resets counter to count up
clrf	CH1V1		;resets counter to count down
decf	CH1V1,f
return				;count after 1ms

CH1:

btfss	PORTB,7		;is the pin still high?
return				;no, go back to main
call	Waste128	;yes, waste some time and
incfsz	CH1V,f		;increase the count, skip if max (0 again)
goto	CH1inc		;sub routine to inc count and dec counter count
decf	CH1V,f		;dec count if max, keep at max
return

CH1inc:
decf	CH1V1,f		;dec CH1 down count
goto	CH1

CH2Start:
btfss	PORTB,6		;wait for pulse to start
goto	CH2Start	;loop till pin is high
call	Waste1ms	;Wait nearly 1ms
clrf	CH2V		;resets counter to count up
clrf	CH2V1		;resets counter to count down
decf	CH2V1,f
return				;count after 1ms

CH2:

btfss	PORTB,6		;is the pin still high?
return				;no, go back to main
call	Waste128	;yes, waste some time and
incfsz	CH2V,f		;increase the count, skip if max (0 again)
goto	CH2inc		;sub routine to inc count and dec counter count
decf	CH2V,f		;dec count if max, keep at max
return

CH2inc:
decf	CH2V1,f		;dec CH2 down count
goto	CH2

Waste128:
movlw	d'1'		;rest time between incrementing signal
movwf	WST0		;change for different RC output with Waste 1ms
Waste2:					;with RC unit tested
decfsz	WST0,f		;
goto	Waste2
Return

Waste1ms:
movlw	d'7'		;rest time before counting signal
movwf	WST2		;should be about 1ms
Waste1:
decfsz	WST1,f
goto	Waste1
decfsz	WST2,f
goto	Waste1
Return

Output1
btfss	CH1V,7		;is it forward or reverse?
goto	Output1up	;use up counter as output
goto	Output1dn	;use down counter as output

Output1up	;forwardL
BCF		PORTC,0		;set pins for forward
BSF		PORTC,1
BCF		PORTB,0		;set LEDS for show
BSF		PORTB,1
movf	CH1V1,w
goto	SpeedL

Output1dn	;ReverseL
BSF		PORTC,0		;set pins for reverse
BCF		PORTC,1
BSF		PORTB,0		;Sets LED direction indicators
BCF		PORTB,1
movf	CH1V,w
goto	SpeedL

Output2
btfss	CH2V,7		;which direction?
goto	Output2up	;use up counter as output
goto	Output2dn	;use down counter as output

Output2up	;ForwardR:
BCF		PORTC,3		;set direction forwards
BSF		PORTC,4
BCF		PORTB,2		;set LED indicators
BSF		PORTB,3
movf	CH2V1,w		;move speed for forward to working
goto	SpeedR

Output2dn
movf	CH2V,w		;as per previous
BSF		PORTC,3
BCF		PORTC,4
BSF		PORTB,2
BCF		PORTB,3
goto	SpeedR

SpeedL:				;use value in W to set speed (0-127)(i think)

MOVWF	temp
bcf		temp,0	;remove lower bits to give
bcf		temp,1	;a better stand still signal
bcf		temp,2	;
ANDLW	0x7F
MOVWF   CCPR1L
RETURN

SpeedR:
MOVWF	temp
bcf		temp,0	;remove lower bits to give
bcf		temp,1	;better stand still signal
bcf		temp,2	;
ANDLW	0x7F
MOVWF   CCPR2L
RETURN

;Delay routines

Long_Delay
movlw	d'10'		;delay 1 seconds
call	Delay100W
return

Delay100W	movwf	count		;delay W x 100mS
d2		call	Delay100	;maximum delay 25.5 seconds
decfsz	count	,f
goto	d2
return

Delay255	movlw	0xff		;delay 255 mS
goto	d0
Delay100	movlw	d'100'		;delay 100mS
goto	d0
Delay50		movlw	d'50'		;delay 50mS
goto	d0
Delay20		movlw	d'20'		;delay 20mS
goto	d0
Delay10		movlw	d'10'		;delay 10mS
goto	d0
Delay1		movlw	d'1'		;delay 1mS
goto	d0
Delay5		movlw	0x05		;delay 5.000 ms (4 MHz clock)
d0		movwf	count1
d1		movlw	0xE7
movwf	counta
movlw	0x04
movwf	countb
Delay_0		decfsz	counta, f
goto	\$+2
decfsz	countb, f
goto	Delay_0

decfsz	count1	,f
goto	d1
return

;end of Delay routines

END
Only thing that is bugging me now, because I am using the same stick for a tank control, i still think i am presented with the original problem of mixing the signals like a wheel chair. Unless I missed something, I have just got the code for an ESC and not much more ><

Last edited:

#### niak32

##### New Member
Thanks Nigel, the code worked great, I made my own problems applying my code to yours and had to modify both so i could understand it, and so of course it worked. Biggest thing for me is that I understand it.

To make a point, this works great as a skid steer system using 2 sticks and that is most likely how the original code was intended including a hell of a lot of control over speed and of course, the 8th bit for direction.

I'm still faced with the original problem of mixing the signals from one stick instead of using 2
ie

one stick using Both Axis's, like a wheel chair (or at least like mine)
FL FF FR
HL xx HR
RL FR RR

2 sticks, one axis - normal skid steer system.
FL FR
xx xx
RL RR

I will have a play and try to figure out how to mix the signals. the only way i can think of how to do that so far includes a hell of a lot of code testing each bit in a range, or adding a third channel for the speed control and go back to basics with direction.

#### Nigel Goodwin

##### Super Moderator
I posted BASIC code to do exactly that earlier this year - but I'm not quite sure what thread it was in.

EDIT:
Just found this, on my work computer, I'm not sure if it was the same as I posted before, but it should give you some ideas.

Code:
Device 16F876
Dim Speed, Steer, C, Dead, Left, Right, Error
Freq=20
Define PortC=%00000000
Define PortB=%11111111
Define PortA=%11111111
Set(CCP1=PWM)
Set(CCP2=PWM)
PERIOD_REG=249
Set(TIMER2_PRESCALER=1)
Set(TIMER2_POSTSCALER=1)
START(TIMER2)
OUTC(0)
OUTB(0)
Error=0
ReStart:
Left=0
Right=0
Loop:
PWM_Duty1L=Left
PWM_Duty2L=Right
Speed=Pulsein(portB, 7, 1)
If Speed=0 Then Goto NoPulse
If Speed>750 Then Speed=750
If Speed<250 Then Speed=250
Steer=Pulsein(portB, 6, 1)
If Steer=0 Then Goto NoPulse
Error=0				'both pulses OK
If Steer>750 Then Steer=750
If Steer<250 Then Steer=250
Steer=Steer-250
If Steer<250 Then Gosub TurnLeft
If Steer>249 Then Gosub TurnRight
Goto Loop

NoPulse:
Error=Error+1
If Error > 5 Then Goto ReStart
Goto Loop

TurnLeft:
C=250-Steer
Right=Speed+C
Left=Speed-C
Gosub Scale
Return

TurnRight:
C=Steer-250
Left=Speed+C
Right=Speed-C
Gosub Scale
Return

Scale:
Right=Right-250
Left=Left-250
If Left>10000 Then Left=0	'correct for negative number
If Right>10000 Then Right=0	'correct for negative number
If Right>500 Then Right=500
If Left>500 Then Left=500
If Right<250 Then Goto ReverseA
Goto ForwardA
Do_Left:
If Left<250 Then Goto ReverseB
Goto ForwardB
Done_Left:
Return

ReverseA:
Right=250-Right
High PortC, 3
Goto Do_Left

ForwardA:
Right=Right-250
Low PortC, 3
Goto Do_Left

ReverseB:
Left=250-Left
High PortC, 4
Goto Done_Left

ForwardB:
Left=Left-250
Low PortC, 4
Goto Done_Left

Return

end

Last edited:

#### niak32

##### New Member
Cheers Nigel, I have the general Idea now. got a "semi" working version, just need to keep hacking at it when i have moments of "normal or higher" brain power spurts.

Will post my progress or the end result when i get it.

Status
Not open for further replies.