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.

Add GPS/PARSE to 8xSERVO-MOTOR CODE in Oshonsoft

Hi M and S,
A quick note before I try the latest CODE!
When running normally, the SERVOS won't be moving forward/reverse, but when an instruction arrives from the CONTROL. I've been trying to remove the FOR/REV section, but getting mixed up, also, when sending a test number does the 'DIR' need to be also sent?

The 'stutter' looks like the normal SERVO movement, but each step has a pause, depending on what I add to the WAIT 1 LOOP.
C
 
Hi M and S,
I tried the #236 CODE, but there were a few 'none compile' erros. I tried changing some, but no good. (marked '<<<<<<<<<<<<<<) The Leds flash but no SERVO movement.
Check [ getmsflag ] and [getms]

I tried both methods of copy and paste, but there doesn't seem to be anyway to keep the indents and good CODE :(
C.
Code:
'18F4431 32MHz XTL PCB9 REMOTE_SLAVE GPS_SERVO 180423 1030

Define CONFIG1L = 0x00
Define CONFIG1H = 0x06  '8mHz XTL x4 =32mHz
Define CONFIG2L = 0x0c
Define CONFIG2H = 0x20
Define CONFIG3L = 0x04
Define CONFIG3H = 0x80
Define CONFIG4L = 0x80  'Set for HVP
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40

Define CLOCK_FREQUENCY = 32
Define SINGLE_DECIMAL_PLACES = 2
Define STRING_MAX_LENGTH = 20

'Define SIMULATION_WAITMS_VALUE = 1  'Comment in for SIM out for PIC

Dim wordTemp As Word
Dim servoCount As Byte
Dim i As Word
Dim servoPos(8) As Word
Dim servoDir(8) As Byte
Dim frame As Word
Dim buff(80) As Byte
Dim strCount As Byte
Dim rec As Byte
Dim isDone As Bit
Dim cnt As Byte
Dim fifo(16) As Byte
Dim fifoStart As Byte
Dim fifoEnd As Byte
Dim ccpDone As Bit
Dim previous As Bit
Dim TXbyte As Byte
Dim bitCount As Byte
Dim ms As Word
Dim readMsFlag As Bit
Dim tick As Byte
Dim tickLED As Word
Dim str As String

Dim pos As Word  '<<<<<<<<<<<<
Dim dir As Byte  '<<<<<<<<<<<
Dim serialcount As Byte  '<<<<<<<<<<<<<<
Dim length As Byte  '<<<<<<<<<<<<<<<<<<<
Dim getmsflag As Bit  '<<<<<<<<<<<<<<

Symbol rled = PORTD.7  '<<<<<<<<<<<
Symbol yled = PORTD.6  '<<<<<<<<<<<

OSCCON = %01110000  '& h70
Gosub initIO  'Moved up<<<<<<<<<<<<<<<<<<<<<<<<<<<
Gosub initServos
Gosub initSerial
Gosub initTMR1
Gosub initTMR2

'Start up leds
rled = 1
yled = 1
WaitMs 1000
rled = 0
yled = 0
WaitMs 1000
rled = 1
yled = 1
WaitMs 1000
rled = 0
yled = 0
WaitMs 1000
tick = 0
ms = 0
INTCON = 0xc0  'only PEIE and GIE set
WaitMs 2  'let serial flush and get stable
str = "$test stringW"
For i = 0 To Len(str) - 1
Call putFifo(str(i))
Next i
While 1
If (ms.LB - tick) > 20 Then
tick = ms.LB
'this code gets executed 50 times per second (every 20mS)
For i = 0 To 7
dir = servoDir(i)  'doesn't matter if ISR happens as servoPos isn't changed by ISR
pos = servoPos(i)
If dir = 1 Then
pos = pos + 40  'add 1/50th to the servo position
Else
pos = pos - 40  'subtract it
Endif
If pos < 2000 Then  'have we gone past the end?
pos = 2000  'yes so make it the end stop
dir = 1  'and turn it around
Endif
If pos > 4000 Then  'same for other end
pos = 4000
dir = 0
Endif
INTCON.GIE = 0  'no interrupts
servoPos(i) = pos
INTCON.GIE = 1  're enable interrupts
servoDir(i) = dir  'servoDir not used by ISR
Next i
Endif
'example code to flash an LED at 1Hz
If (getMS - tickLED) > 500 Then  'note cannot be more than 65535 (65 seconds!!!!)
'this code executed every 500mS which is 1Hz
tickLED = ms
rled = 1 - rled  'ERROR Can't use BIT variable for rled <<<<<<<<<<<<<<<<<<<
Endif
Wend
End                                              

Function getMS() As Word
getmsflag = 0
getMS = ms
If getmsflag Then
getMS = ms
Endif
End Function                                    

Proc putFifo(dat As Byte)
While ((fifoEnd - fifoStart) And 0x0f) = 0x0f
Wend
fifo(fifoEnd) = dat  'add data to queue
fifoEnd = (fifoEnd + 1) And 0x0f  'and increment pointer
End Proc                                        

Function getFifo() As Byte  'note, doesn't test if fifo is empty
getFifo = fifo(fifoStart)  'so always call getFifoLen first
fifoStart = (fifoStart + 1) And 0x0f
End Function                                    

Function getFifoLen() As Byte
getFifoLen = (fifoEnd - fifoStart) And 0x0f
End Function                                    

initSerial:
'setup USART for 9600 baud receive
RCSTA = %10010000
TXSTA.BRGH = 1
SPBRG = 207
PIR1.RCIF = 0
BAUDCON.BRG16 = 1
PIE1.RCIE = 1
PIE1.RCIE = 1
strCount = 0
isDone = 0
ccpDone = 1
Return                                          

initServos:
LATC.0 = 0  'ensure data is low
LATC.2 = 0  'and clock
For i = 0 To 7
LATC.2 = 1  'send positive clock edge
servoPos(i) = i * 250 + 2000  '1ms(2000) to 1.875(1 7/8ths - 3750)ms in 1/8th mS steps
LATC.2 = 0  'send negative edge
servoDir(i) = i And 1  '<<<<<<<added
Next i
servoCount = 8  'cause it to reset
CCP1CON = %1000  'will go high on interrupt - will start a 0.5mS pulse
frame = 1000  'start everything in 4000 cycles
Return                                          

initTMR1:
T1CON = %00100000  'prescaler = 4
T1CON.0 = 1  'start timer
Return                                          

initTMR2:
'setup 1mS interrupt = 8,000,000/16 = 500,000/10 = 50,000 set PR2=49 = 50,000/50 = 1000 = 1mS
T2CON = %01001110  '& h4e
PR2 = 49  'This is timer 2 period register. I.E. reset after 50 clocks (0 to 49 = 50 counts)
PIE1.TMR2IE = 1  'timer 2 interrupts enable
Return                                          

initIO:
TRISA = %11000000  '7=OSC, 6=OSC,
TRISB = %00000000
TRISC = %11111000  '6=1-slave4431_cs, 2=74HC164 CLK, 0=74HC164 DATA 1=Serial out
TRISC = %11111010  'CCP0 (RC2) & RC0 output
TRISD = %00000000
Return                                          

