Continue to Site

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.

  • 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.

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
	addwf	CH1T22,f
	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
	addwf	CH2T22,f
	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:
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.
 
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.
 
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.
 
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?
 
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.
 
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).
 
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.
 
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.
 
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:
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	;for bootloader compatibility
    	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'
	movwf	ADCON1		;turn off A2D
    
	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:
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.
 
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
Dead=30	'set dead band value
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
	Gosub Check_Dead
	High PortC, 3
Goto Do_Left

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

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

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

Check_Dead:
	If Right<Dead Then Right=0
	If Left<Dead Then Left=0
Return

end
 
Last edited:
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.

Latest threads

New Articles From Microcontroller Tips

Back
Top