PIC based Servo Exerciser/Tester
(Harry Lythall)

Introduction

Here is my first PIC project for radio control. The object is to create a code that will vary the servo position from 0-90 degrees and back again. This is done for up to four servos, but with each servo in a different position. Note that tghis circuit generates a code for the R/C decoder and can not drive a single servo. The timing diagram of the output looks something like this (not to scale):

Pulse A is the frame start pulse. The time from the start of pulse A - B controls servo 1 position. The time from the start of pulse B - C controls servo 2 position. The time from the start of pulse C - D controls servo 3 position. The time from the start of pulse D - E controls servo 4 position. The delay between pulses E and the following pulse A is the reset delay to tell the receiver decoder to reset the servo counter and begin a new frame, starting with pulse A. This duration should be about 20ms but can be anything from 10ms upwards. Mine is 20ms.

The timing diagram is not really all that critical. I think that my final pulses are around 200us and the timing varies from 0.6ms to 1.6ms between them. I simply fiddled with the timing a bit so it was stable with several different servos that I have in the junkbox, including a pair of micro servos robbed from an electrically powered model helicopter.

This project does not have a circuit diagram, but do you really need one? Just connect +5v to the chip pin 1, Gnd to pin 8, and connect pin 7 to the servo decoder. There are no resistors, capacitors, crystals, or any other components, other than the chip. There is a simple diagram in the ASM file itself. The power can be anything from 3v to 5.5vDC at about 100uA.

This must be the simplest circuit I have ever made, if you consider only the hardware. The software, however, is a bit more complicated.

Software

If you have a PIC programmer then you can download the HEX file and burn it yourself using PICProg4U or WINPROG. I am using the MPLabs PIC-Kit2 assembler and the RCD programmer. This nice little programmer is published by Feng3 at http://feng3.nobody.jp/en/rcd.html, which you can download and use for free. The HEX file you need is pic-rc-encoder_02.hex, which you download and burn to the processor flash memory. Right-click the link and save the file to your hard disk.

If you wish to modify the code for your own application then you will need the source code. If you want a chip ready programmed then you can send me US$2.50 per chip and US$4.50 to cover postage (any reasonable quantity). For one chip this is US$7 (SEK50) including postage.

If you want the chips for commercial use then please call me: If you are going to make a profit from my work then I would like US$1.50 commission per chip. Here is my ASM file:

; ----------------------------------------------------------------|
;                                                                 |
; Experiment using 12F509, which will be changed to 12F675 (with  |
; A-D converter) to generate a variable PWM timing frame; basis   |
; for R/C encoder.                                                |
;                                                                 |
; Experiment generates a sliding PWM pulse to simulate four pots. |
;                                                                 |
; ----------------------------------------------------------------|
;                                                                 |
; Programmer:     	Harry Lythall (SM0VPO) www.sm0vpo.com     |
; 2012-04-17:		date started                              |
; 2012-04-19:		Channel pulses and frame generated        |
; 2012-05-30:		timing checked                            |
; 2012-06-01:		Practical test with decoder and 4 servos  |
;                                                                 |
; ----------------------------------------------------------------|
;                                                                 |
; Chip pinout (only 3 pins used):                                 |
;                                                                 |
; 		----U----                                         |
; 	+5vDCin	:1	8: Chassis/ground/power negative          |
;  not used GP5 :2	7: GP0 - Output pulses                    |
;  not used GP4	:3	6: GP1 - not used                         |
; 	GP3/RST	:4	5: GP2 - not used                         |
; 		----------                                        |
;                                                                 |
; GP3/RST will reset the processor if grounded.                   |
;                                                                 |
; Connect +5v (3.5v to 5.5v) to pin 1                             |
; Connect -ve Gnd to pin 8                                        |
; Connect GP0 pin 7 to 4CH servo decoder                          |
;                                                                 |
; ----------------------------------------------------------------|
;                                                                 |
; Can be used to exercise R/C decoder and four servos in constant |
; motion with no two servos in the same position. Servos 1 and 2  |
; move oposite directions and servos 3 and 4 also move in oposite |
; directions. Servos 1 and 3 cycles are displaced by 90 degrees.  |
;                                                                 |
; Complicated, isn't it?                                          |
;                                                                 |
; ----------------------------------------------------------------|
;                                                                 |
; Future:                                                         |
; Replace processor with 12F675-I/P and read analogue instead     |
; of pot registers (pt1-4) and you will have a 4-CH R/C encoder.  |
;                                                                 |
; ----------------------------------------------------------------|
;                                                                 |
; Internal clock = 4MHz                                           |
;                                                                 |
; ----------------------------------------------------------------|

    list        p=12F509      
    #include    

	; ext reset, no code protect, no watchdog, 4Mhz int clock
    __CONFIG    _MCLRE_OFF & _CP_ON & _WDT_OFF & _IntRC_OSC