On High Interrupt  'go via location 0x0008
Save System
If PIR2.CCP2IF Then
serialcount = serialcount + 1
wordTemp.LB = CCPR2L  'ensure next interrupt is
wordTemp.HB = CCPR2H  'in 208*4=832 instruction cycles
wordTemp = wordTemp + 208  '208 is 2,000,000/9600 = 104uS or the time for 1 bit at 9600 baud
CCPR2H = wordTemp.HB  'it's really important that the high byte gets written first
CCPR2L = wordTemp.LB  'write it back
LATC.1 = PORTC.1  'ensure latch is same as current CCP output
If ccpDone Then  'are we idle
bitCount = 0  'yes so reset things
length = getFifoLen()  'is anything in the fifo?
If length > 0 Then  'yes so start a new transmision
TXbyte = getFifo()  'get byte to transmit
CCP2CON = %1001  'pin high and low on next interrupt = start bit
ccpDone = False  'tell everything we're no londer idle
previous = 0  'set previous equal to start bit
Endif
Else
'we're sending a byte
If bitCount < 9 Then  'have we done a complete byte
If TXbyte.0 = previous Then  'no so send next bit,
'just need the interrupt as next bit is same as previous bit
CCP2CON = %1010
Else
'we need to flip the bit
If previous Then  'did we previously send a one?
'we need a zero next
previous = 0  'we're sending a zero next
CCP2CON = %1001  'will go to zero next match
Else
'we need a one next
previous = 1  'we're sending a one next
CCP2CON = %1000  'will go to zero next match
Endif
Endif
TXbyte = ShiftRight(TXbyte, 1)  'shift next bit to zero position
Else
'doing the stop bits
If bitCount < 10 Then
If previous Then
CCP2CON = %1010  'just need interrupt
Else
previous = 1
CCP2CON = %1000  'go high next interrupt
Endif
Else
ccpDone = True  'stop bits will still be generated - this happens at bitCount=10
Endif  'and output will stay high until next byte
Endif
Endif
bitCount = bitCount + 1  'this will get reset if idle
PIR2.CCP2IF = 0
Endif
If PIR1.TMR2IF Then  'Is it a timer 2 interrupt
getmsflag = 1  'make any read invalid
cnt = cnt + 1  'Increment count
ms = ms + 1  'increment milliSecond
If cnt >= 5 Then  'Has 5mS passed without a byte being received
isDone = 0
strCount = 0
cnt = 0
Endif
PIR1.TMR2IF = 0
Endif
If PIR1.CCP1IF Then  'has CCP1 triggered?
wordTemp.HB = CCPR1H  'get value of CCPR1 into wordTemp
wordTemp.LB = CCPR1L
If CCP1CON = 0x08 Then  'have we started the 1000 cycle pulse
CCP1CON = 0x09  'yes so end the pulse after 0.5mS
wordTemp = wordTemp + 1000  'adding 1000 will make pulse 0.5mS long
Else
LATC.0 = 0  'clear the data pin
CCP1CON = 0x08  'No so output the timed gap
If servoCount < 8 Then
'still doing the servos so add remainder of time
wordTemp = wordTemp + servoPos(servoCount)
wordTemp = wordTemp - 1000  'knock of the 1000 (0.5mS) already elapsed
frame = frame - servoPos(servoCount)
servoCount = servoCount + 1
Else
'done all the servos so just the frame gap to do
wordTemp = wordTemp + frame
frame = 39000  '40,000(20mS) minus time of positive pulse(0.5mS)
servoCount = 0  'start all over again
LATC.0 = 1  'will become first pulse
Endif
Endif
CCPR1H = wordTemp.HB  'put value back into CCPR1
CCPR1L = wordTemp.LB
PIR1.CCP1IF = 0  'clear interrupt flag
Endif
If PIR1.RCIF Then
cnt = 0  'stop any timeout happening
rec = RCREG  'get the received character
If RCSTA.OERR Or RCSTA.FERR Then  'neither of these should ever occur.
RCSTA.CREN = 0  'this is kinda wishful thinking
While PIR1.RCIF  'if any bytes in the buffer
rec = RCREG  'throw them away
Wend
RCSTA.CREN = 1  'as any data received is corrupt
strCount = 0  'however, reset everything
isDone = 0  'and hope for the best
Else  'no errors so use the data
'the following is waiting for a "$" sign
If strCount = 0 Then  'are we already receiving
'waiting for $        'no so wait
If rec = "$" Then  'for $ to appear
buff(strCount) = rec  'start receiving
strCount = 1  'must have been zero previously
Endif
Endif
'the following gets executed if we've allready got a "$" sign
'but not got a "W" yet.
If isDone = 0 And strCount <> 0 Then
If strCount < 80 Then  'only store it if there's room in the buffer
buff(strCount) = rec  'no so carry on storing
strCount = strCount + 1  'this may cause strCount to get to 80 = buffer full
Endif
If rec = "W" Then  'have we got the "endOfString" character
isDone = 1  'yes, so set done true
Endif
Endif
If isDone = 0 And strCount > 79 Then
'buffer has overflown
strCount = 0
Endif
Endif
Endif  'end RS232 if
Resume
 
I've made all the changes and (hopefully) fixed the flashing LED.
Code:
'18F4431 32MHz XTL REMOTE_SLAVE 164 160223 2330

Define CONFIG1L = 0x00
Define CONFIG1H = 0x06    '8mHz XTL x4 =32mHz
Define CONFIG2L = 0x0c
Define CONFIG2H = 0x20
Define CONFIG3L = 0x04
Define CONFIG3H = 0x80
Define CONFIG4L = 0x80    'Set for HVP
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40

Define CLOCK_FREQUENCY = 32
Define SINGLE_DECIMAL_PLACES = 2
Define STRING_MAX_LENGTH = 20

'Define SIMULATION_WAITMS_VALUE = 1    'Comment in for SIM out for PIC

Dim wordTemp As Word
Dim servoCount As Byte
Dim i As Word
Dim servoPos(8) As Word
Dim servoDir(8) As Byte
Dim frame As Word
Dim buff(80) As Byte
Dim strCount As Byte
Dim rec As Byte
Dim isDone As Bit
Dim cnt As Byte
dim fifo(16) as byte
dim fifoStart as byte
dim fifoEnd as byte
Dim ccpDone As Bit
Dim previous as Bit
Dim TXbyte as byte
Dim bitCount as byte
Dim ms as word
Dim readMsFlag as bit
Dim tick as byte
Dim tickLED as word
Dim str as string
Dim pos as word
Dim dir as byte
Dim serialCount as byte
Dim length as byte

Symbol rled = PORTD.7
Symbol yled = PORTD.6

OSCCON = %01110000        '& h70
gosub initIO
gosub initServos
gosub initSerial
gosub initTMR1
gosub initTMR2
'Start up leds
rled = 1
WaitMs 1000
rled = 0
WaitMs 1000
rled = 1
WaitMs 1000
rled = 0
WaitMs 1000
tick=0
ms=0
INTCON=0xc0                        'only PEIE and GIE set
WaitMs 2                            'let serial flush and get stable
str="$test stringW"
for i=0 to len(str)-1
    call putFifo(str(i))
