18F46K22 PBP2.6C
Ok, wanting to command a servo... but, want to use interupts so that the pic can do other things and/or drive multiple servo's...
So, first of all, i started off doing it with PAUSEUS to make sure i get the timings right...
Code:
SERVO1 VAR LATD.0
SERVO1POS VAR BYTE
MAIN:
SERVO1POS = 128
FOR ALOOP = 1 to 250
SERVO1 = 1
PAUSEUS 988
PAUSEUS (SERVO1POS * 4)
SERVO1 = 0
PAUSEUS (20000 - (988 + (SERVO1POS * 4)))
NEXT ALOOP
SERVO1POS = 1
FOR ALOOP = 1 to 250
SERVO1 = 1
PAUSEUS 988
PAUSEUS (SERVO1POS * 4)
SERVO1 = 0
PAUSEUS (20000 - (988 + (SERVO1POS * 4)))
NEXT ALOOP
SERVO1POS = 255
FOR ALOOP = 1 to 250
SERVO1 = 1
PAUSEUS 988
PAUSEUS (SERVO1POS * 4)
SERVO1 = 0
PAUSEUS (20000 - (988 + (SERVO1POS * 4)))
NEXT ALOOP
GOTO MAIN
Simples... works perfectly...
So now i start doing the math and working out the preloads for timers with the help of an excell spreadsheet.
Code:
SERVO1 VAR LATD.0
SERVO1POS VAR BYTE
PRELOAD1 VAR WORD
PRELOAD2 VAR WORD
PRELOAD3 VAR WORD
SERVOCMDMODE VAR BYTE
SERVOPWMCOUNTER VAR WORD
PRELOAD1 = 63556 ' 990us '63556
TMR0_CON_PL1 CON %10000010 ' 1:8
PRELOAD2 = 65528 ' 4us '65528
TMR0_CON_PL2 CON %10000010 ' 1:8
PRELOAD3 = 29556 ' 17990us '29556
TMR0_CON_PL3 CON %10000010 ' 1:8
@ INT_ENABLE TMR0_INT
TMR0L = PRELOAD3.LOWBYTE
TMR0H = PRELOAD3.HIGHBYTE
T0CON = TMR0_CON_PL3
SERVOCMDMODE = 1
MAIN:
SERVO1POS = 0
PAUSE 5000
SERVO1POS = 128
PAUSE 5000
SERVO1POS = 255
PAUSE 5000
GOTO MAIN
SERVO_HANDLER:
IF SERVOCMDMODE = 2 Then
IF SERVOPWMCOUNTER < 256 THEN
T0CON = TMR0_CON_PL2
TMR0L = PRELOAD2.LOWBYTE
TMR0H = PRELOAD2.HIGHBYTE
IF SERVO1POS < SERVOPWMCOUNTER THEN
SERVO1 = 0
LATD.1 = 0
LATD.2 = 0
LATD.3 = 0
ELSE
SERVO1 = 1
LATD.1 = 0
LATD.2 = 1
LATD.3 = 0
ENDIF
SERVOPWMCOUNTER = SERVOPWMCOUNTER + 1
ELSE
T0CON = TMR0_CON_PL3
TMR0L = PRELOAD3.LOWBYTE
TMR0H = PRELOAD3.HIGHBYTE
SERVO1 = 0
LATD.1 = 0
LATD.2 = 0
LATD.3 = 1
SERVOCMDMODE = 1
ENDIF
@ INT_RETURN
ENDIF
IF SERVOCMDMODE = 1 Then
T0CON = TMR0_CON_PL1
TMR0L = PRELOAD1.LOWBYTE
TMR0H = PRELOAD1.HIGHBYTE
SERVOCMDMODE = 2
SERVO1 = 1
LATD.1 = 1
LATD.2 = 0
LATD.3 = 0
SERVOPWMCOUNTER = 1
@ INT_RETURN
ENDIF
@ INT_RETURN
And thats where i now have a problem and i don't understand why.
For debug purposes i added the three LATD outputs so that i could find where i was having issues.
First off, the frequency is 46.75... ok, i'm sure it can still handle it, and i can adjust this later.
Secondly, the duty cycle goes from 84.0% to 93.9% to 99.6%...
It should be 5%, 7.5% and 10%...
Debug output shows LATD1 at 84.4%...
LATD1 is for pre-duty phase, when in my code is SERVOCMDMODE = 1
It's on for 84% of the time and it shouldn't, it should be 5%...
I'm looking at my code thinking 'that is not possible'...
So, I've got to have made a stupid mistake somewhere and i can't see it. Can some wonderful person tell me what my stupid mistake is?
Thanks
Bookmarks