;***** SET VARIABLES AND INITIALISE

;***************** variable definitions
        UDATA
	pt1     res 1           ; Potentiometer 1 value
	pt2     res 1           ; Potentiometer 2 value
	pt3     res 1           ; Potentiometer 3 value
	pt4     res 1           ; Potentiometer 4 value
	stat    res 1		; Status register
	dly1	res 1		; used in var delay routine
	dly2	res 1		; used for the 25ms wait

;***************** Configure ports
RESET   CODE    0x000           ; effective reset vector
        movwf   OSCCAL          ; update OSCCAL with factory cal value 

	movlw   b'111110'       ; configure GP0 as an output
        tris    GPIO		; execute it

;***************** Set variables
	movlw   .127		; pot starting value
	movwf	pt1		; save it to pt1

	movlw   .127		; pot starting value
	movwf	pt2		; save it to pt2

	movlw   .63		; pot starting value
	movwf	pt3		; save it to pt2

	movlw   .183		; pot starting value
	movwf	pt4		; save it to pt2

	movlw   b'00001010'	; Set pots to counting up/down
	movwf	stat		; save to status register


;***** START OF MAIN PROGRAM

;***************** Send start pulse and pot 1
Start	movlw	b'00001'	; Binary value for port output
	movwf	GPIO		; Set pot GP0 to 1
	movlw	.49		; Get 200uS value
	movwf	dly1		; Save it to delay va4riable
	call	Dely1		; go there
	movlw	b'00000'	; Binary value for port output
	movwf	GPIO		; Set port GP0 to 0

;***************** Now wait 500mS
	movlw	.125		; value for 500mS
	movwf	dly1		; save it to delay variable
	call	Dely1		; go do it


; ***** SIMULATE POTENTIOMETER 1

;***************** Test loop - count pt1 up then down
Pot1	btfsc	stat,0		; test bit0 - skip if clear
	goto	Cup1		; Ok, so its 1 then goto cup1 (count UP pot1)
Cdn1	decfsz	pt1		; subtract 1 (count down)
	goto	Cdn1a		; continue if not zero
	bsf	stat,0		; Still here? Should be counting down. Set status 1
	goto	Cup1		; and go to count up
Cdn1a	movfw	pt1		; get pot value
	movwf	dly1		; save the pot value
	call	Dely1		; wait for it
	goto	Pot2		; start again
Cup1	incfsz	pt1		; add 1 to count up - skip if over the top
	goto	Cup1a
	goto	Cup1b		; over the top so go set stat to 0 and have another go
Cup1a	movfw	pt1		; get pot1 value
	movwf	dly1		; save pot value
	call	Dely1		; wait for it
	goto	Pot2		; do it all again
Cup1b	bcf	stat,0		; Set bit0 to zero to change direction
	goto	Cdn1		; and start the count down

; ***** SIMULATE POTENTIOMETER 2

;***************** Send start pulse and pot 2
Pot2	movlw	b'00001'	; Binary value for port output
	movwf	GPIO		; Set opot GP0 to 1
	movlw	.49		; Get 200uS value
	movwf	dly1		; Save it to delay va4riable
	call	Dely1		; go there
	movlw	b'00000'	; Binary value for port output
	movwf	GPIO		; Set port GP0 to 0

;***************** Now wait 500mS
	movlw	.125		; value for 500mS
	movwf	dly1		; save it to delay variable
	call	Dely1		; go do it

;***************** Test loop - count pt2 up then down
	btfsc	stat,1		; test bit1 - skip if clear
	goto	Cup2		; Ok, so its 1 then goto cup2
Cdn2	decfsz	pt2		; subtract 1 (count down)
	goto	Cdn2a		; continue if not zero
	bsf	stat,1		; Still here? Should be counting down. Set status 1
	goto	Cup2		; and go to count up
Cdn2a	movfw	pt2		; get pot value
	movwf	dly1		; save the pot value
	call	Dely1		; wait for it
	goto	Pot3		; start again
Cup2	incfsz	pt2		; add 1 to count up - skip if over the top
	goto	Cup2a
	goto	Cup2b		; over the top so go set stat to 0 and have another go
Cup2a	movfw	pt2		; get pot1 value
	movwf	dly1		; save pot value
	call	Dely1		; wait for it
	goto	Pot3		; do it all again
Cup2b	bcf	stat,1		; Set bit2 to zero to change direction
	goto	Cdn2		; and start the count down


; ***** SIMULATE POTENTIOMETER 3