next i
While 1
    If (ms.LB - tick) > 20 Then
        tick=ms.LB
        'this code gets executed 50 times per second (every 20mS)
       For i = 0 To 7
           dir=servoDir(i)                'doesn't matter if ISR happens as servoPos isn't changed by ISR
           pos=servoPos(i)
           If dir = 1 Then
              pos = pos + 40            'add 1/50th to the servo position
          Else
              pos = pos - 40             'subtract it
          Endif
          If pos < 2000 Then             'have we gone past the end?
              pos = 2000                  'yes so make it the end stop
              dir = 1                      'and turn it around
          Endif
          If pos > 4000 Then              'same for other end
              pos = 4000
              dir = 0
          Endif
          INTCON.GIE = 0                    'no interrupts
          servoPos(i)=pos
          INTCON.GIE = 1                    're enable interrupts
          servoDir(i)=dir                'servoDir not used by ISR
        Next i
    Endif
    'example code to flash an LED at 1Hz
    call getMS
    if (getMS-tickLED)>500 then            'note cannot be more than 65535 (65 seconds!!!!)
        'this code executed every 500mS which is 1Hz
        tickLED=getMS
        rLED=not rLED
    endif
Wend
End                        

function getMS() as word
    readMsFlag=0
    getMS=ms
    if readMsFlag then
        getMS=ms
    endif
end function                                         

proc putFifo(dat as byte)
    while ((fifoEnd-fifoStart) AND 0x0f)=0x0f
    wend    
    fifo(fifoEnd)=dat                                    'add data to queue
    fifoEnd=(fifoEnd+1) AND 0x0f                    'and increment pointer
End Proc    

function getFifo() as byte                            'note, doesn't test if fifo is empty
    getFifo=fifo(fifoStart)                            'so always call getFifoLen first
    fifoStart=(fifoStart+1) AND 0x0f
End Function                                                                                     

function getFifoLen() as byte
    getFifoLen=(fifoEnd-fifoStart) AND 0x0f
End Function

initSerial:
    'setup USART for 9600 baud receive
    RCSTA = %10010000
    TXSTA.BRGH = 1
    SPBRG = 207
    PIR1.RCIF = 0
    BAUDCON.BRG16 = 1
    PIE1.RCIE = 1
    PIE1.RCIE = 1
    strCount = 0
    isDone = 0
    ccpDone = 1
return

initServos:
    LATC.0 = 0                        'ensure data is low
    LATC.2 = 0                        'and clock
    For i = 0 To 7
        LATC.2 = 1                    'send positive clock edge
        servoPos(i) = i * 250 + 2000    '1ms(2000) to 1.875(1 7/8ths - 3750)ms in 1/8th mS steps
        LATC.2 = 0                    'send negative edge
        servoDir(i) = i And 1    '<<<<<<<added
    Next i
    servoCount = 8                    'cause it to reset
    CCP1CON = %1000                'will go high on interrupt - will start a 0.5mS pulse
    frame = 1000                    'start everything in 4000 cycles
return

initTMR1:
    T1CON = %00100000            'prescaler = 4
    T1CON.0 = 1                        'start timer
return

initTMR2:
    'setup 1mS interrupt = 8,000,000/16 = 500,000/10 = 50,000 set PR2=49 = 50,000/50 = 1000 = 1mS
    T2CON = %01001110                        '& h4e
    PR2 = 49                                        'This is timer 2 period register. I.E. reset after 50 clocks (0 to 49 = 50 counts)
    PIE1.TMR2IE = 1                             'timer 2 interrupts enable
return

initIO:
    TRISA = %11000000            '7=OSC, 6=OSC,
    TRISC = %11111000            '6=1-slave4431_cs, 2=74HC164 CLK, 0=74HC164 DATA 1=Serial out
    TRISC = %11111010            'CCP0 (RC2) & RC0 output
return

On High Interrupt            'go via location 0x0008
Save System
    if PIR2.CCP2IF Then
        serialCount=serialCount+1
        wordTemp.LB=CCPR2L                    'ensure next interrupt is
        wordTemp.HB=CCPR2H                    'in 208*4=832 instruction cycles
        wordTemp=wordTemp+208                '208 is 2,000,000/9600 = 104uS or the time for 1 bit at 9600 baud
        CCPR2H=wordTemp.HB                    'it's really important that the high byte gets written first
        CCPR2L=wordTemp.LB                    'write it back
        LATC.1=PORTC.1                            'ensure latch is same as current CCP output
        if ccpDone then                        'are we idle
            bitCount=0                            'yes so reset things
            length=getFifoLen()                'is anything in the fifo?
            if length>0 then                    'yes so start a new transmision
                TXbyte=getFifo()                'get byte to transmit
                CCP2CON=%1001                    'pin high and low on next interrupt = start bit
                ccpDone=false                    'tell everything we're no londer idle
                previous=0                        'set previous equal to start bit
            Endif
        else
            'we're sending a byte
            if bitCount<9 then                'have we done a complete byte
                if TXbyte.0=previous then    'no so send next bit,
                    'just need the interrupt as next bit is same as previous bit
                    CCP2CON=%1010
                else
                    'we need to flip the bit
                    if previous Then            'did we previously send a one?
                        'we need a zero next
                        previous=0                'we're sending a zero next
                        CCP2CON=%1001            'will go to zero next match
                    else
                        'we need a one next
                        previous=1                'we're sending a one next
                        CCP2CON=%1000            'will go to zero next match
                    endif
                endif
                TXbyte=shiftRight(TXbyte,1)'shift next bit to zero position
            else
                'doing the stop bits
                if bitCount<10 then
                    if previous then
                        CCP2CON=%1010        'just need interrupt
                    else
                        previous=1
                        CCP2CON=%1000        'go high next interrupt
                    endif
                else
                    ccpDone=true            'stop bits will still be generated - this happens at bitCount=10
                 Endif                            'and output will stay high until next byte
            Endif
        Endif
        bitCount=bitCount+1                'this will get reset if idle
        PIR2.CCP2IF=0
    Endif
    If PIR1.TMR2IF Then                    'Is it a timer 2 interrupt
        getMsFlag=1                            'make any read invalid
        Cnt = Cnt + 1                        'Increment count
        ms=ms+1                                'increment milliSecond
        If Cnt >= 5 Then                    'Has 5mS passed without a byte being received
            isDone=0
            strCount=0
            cnt=0
        Endif
        PIR1.TMR2IF = 0
    Endif
    If PIR1.CCP1IF Then                'has CCP1 triggered?
        wordTemp.HB = CCPR1H        'get value of CCPR1 into wordTemp
        wordTemp.LB = CCPR1L
        If CCP1CON = 0x08 Then    'have we started the 1000 cycle pulse
            CCP1CON = 0x09                'yes so end the pulse after 0.5mS
            wordTemp = wordTemp + 1000    'adding 1000 will make pulse 0.5mS long
        Else
            LATC.0 = 0                        'clear the data pin
            CCP1CON = 0x08                'No so output the timed gap
            If servoCount < 8 Then
                'still doing the servos so add remainder of time
                wordTemp = wordTemp + servoPos(servoCount)
                wordTemp = wordTemp - 1000    'knock of the 1000 (0.5mS) already elapsed
                frame = frame - servoPos(servoCount)
                servoCount = servoCount + 1
            Else
                'done all the servos so just the frame gap to do
                wordTemp = wordTemp + frame
                frame = 39000                '40,000(20mS) minus time of positive pulse(0.5mS)
                servoCount = 0            'start all over again
                LATC.0 = 1                    'will become first pulse
            Endif
        Endif
        CCPR1H = wordTemp.HB    'put value back into CCPR1
        CCPR1L = wordTemp.LB
        PIR1.CCP1IF = 0                'clear interrupt flag
    Endif
    If PIR1.RCIF Then
        cnt=0                                    'stop any timeout happening
        rec = RCREG                        'get the received character
        If RCSTA.OERR Or RCSTA.FERR Then    'neither of these should ever occur.
            RCSTA.CREN = 0            'this is kinda wishful thinking
            while PIR1.RCIF            'if any bytes in the buffer
                rec = RCREG                'throw them away
            wend
            RCSTA.CREN = 1            'as any data received is corrupt
            strCount = 0                'however, reset everything
            isDone = 0                    'and hope for the best
        Else                                    'no errors so use the data
            'the following is waiting for a "$" sign
            If strCount=0 Then    'are we already receiving
                'waiting for $        'no so wait
                If rec = "$" Then    'for $ to appear
                    buff(strCount)=rec'start receiving
                    strCount = 1        'must have been zero previously
                Endif
            Endif
            'the following gets executed if we've allready got a "$" sign
            'but not got a "W" yet.
            If isDone=0 And strCount<>0 Then
                if strCount<80 then                'only store it if there's room in the buffer
                    buff(strCount)=rec            'no so carry on storing
                    strCount = strCount + 1    'this may cause strCount to get to 80 = buffer full
                Endif
                If rec = "W" Then                    'have we got the "endOfString" character
                    isDone = 1                            'yes, so set done true
                Endif
            Endif
            If isDone=0 AND strCount>79 Then    
                'buffer has overflown
                strCount = 0
            Endif
        Endif
    Endif    'end RS232 if
