comwarrior
- 15th August 2013, 00:10
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...
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.
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
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...
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.
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