;***************** Send start pulse and pot 3
Pot3	movlw	b'00001'	; Binary value for port output
	movwf	GPIO		; Set opot GP0 to 1
	movlw	.49		; Get 200uS value
	movwf	dly1		; Save it to delay va4riable
	call	Dely1		; go there
	movlw	b'00000'	; Binary value for port output
	movwf	GPIO		; Set port GP0 to 0

;***************** Now wait 500mS
	movlw	.125		; value for 500mS
	movwf	dly1		; save it to delay variable
	call	Dely1		; go do it

;***************** Test loop - count pt3 up then down
	btfsc	stat,2		; test bit2 - skip if clear
	goto	Cup3		; Ok, so its 1 then goto cup3
Cdn3	decfsz	pt3		; subtract 1 (count down)
	goto	Cdn3a		; continue if not zero
	bsf	stat,2		; Still here? Should be counting down. Set status 1
	goto	Cup3		; and go to count up
Cdn3a	movfw	pt3		; get pot value
	movwf	dly1		; save the pot value
	call	Dely1		; wait for it
	goto	Pot4		; start again
Cup3	incfsz	pt3		; add 1 to count up - skip if over the top
	goto	Cup3a
	goto	Cup3b		; over the top so go set stat to 0 and have another go
Cup3a	movfw	pt3		; get pot1 value
	movwf	dly1		; save pot value
	call	Dely1		; wait for it
	goto	Pot4		; do it all again
Cup3b	bcf	stat,2		; Set bit0 to zero to change direction
	goto	Cdn3		; and start the count down


; ***** SIMULATE POTENTIOMETER 4

;***************** Send start pulse and pot 4
Pot4	movlw	b'00001'	; Binary value for port output
	movwf	GPIO		; Set opot GP0 to 1
	movlw	.49		; Get 200uS value
	movwf	dly1		; Save it to delay va4riable
	call	Dely1		; go there
	movlw	b'00000'	; Binary value for port output
	movwf	GPIO		; Set port GP0 to 0

;***************** Now wait 500mS
	movlw	.125		; value for 500mS
	movwf	dly1		; save it to delay variable
	call	Dely1		; go do it

;***************** Test loop - count pt4 up then down
	btfsc	stat,3		; test bit3 - skip if clear
	goto	Cup4		; Ok, so its 1 then goto cup4
Cdn4	decfsz	pt4		; subtract 1 (count down)
	goto	Cdn4a		; continue if not zero
	bsf	stat,3		; Still here? Should be counting down. Set status 1
	goto	Cup4		; and go to count up
Cdn4a	movfw	pt4			; get pot value
	movwf	dly1		; save the pot value
	call	Dely1		; wait for it
	goto	Finish		; start again
Cup4	incfsz	pt4		; add 1 to count up - skip if over the top
	goto	Cup4a
	goto	Cup4b		; over the top so go set stat to 0 and have another go
Cup4a	movfw	pt4		; get pot4 value
	movwf	dly1		; save pot value
	call	Dely1		; wait for it
	goto	Finish		; do it all again
Cup4b	bcf	stat,3		; Set bit0 to zero to change direction
	goto	Cdn4		; and start the count down


; ***** DELAY LOOPS

;***************** final delay (send pulse and wait 25mS)
Finish	movlw	b'00001'		; Binary value for port output
	movwf	GPIO		; Set opot GP0 to 1
	movlw	.49		; Get 200uS value
	movwf	dly1		; Save it to delay va4riable
	call	Dely1		; go there
	movlw	b'00000'	; Binary value for port output
	movwf	GPIO		; Set port GP0 to 0
				; the big wait
	movlw	25		; for 25mS
	movwf	dly2		; save it in delay counter
Fin1	decfsz	dly2
	goto	Fin2
	goto	Start
Fin2	movlw	.200		; get value for 1ms
	movwf	dly1		; put in delay register
	call	Dely1		; lets have 4uS delay x dly1
	goto	Fin1		; go back to see if we have had enough


;***************** 4us delay routine (x value in dly1 + 12us)
Dely1	decfsz	dly1			; decrement and jump if zero
	goto	Dely1		; not zero - hop over
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	retlw	0		; it's zero - return

        END

The program reads the contents of the status register. In each case bits 0-3 are an UP/DOWN flag for each servo direction. Servos 1 and two have the same starting value and servos 3 and 4 have other starting values.

The delay values range from 1 to 253. If the top or bottom value is reached then the UP/DOWN flag bit in the status register is changed to make the servo move in the opposite direction. A value of 253 is equal to 1ms (plus the 200us pulse and 400us delay fixed values).

Support

These projects are all 100% free for non-profit private use. You may download and use all my projects, PCB foil patterns and software for prive use. These projects have taken years to create and are free from membership fees, advertising and banners.

Best regards from Harry - SM0VPO

Return to INFO page