Resume

I've made a call to getMS as I suspect it's never updated.

Mike.
 

Attachments

  • code 190423 0430.txt
    9.4 KB · Views: 135
To change the servo positions, remove all the code from the wait 1 loop and replace it with just setting servoPos to whatever is required and the servo should move to the desired position. Dir can be simply deleted.

Mike.
 
Hi M,
I added: Dim getmsflag As Byte

and
-------------------------------------
tickLED = getMS
rled = Not rled
Endif

Serout PORTB.0, 9600, "R= ", buff(4), CrLf

Wend
End
-----------------------------------------------
Sim looks ok
'live' no LEDs and no SERVO movement.

I'll look a bit closer tomorrow,
C
 
I added: Dim getmsflag As Byte
That should be readMsFlag which is already defined as a bit and needs changing in the ISR.
Code:
    If PIR1.TMR2IF Then                    'Is it a timer 2 interrupt
        readMsFlag=1                            'make any read invalid
        Cnt = Cnt + 1                        'Increment count
        ms=ms+1                                'increment milliSecond
        If Cnt >= 5 Then                    'Has 5mS passed without a byte being received
            isDone=0
            strCount=0
            cnt=0
        Endif
        PIR1.TMR2IF = 0
    Endif

and
-------------------------------------
tickLED = getMS
rled = Not rled
Endif
Isn't this how it already is? Except for spacing and capitalization.

The serial out should use the ISR routine not the built in soft serial.

Mike.
 
Note, the line Serout PORTB.0, 9600, "R= ", buff(4), CrLf will be executed repeatedly and take 6mS to run which will stop all other things working. Does the code work without this line?

The flashing LED code is to demonstrate how to call something after a preset time.

Mike.
 
Hi M,
Isn't this how it already is? Except for spacing and capitalization.
Yes apart from the SEROUT.

Removed DIM and changed [readMsFlag]

I used the SEROUT, to place something in the WAIT 1 LOOP, as test to see the effects of added time, in the LOOP. This is how I'm used to programming.

The flashing LED code is to demonstrate how to call something after a preset time.
This is complicated for me to see how it works, without hours of looking through it.
It may be true that I will be unable to CODE correctly enough for this type of CODE.

