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