Results from the 'corrected' test. Same: No LED flash, and no SERVO move. (This could be my end? but the original CODE works as usual.
C
 
Results from the 'corrected' test. Same: No LED flash, and no SERVO move. (This could be my end? but the original CODE works as usual.
Are the servos "stiff" I.E. won't move, if so it shows that the pulses are being generated (by the ISR) but the position isn't being updated.

Try changing these two lines to,
If (ms.LB - tick) >= 20 Then
and,
if (getMS-tickLED)>=500 then

Note, the change is just to the comparison I.E. = to >=.

Mike.
 
Last edited:
This is complicated for me to see how it works, without hours of looking through it.
If you want something to happen every 1 second (1000mS) then you would do,
Note, second bit of code,
Code:
    if (getMS-tickLED)>=500 then            'note cannot be more than 65535 (65 seconds!!!!)
        'this code executed every 500mS which is 1Hz
        tickLED=getMS
        rLED=not rLED
    endif
    if (getMS-tickSomething)>=1000 then  'this is added after the LED code
        tickSomething=getMS
        'this will get executed every second
    endif
Obviously, tickSomething will need to be defined as a word.
If you wish to add other things then you'll need a new word variable and repeat the above code with 1000 changed to the time in mS.

I'm assuming that getMS will be a word variable after the call to getMS.


Mike.
 
Are the servos "stiff" I.E. won't move, if so it shows that the pulses are being generated (by the ISR) but the position isn't being updated.

Try changing these two lines to,
If (ms.LB - tick) >= 20 Then
and,
if (getMS-tickLED)>=500 then

Note, the change is just to the comparison I.E. = to >=.

Mike.
Hi M,
Changed the 2x lines.
Same result, 'live' no LEDS no SERVO move.

SERVOS free.
C
 
I found a few bugs,
Here's a new version,
Code:
'18F4431 32MHz XTL REMOTE_SLAVE 164 160223 2330

Define CONFIG1L = 0x00
Define CONFIG1H = 0x06    '8mHz XTL x4 =32mHz
Define CONFIG2L = 0x0c
Define CONFIG2H = 0x20
Define CONFIG3L = 0x04
Define CONFIG3H = 0x80
Define CONFIG4L = 0x80    'Set for HVP
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40

Define CLOCK_FREQUENCY = 32
Define SINGLE_DECIMAL_PLACES = 2
Define STRING_MAX_LENGTH = 20

'Define SIMULATION_WAITMS_VALUE = 1    'Comment in for SIM out for PIC

Dim wordTemp As Word
Dim servoCount As Byte
Dim i As Word
Dim servoPos(8) As Word
Dim servoDir(8) As Byte
Dim frame As Word
Dim buff(80) As Byte
Dim strCount As Byte
Dim rec As Byte
Dim isDone As Bit
Dim cnt As Byte
dim fifo(16) as byte
dim fifoStart as byte
dim fifoEnd as byte
Dim ccpDone As Bit
Dim previous as Bit
Dim TXbyte as byte
Dim bitCount as byte
Dim ms as word
Dim readMsFlag as bit
Dim tick as byte
Dim tickLED as word
Dim str as string
Dim pos as word
Dim dir as byte
Dim serialCount as byte
Dim length as byte

Symbol rled = PORTD.7
Symbol yled = PORTD.6

OSCCON = %01110000        '& h70
gosub initIO
gosub initServos
gosub initSerial
gosub initTMR1
gosub initTMR2
ccpDone=1
'Start up leds
rled = 1
WaitMs 1000
rled = 0
WaitMs 1000
rled = 1
WaitMs 1000
rled = 0
WaitMs 1000
tick=0
ms=0
INTCON=0xc0                        'only PEIE and GIE set
WaitMs 2                            'let serial flush and get stable
str="$test stringW"
for i=0 to len(str)-1
    call putFifo(str(i))
next i
While 1
    If (ms.LB - tick) > 20 Then
        tick=ms.LB
        'this code gets executed 50 times per second (every 20mS)
       For i = 0 To 7
           dir=servoDir(i)                'doesn't matter if ISR happens as servoPos isn't changed by ISR
           pos=servoPos(i)
           If dir = 1 Then
              pos = pos + 40            'add 1/50th to the servo position
          Else
              pos = pos - 40             'subtract it
          Endif
          If pos < 2000 Then             'have we gone past the end?
              pos = 2000                  'yes so make it the end stop
              dir = 1                      'and turn it around
          Endif
          If pos > 4000 Then              'same for other end
              pos = 4000
              dir = 0
          Endif
          INTCON.GIE = 0                    'no interrupts
          servoPos(i)=pos
          INTCON.GIE = 1                    're enable interrupts
          servoDir(i)=dir                'servoDir not used by ISR
        Next i
    Endif
    'example code to flash an LED at 1Hz
    call getMS
    if (getMS-tickLED)>500 then            'note cannot be more than 65535 (65 seconds!!!!)
        'this code executed every 500mS which is 1Hz
        tickLED=getMS
        rLED=not rLED
    endif
Wend
End                        

function getMS() as word
    readMsFlag=0
    getMS=ms
    if readMsFlag then
        getMS=ms
    endif
end function                                         

proc putFifo(dat as byte)
    while ((fifoEnd-fifoStart) AND 0x0f)=0x0f
    wend    
    fifo(fifoEnd)=dat                                    'add data to queue
    fifoEnd=(fifoEnd+1) AND 0x0f                    'and increment pointer
End Proc    

function getFifo() as byte                            'note, doesn't test if fifo is empty
    getFifo=fifo(fifoStart)                            'so always call getFifoLen first
    fifoStart=(fifoStart+1) AND 0x0f
End Function                                                                                     

function getFifoLen() as byte
    getFifoLen=(fifoEnd-fifoStart) AND 0x0f
End Function

initSerial:
    'setup USART for 9600 baud receive
    RCSTA = %10010000
    TXSTA.BRGH = 1
    SPBRG = 207
    PIR1.RCIF = 0
    BAUDCON.BRG16 = 1
    PIE1.RCIE = 1
    strCount = 0
    isDone = 0
    ccpDone = 1
    PIE2.CCP2IE=1
return

initServos:
    LATC.0 = 0                        'ensure data is low
    LATC.2 = 0                        'and clock
    For i = 0 To 7
        LATC.2 = 1                    'send positive clock edge
        servoPos(i) = i * 250 + 2000    '1ms(2000) to 1.875(1 7/8ths - 3750)ms in 1/8th mS steps
        LATC.2 = 0                    'send negative edge
        servoDir(i) = i And 1    '<<<<<<<added
    Next i
    servoCount = 8                    'cause it to reset
    CCP1CON = %1000                'will go high on interrupt - will start a 0.5mS pulse
    frame = 1000                    'start everything in 4000 cycles
    PIE1.CCP1IE = 1
return

initTMR1:
    T1CON = %00100000            'prescaler = 4
    T1CON.0 = 1                        'start timer
return

initTMR2:
    'setup 1mS interrupt = 8,000,000/16 = 500,000/10 = 50,000 set PR2=49 = 50,000/50 = 1000 = 1mS
    T2CON = %01001010                            'pre=16, post=10
    T2CON.TMR2ON=1                                'turn it on
    PR2 = 49                                        'This is timer 2 period register. I.E. reset after 50 clocks (0 to 49 = 50 counts)
    PIE1.TMR2IE = 1                             'timer 2 interrupts enable
return

initIO:
    TRISA = %11000000            '7=OSC, 6=OSC,
    TRISC = %11111000            '6=1-slave4431_cs, 2=74HC164 CLK, 0=74HC164 DATA 1=Serial out
    TRISC = %11111010            'CCP0 (RC2) & RC0 output
return

On High Interrupt            'go via location 0x0008
Save System
    if PIR2.CCP2IF Then
        serialCount=serialCount+1
        wordTemp.LB=CCPR2L                    'ensure next interrupt is
        wordTemp.HB=CCPR2H                    'in 208*4=832 instruction cycles
        wordTemp=wordTemp+208                '208 is 2,000,000/9600 = 104uS or the time for 1 bit at 9600 baud
        CCPR2H=wordTemp.HB                    'it's really important that the high byte gets written first
        CCPR2L=wordTemp.LB                    'write it back
        LATC.1=PORTC.1                            'ensure latch is same as current CCP output
        if ccpDone then                        'are we idle
            bitCount=0                            'yes so reset things
            length=getFifoLen()                'is anything in the fifo?
            if length>0 then                    'yes so start a new transmision
                TXbyte=getFifo()                'get byte to transmit
                CCP2CON=%1001                    'pin high and low on next interrupt = start bit
                ccpDone=false                    'tell everything we're no londer idle
                previous=0                        'set previous equal to start bit
            Endif
        else
            'we're sending a byte
            if bitCount<9 then                'have we done a complete byte
                if TXbyte.0=previous then    'no so send next bit,
                    'just need the interrupt as next bit is same as previous bit
                    CCP2CON=%1010
                else
                    'we need to flip the bit
                    if previous Then            'did we previously send a one?
                        'we need a zero next
                        previous=0                'we're sending a zero next
                        CCP2CON=%1001            'will go to zero next match
                    else
                        'we need a one next
                        previous=1                'we're sending a one next
                        CCP2CON=%1000            'will go to zero next match
                    endif
                endif
                TXbyte=shiftRight(TXbyte,1)'shift next bit to zero position
            else
                'doing the stop bits
                if bitCount<10 then
                    if previous then
                        CCP2CON=%1010        'just need interrupt
                    else
                        previous=1
                        CCP2CON=%1000        'go high next interrupt
                    endif
                else
                    ccpDone=true            'stop bits will still be generated - this happens at bitCount=10
                 Endif                            'and output will stay high until next byte
            Endif
        Endif
        bitCount=bitCount+1                'this will get reset if idle
        PIR2.CCP2IF=0
    Endif
    If PIR1.TMR2IF Then                    'Is it a timer 2 interrupt
        getMsFlag=1                            'make any read invalid
        Cnt = Cnt + 1                        'Increment count
        ms=ms+1                                'increment milliSecond
        If Cnt >= 5 Then                    'Has 5mS passed without a byte being received
            isDone=0
            strCount=0
            cnt=0
        Endif
        PIR1.TMR2IF = 0
    Endif
    If PIR1.CCP1IF Then                'has CCP1 triggered?
        wordTemp.HB = CCPR1H        'get value of CCPR1 into wordTemp
        wordTemp.LB = CCPR1L
        If CCP1CON = 0x08 Then    'have we started the 1000 cycle pulse
            CCP1CON = 0x09                'yes so end the pulse after 0.5mS
            wordTemp = wordTemp + 1000    'adding 1000 will make pulse 0.5mS long
        Else
            LATC.0 = 0                        'clear the data pin
            CCP1CON = 0x08                'No so output the timed gap
            If servoCount < 8 Then
                'still doing the servos so add remainder of time
                wordTemp = wordTemp + servoPos(servoCount)
                wordTemp = wordTemp - 1000    'knock of the 1000 (0.5mS) already elapsed
                frame = frame - servoPos(servoCount)
                servoCount = servoCount + 1
            Else
                'done all the servos so just the frame gap to do
                wordTemp = wordTemp + frame
                frame = 39000                '40,000(20mS) minus time of positive pulse(0.5mS)
                servoCount = 0            'start all over again
                LATC.0 = 1                    'will become first pulse
            Endif
        Endif
        CCPR1H = wordTemp.HB    'put value back into CCPR1
        CCPR1L = wordTemp.LB
        PIR1.CCP1IF = 0                'clear interrupt flag
    Endif
    If PIR1.RCIF Then
        cnt=0                                    'stop any timeout happening
        rec = RCREG                        'get the received character
        If RCSTA.OERR Or RCSTA.FERR Then    'neither of these should ever occur.
            RCSTA.CREN = 0            'this is kinda wishful thinking
            while PIR1.RCIF            'if any bytes in the buffer
                rec = RCREG                'throw them away
            wend
            RCSTA.CREN = 1            'as any data received is corrupt
            strCount = 0                'however, reset everything
            isDone = 0                    'and hope for the best
        Else                                    'no errors so use the data
            'the following is waiting for a "$" sign
            If strCount=0 Then    'are we already receiving
                'waiting for $        'no so wait
                If rec = "$" Then    'for $ to appear
                    buff(strCount)=rec'start receiving
                    strCount = 1        'must have been zero previously
                Endif
            Endif
            'the following gets executed if we've allready got a "$" sign
            'but not got a "W" yet.
            If isDone=0 And strCount<>0 Then
                if strCount<80 then                'only store it if there's room in the buffer
                    buff(strCount)=rec            'no so carry on storing
                    strCount = strCount + 1    'this may cause strCount to get to 80 = buffer full
                Endif
                If rec = "W" Then                    'have we got the "endOfString" character
                    isDone = 1                            'yes, so set done true
                Endif
            Endif
            If isDone=0 AND strCount>79 Then    
                'buffer has overflown
                strCount = 0
            Endif
        Endif
    Endif    'end RS232 if
Resume

The bugs I found will explain the not working parts.

Mike.
 

Attachments

  • code 190423 1830.txt
    9.4 KB · Views: 137
Hi M,
#254 test.
Same result, No Leds, SERVOs free.

If we go back to this CODE:
18F4431 32MHz XTL PCB9 REMOTE_SLAVE GPS_SERVO 190423 0900

Which fills the BUFFER with GPS DATA (In SIM so should work) and moves the SERVOs.
I have now removed all CODE from the WAIT 1 LOOP, and added a SEROUT ( I expect timing consequences} also a ServoPos(0) =(Between 2000 and 4000)
I get the LEDS flash and the SERVOs are stiff, but don't change with the change of number.

If we work through this CODE and change as little as possible, I can perhaps follow.
C
Code:
'18F4431 32MHz XTL PCB9 REMOTE_SLAVE GPS_SERVO 190423 0900

Define CONFIG1L = 0x00
Define CONFIG1H = 0x06  '8mHz XTL x4 =32mHz
Define CONFIG2L = 0x0c
Define CONFIG2H = 0x20
Define CONFIG3L = 0x04
Define CONFIG3H = 0x80
Define CONFIG4L = 0x80  'Set for HVP
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40

Define CLOCK_FREQUENCY = 32
Define SINGLE_DECIMAL_PLACES = 2
Define STRING_MAX_LENGTH = 20

'Define SIMULATION_WAITMS_VALUE = 1  'Comment in for SIM out for PIC

Dim wordTemp As Word
Dim ServoCount As Byte
Dim i As Word
Dim ServoPos(8) As Word
Dim servoDir(8) As Byte
Dim frame As Word
Dim gpsbuf(80) As Byte
Dim strCount As Byte
Dim rec As Byte
Dim isDone As Bit
Dim s2m(50) As Byte
Dim pos As Word
Dim dir As Byte

Symbol rled = PORTD.7

OSCCON = %01110000  '& h70
TRISA = %11000000  '7=OSC, 6=OSC,
TRISB = %00000000  '0=SEROUT
TRISC = %11110010  '6=1-slave4431_cs, 3=74HC164 MR, 2=74HC164 CLK, 0=74HC164 DATA
TRISD = %00000000
LATC.0 = 0  'ensure data is low
LATC.2 = 0  'and clock
LATC.3 = 1  'Master reset HIGH for run.

For i = 0 To 7
LATC.2 = 1  'send positive clock edge
ServoPos(i) = i * 250 + 2000  '1ms(2000) to 1.875(1 7/8ths - 3750)ms in 1/8th mS steps
LATC.2 = 0  'send negative edge
servoDir(i) = i And 1
Next i

'Start up led
rled = 1
WaitMs 1000
rled = 0
WaitMs 1000
rled = 1
WaitMs 1000
rled = 0
WaitMs 1000

'TRISC = %11111010  'CCP0 (RC2) & RC0 output
ServoCount = 8  'cause it to reset
T1CON = %00100000  'prescaler = 4
T1CON.0 = 1  'start timer
CCP1CON = %1000  'will go high on interrupt - will start a 0.5mS pulse
frame = 1000  'start everything in 4000 cycles
strCount = 0
isDone = 0
'setup USART for 9600 baud receive
RCSTA = %10010000
TXSTA.BRGH = 1
BAUDCON.BRG16 = 1
SPBRG = 207
PIR1.RCIF = 0
PIE1.RCIE = 1
PIE1.CCP1IE = 1
INTCON.PEIE = 1
INTCON.GIE = 1

While 1  '\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\

ServoPos(0) = 2000  '<<<<<<<
   
Serout PORTB.0, 9600, "$ R W ", gpsbuf(0), gpsbuf(3), gpsbuf(44), CrLf

Wend

End                                              

On High Interrupt  'go via location 0x0008
Save System

If PIR1.CCP1IF Then  'has CCP1 triggered?
    wordTemp.HB = CCPR1H  'get value of CCPR1 into wordTemp
    wordTemp.LB = CCPR1L
    If CCP1CON = 0x08 Then  'have we started the 1000 cycle pulse
        CCP1CON = 0x09  'yes so end the pulse after 0.5mS
        wordTemp = wordTemp + 1000  'adding 1000 will make pulse 0.5mS long
    Else
        LATC.0 = 0  'clear the data pin
        CCP1CON = 0x08  'No so output the timed gap
        If ServoCount < 8 Then
            'still doing the servos so add remainder of time
            wordTemp = wordTemp + ServoPos(ServoCount)
            wordTemp = wordTemp - 1000  'knock of the 1000 (0.5mS) already elapsed
            frame = frame - ServoPos(ServoCount)
            ServoCount = ServoCount + 1
        Else
            'done all the servos so just the frame gap to do
            wordTemp = wordTemp + frame
            frame = 39000  '40,000(20mS) minus time of positive pulse(0.5mS)
            ServoCount = 0  'start all over again
            LATC.0 = 1  'will become first pulse (is data pin of shift register)
        Endif
    Endif
        CCPR1H = wordTemp.HB  'put value back into CCPR1
        CCPR1L = wordTemp.LB
        PIR1.CCP1IF = 0  'clear interrupt flag
Endif

If PIR1.RCIF Then
    rec = RCREG  'get the received character
    If RCSTA.OERR Or RCSTA.FERR Then  'neither of these should ever occur.
            RCSTA.CREN = 0  'this is kinda wishful thinking
        If PIR1.RCIF Then
            rec = RCREG
        Endif
        RCSTA.CREN = 1  'as any data received is corrupt
        strCount = 0  'however, reset everything
        isDone = 0  'and hope for the best
    Else  'no errors so use the data
        If strCount = 0 And isDone = 0 Then  'are we already receiving
                'waiting for $           'no so wait
            If rec = "$" Then  'for $ to appear
                gpsbuf(strCount) = rec  'start receiving
               
                s2m(0) = gpsbuf(0)
                strCount = strCount + 1
            Endif
        Else
            If isDone = 0 And strCount < 79 Then  'have we collected a full string?
                gpsbuf(strCount) = rec  'no so carry on storing
                strCount = strCount + 1
                If rec = "W" Then  'have we got the "endOfString" character
                    isDone = 1  'yes, so set done true
                    'put break here
                Endif
            Else
                If isDone = 0 Then
                    'still waiting to start or buffer overflow
                    strCount = 0
                Endif
            Endif
        Endif
    Endif
Endif  'end RS232 if
Resume
 
Last edited:
I get the LEDS flash and the SERVOs are stiff, but don't change with the change of number.
What flashing are the LEDs doing? Is it just the startup flashing or are you seeing the 1Hz flash?
The servos being stiff means they are getting pulses but are not moving because the value of servoPos(0) isn't changing but staying as 2000.

I'll have another check in the morning, try to figure out what's wrong.

Mike.
 
What flashing are the LEDs doing? Is it just the startup flashing or are you seeing the 1Hz flash?
The servos being stiff means they are getting pulses but are not moving because the value of servoPos(0) isn't changing but staying as 2000.

I'll have another check in the morning, try to figure out what's wrong.

Mike.
Hi M,
#255 CODE:
I understand why the SERVOS are stiff, and with this CODE they are, but trying different 'servoPos(0)' numbers doesn't move them.

The LEDs flash at START and the WAITMS 1 LOOP LEDS, only

The serial out should use the ISR routine not the built in soft serial.
How can I see what is output?
C
 
Last edited:
Hi M,
#255 CODE
I was at the wrong end of the SERVO PINS, so was setting servoPos(0) instead of servoPos(7).
Now they move and hold :)

The [ Serout PORTB.0, 9600, "$ R W ", #gpsbuf(0), #gpsbuf(3), #gpsbuf(44), CrLf ] shows the "S R W ", but not the result of the gpsbuf() memories.
C
 
Serout will print no matter what, even before data arrives, it is in an infinite continuous loop. You should print with Serout only when isDone = 1.
Also, if you have any overrun or framing error, the isDone and strCount will always be zero.
 
Can we try this code?
Code:
'18F4431 32MHz XTL REMOTE_SLAVE 164 160223 2330

Define CONFIG1L = 0x00
Define CONFIG1H = 0x06    '8mHz XTL x4 =32mHz
Define CONFIG2L = 0x0c
Define CONFIG2H = 0x20
Define CONFIG3L = 0x04
Define CONFIG3H = 0x80
Define CONFIG4L = 0x80    'Set for HVP
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40

Define CLOCK_FREQUENCY = 32
Define SINGLE_DECIMAL_PLACES = 2
Define STRING_MAX_LENGTH = 20

'Define SIMULATION_WAITMS_VALUE = 1    'Comment in for SIM out for PIC

Dim wordTemp As Word
Dim servoCount As Byte
Dim i As Word
Dim servoPos(8) As Word
Dim servoDir(8) As Byte
Dim frame As Word
Dim buff(80) As Byte
Dim strCount As Byte
Dim rec As Byte
Dim isDone As Bit
Dim cnt As Byte
dim fifo(16) as byte
dim fifoStart as byte
dim fifoEnd as byte
Dim ccpDone As Bit
Dim previous as Bit
Dim TXbyte as byte
Dim bitCount as byte
Dim ms as word
Dim readMsFlag as bit
Dim tick as byte
Dim tickLED as word
Dim str as string
Dim pos as word
Dim dir as byte
Dim serialCount as byte
Dim length as byte

Symbol rled = PORTD.7
Symbol yled = PORTD.6

OSCCON = %01110000        '& h70
gosub initIO
gosub initServos
gosub initSerial
gosub initTMR1
gosub initTMR2
ccpDone=1
'Start up leds
rled = 1
WaitMs 1000
rled = 0
WaitMs 1000
rled = 1
WaitMs 1000
rled = 0
WaitMs 1000
tick=0
ms=0
INTCON=0xc0                        'only PEIE and GIE set
WaitMs 2                            'let serial flush and get stable
str="$test stringW"
for i=0 to len(str)-1
    call putFifo(str(i))
next i
While 1
    If (ms.LB - tick) > 20 Then
        tick=ms.LB
        'this code gets executed 50 times per second (every 20mS)
       For i = 0 To 7
           dir=servoDir(i)                'doesn't matter if ISR happens as servoPos isn't changed by ISR
           pos=servoPos(i)
           If dir = 1 Then
              pos = pos + 40            'add 1/50th to the servo position
          Else
              pos = pos - 40             'subtract it
          Endif
          If pos < 2000 Then             'have we gone past the end?
              pos = 2000                  'yes so make it the end stop
              dir = 1                      'and turn it around
          Endif
          If pos > 4000 Then              'same for other end
              pos = 4000
              dir = 0
          Endif
          INTCON.GIE = 0                    'no interrupts
          servoPos(i)=pos
          INTCON.GIE = 1                    're enable interrupts
          servoDir(i)=dir                'servoDir not used by ISR
        Next i
    Endif
    'example code to flash an LED at 1Hz
    call getMS
    if (getMS-tickLED)>500 then            'note cannot be more than 65535 (65 seconds!!!!)
        'this code executed every 500mS which is 1Hz
        tickLED=getMS
        rLED= NOT rLED
    endif
Wend
End                        

function getMS() as word
    readMsFlag=0
    getMS=ms
    if readMsFlag then
        getMS=ms
    endif
end function                                         

proc putFifo(dat as byte)
    while ((fifoEnd-fifoStart) AND 0x0f)=0x0f
    wend    
    fifo(fifoEnd)=dat                                    'add data to queue
    fifoEnd=(fifoEnd+1) AND 0x0f                    'and increment pointer
End Proc    

function getFifo() as byte                            'note, doesn't test if fifo is empty
    getFifo=fifo(fifoStart)                            'so always call getFifoLen first
    fifoStart=(fifoStart+1) AND 0x0f
End Function                                                                                     

function getFifoLen() as byte
    getFifoLen=(fifoEnd-fifoStart) AND 0x0f
End Function

initSerial:
    'setup USART for 9600 baud receive
    RCSTA = %10010000
    TXSTA.BRGH = 1
    BAUDCON.BRG16 = 1
    SPBRG = 207
    PIR1.RCIF = 0
    PIE1.RCIE = 1
    strCount = 0
    isDone = 0
    ccpDone = 1
    PIE2.CCP2IE=1
return

initServos:
    For i = 0 To 7
        servoPos(i) = i * 250 + 2000    '1ms(2000) to 1.875(1 7/8ths - 3750)ms in 1/8th mS steps
        servoDir(i) = i And 1    '<<<<<<<added
    Next i
    servoCount = 8                    'cause it to reset
    CCP1CON = %1000                'will go high on interrupt - will start a 0.5mS pulse
    frame = 1000                    'start everything in 4000 cycles
    PIE1.CCP1IE = 1
return

initTMR1:
    T1CON = %00100000            'prescaler = 4
    T1CON.0 = 1                    'start timer
return

initTMR2:
    'setup 1mS interrupt = 8,000,000/16 = 500,000/10 = 50,000 set PR2=49 = 50,000/50 = 1000 = 1mS
    T2CON = %01001010                            'pre=16, post=10
    T2CON.TMR2ON=1                                'turn it on
    PR2 = 49                                        'This is timer 2 period register. I.E. reset after 50 clocks (0 to 49 = 50 counts)
    PIE1.TMR2IE = 1                             'timer 2 interrupts enable
return

initIO:
    TRISA = %11000000            '7=OSC, 6=OSC,
    TRISB    = %00000000
    TRISC = %11111000            '6=1-slave4431_cs, 2=74HC164 CLK, 0=74HC164 DATA 1=Serial out
    TRISD = %00000000
    LATC.3=0
    LATC.3=1
return

On High Interrupt            'go via location 0x0008
Save System
    if PIR2.CCP2IF Then
        serialCount=serialCount+1
        wordTemp.LB=CCPR2L                    'ensure next interrupt is
        wordTemp.HB=CCPR2H                    'in 208*4=832 instruction cycles
        wordTemp=wordTemp+208                '208 is 2,000,000/9600 = 104uS or the time for 1 bit at 9600 baud
        CCPR2H=wordTemp.HB                    'it's really important that the high byte gets written first
        CCPR2L=wordTemp.LB                    'write it back
        LATC.1=PORTC.1                            'ensure latch is same as current CCP output
        if ccpDone then                        'are we idle
            bitCount=0                            'yes so reset things
            length=getFifoLen()                'is anything in the fifo?
            if length>0 then                    'yes so start a new transmision
                TXbyte=getFifo()                'get byte to transmit
                CCP2CON=%1001                    'pin high and low on next interrupt = start bit
                ccpDone=false                    'tell everything we're no londer idle
                previous=0                        'set previous equal to start bit
            Endif
        else
            'we're sending a byte
            if bitCount<9 then                'have we done a complete byte
                if TXbyte.0=previous then    'no so send next bit,
                    'just need the interrupt as next bit is same as previous bit
                    CCP2CON=%1010
                else
                    'we need to flip the bit
                    if previous Then            'did we previously send a one?
                        'we need a zero next
                        previous=0                'we're sending a zero next
                        CCP2CON=%1001            'will go to zero next match
                    else
                        'we need a one next
                        previous=1                'we're sending a one next
                        CCP2CON=%1000            'will go to zero next match
                    endif
                endif
                TXbyte=shiftRight(TXbyte,1)'shift next bit to zero position
            else
                'doing the stop bits
                if bitCount<10 then
                    if previous then
                        CCP2CON=%1010        'just need interrupt
                    else
                        previous=1
                        CCP2CON=%1000        'go high next interrupt
                    endif
                else
                    ccpDone=true            'stop bits will still be generated - this happens at bitCount=10
                 Endif                            'and output will stay high until next byte
            Endif
        Endif
        bitCount=bitCount+1                'this will get reset if idle
        PIR2.CCP2IF=0
    Endif
    If PIR1.TMR2IF Then                        'Is it a timer 2 interrupt
        getMsFlag=1                                'make any read invalid
        Cnt = Cnt + 1                            'Increment count
        ms=ms+1                                    'increment milliSecond
        If Cnt >= 5 AND NOT isDone Then    'Has 5mS passed without a byte being received
            isDone=0
            strCount=0
            cnt=0
        Endif
        PIR1.TMR2IF = 0
    Endif
    If PIR1.CCP1IF Then                'has CCP1 triggered?
        wordTemp.HB = CCPR1H            'get value of CCPR1 into wordTemp
        wordTemp.LB = CCPR1L
        If CCP1CON = 0x08 Then        'have we started the 1000 cycle pulse
            CCP1CON = 0x09                'yes so end the pulse after 0.5mS
            wordTemp = wordTemp + 1000    'adding 1000 will make pulse 0.5mS long
        Else
            LATC.0 = 0                    'clear the data pin
            CCP1CON = 0x08                'No so output the timed gap
            If servoCount < 8 Then
                'still doing the servos so add remainder of time
                wordTemp = wordTemp + servoPos(servoCount)
                wordTemp = wordTemp - 1000    'knock of the 1000 (0.5mS) already elapsed
                frame = frame - servoPos(servoCount)
                servoCount = servoCount + 1
            Else
                'done all the servos so just the frame gap to do
                wordTemp = wordTemp + frame
                frame = 39000            '40,000(20mS) minus time of positive pulse(0.5mS)
                servoCount = 0            'start all over again
                LATC.0 = 1                'will become first pulse
            Endif
        Endif
        CCPR1H = wordTemp.HB            'put value back into CCPR1
        CCPR1L = wordTemp.LB
        PIR1.CCP1IF = 0                'clear interrupt flag
    Endif
    If PIR1.RCIF Then
        cnt=0                                'stop any timeout happening
        rec = RCREG                        'get the received character
        If RCSTA.OERR Or RCSTA.FERR Then    'neither of these should ever occur.
            RCSTA.CREN = 0                'this is kinda wishful thinking
            while PIR1.RCIF            'if any bytes in the buffer
                rec = RCREG                'throw them away
            wend
            RCSTA.CREN = 1                'as any data received is corrupt
            strCount = 0                'however, reset everything
            isDone = 0                    'and hope for the best
        Else                                'no errors so use the data
            'the following is waiting for a "$" sign
            If strCount=0 Then        'are we already receiving
                'waiting for $            'no so wait
                If rec = "$" Then        'for $ to appear
                    buff(strCount)=rec'start receiving
                    strCount = 1        'must have been zero previously
                Endif
            Endif
            'the following gets executed if we've allready got a "$" sign
            'but not got a "W" yet.
            If isDone=0 And strCount<>0 Then
                if strCount<80 then    'only store it if there's room in the buffer
                    buff(strCount)=rec    'no so carry on storing
                    strCount = strCount + 1    'this may cause strCount to get to 80 = buffer full
                Endif
                If rec = "W" Then        'have we got the "endOfString" character
                    isDone = 1            'yes, so set done true
                Endif
            Endif
            If isDone=0 AND strCount>79 Then    
                'buffer has overflown
                strCount = 0
            Endif
        Endif
    Endif    'end RS232 if
Resume
Do the servos move?
Does the red (assuming rLED = red) LED flash at 1Hz?

Mike.
 

Attachments

  • code 200423 1130.txt
    9.3 KB · Views: 133

Latest threads

New Articles From Microcontroller Tips

Back
Top