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

I'm assuming that the sentence received from the GPS is parsed and the result is used to set the servo positions.

Mike.
Hi M,
A quick explanation:
BASE has PIC 1 and 2
PIC2 reads the BASE GPS and QEI and sends it to PIC1 via SPI
PIC1 uses PIC2 DATA plus it's own peripherals to produce RC control signals and transmits them.

REMOTE has PIC 3 and 4
PIC4 reads the REMOTE GPS which is sent to PIC3 via SPI
PIC3 reads the RC control signals plus, uses PIC4 DATA plus it's own peripherals, and calculates what to send to the SERVO/MOTORS via SPI.

The calculations will be able to be designed, once the GPS, SERVO and SPI has been done.

(If there are mistakes, put it down to memorising it all in one go)
C
 
Hi,
I've been checking the SERVO moving backwards and forwards CODE
and the GPS parse CODE, which is outputting the NMEA sentence, to my computer screen, so I know both are working, and posted here as latest.
(There are a few errors, but they are minor, and don't affect anything important.)
C
 

Attachments

  • 18F4431 32MHz XTL REMOTE_SLAVE 164 160223 2330.bas
    4.6 KB · Views: 146
  • 18F4431 32MHz XTL REMOTE_SLAVE GPS_SERVO 200223 1400.bas
    19 KB · Views: 157
Hi,
In the GPS CODE #44, there are GUARDS, the one for GPS is in case the GPS looses signal. The GUARD waits ms for a signal, then if not, it RESUMES the back to the loop.
Trying to understand the differences between the SERVO and GPS CODE, using M's SERVO type CODE for the GPS, if the signal was lost, I presume it simply wouldn't INTERRUPT, and the program carries on till a signal is received.
Is this correct?
C
 
The GPS (USART) code simply waits for a $ sign then writes all received bytes to the buffer (buff) until a "W" is received and then sets the isDone flag. A timer2 ISR could be added that resets the USART (actually buffer stuff) if no byte is received for (say) 5mS. Obviously, it would not do this reset if a valid sentence has been received.

Is this what you're thinking?

Mike.
 
The GPS (USART) code simply waits for a $ sign then writes all received bytes to the buffer (buff) until a "W" is received and then sets the isDone flag. A timer2 ISR could be added that resets the USART (actually buffer stuff) if no byte is received for (say) 5mS. Obviously, it would not do this reset if a valid sentence has been received.

Is this what you're thinking?

Mike.
Hi M,
I think this is what I'm thinkingo_O

If you check the GPS CODE #44 you will see BUF_DONE, which I think is the same as what you describe, so to me it looks like the GPS CODE is similar to yours, and is working fine whenever it's been used. If it changes, then the CODE on PIC 1 and 2 will also need changing, so I would change as little as possible. The GPS guards were written so they can be adjusted, for fine tuning, as it develops.

I don't want to volunteer you, to write it, as I will have a go, but let me know if you are ok with writing it, and I won't compete ;)
C
 
Here's some code with timer 2 used to make a 1mS interrupt and if a byte hasn't been received after 5mS then it resets the receiving 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


OSCCON = %01110000    '& h70
TRISA = %11000000     '7=OSC, 6=OSC,
TRISC = %11111010     '6=1-slave4431_cs, 2=74HC164 CLK, 0=74HC164 DATA
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
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
'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 enableINTCON.PEIE = 1
INTCON.GIE = 1
While 1
    'adjust servo positions here
    While servoCount = 0      'wait for 20mS to pass (=1/50th of a second)
    Wend
    While servoCount <> 0
    Wend
    For i = 0 To 7
        INTCON.GIE = 0
        If servoDir(i) = 1 Then
            servoPos(i)=servoPos(i)+40  'add 1/50th to the servo position
        Else
            servoPos(i)=servoPos(i)-40  'subtract it
        Endif
        If servoPos < 2000 Then 'have we gone past the end?
            servoPos(i) = 2000    'yes so make it the end stop
            servoDir(i) = 1       'and turn it around
        Endif
        If servoPos(i)>4000 Then'same for other end
            servoPos(i) = 4000
            servoDir(i) = 0
        Endif
        INTCON.GIE = 1
    Next i
  If isDone then
    'deal with the received sentence here
    idDone=0
  Endif
Wend
End                                              

On High Interrupt  'go via location 0x0008
Save System
  If PIE1.TMR2IE And PIR1.TMR2IF Then  'Is it a timer 2 interrupt
    Cnt = Cnt + 1     'Increment count
    If Cnt >= 5 Then  'Has 5mS passed without a byte being received
      ifDone=0
      strCount=0
      cnt=0
    Endif
      PIR1.TMR2IF = 0  ' 0 = No TMR2 to PR2 match occurred
  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
    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'<<<<<<<<<<<<<<<<<<<<<<<<
          Buff(strCount)=rec'start receiving
          strCount = strCount + 1
        Endif
      Else
        If isDone = 0 And strCount < 79 Then  'have we collected a full string?
          Buff(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
Ahhhhhhhh, just noticed your code doesn't have else if which changes what it does. Does it have a switch type function?

Mike.
 
Here's a version with the lack of "Elseif" fixed,
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


OSCCON = %01110000    '& h70
TRISA = %11000000     '7=OSC, 6=OSC,
TRISC = %11111010     '6=1-slave4431_cs, 2=74HC164 CLK, 0=74HC164 DATA
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
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
'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 enableINTCON.PEIE = 1
INTCON.GIE = 1
While 1
    'adjust servo positions here
    While servoCount = 0      'wait for 20mS to pass (=1/50th of a second)
    Wend
    While servoCount <> 0
    Wend
    For i = 0 To 7
        INTCON.GIE = 0
        If servoDir(i) = 1 Then
            servoPos(i)=servoPos(i)+40  'add 1/50th to the servo position
        Else
            servoPos(i)=servoPos(i)-40  'subtract it
        Endif
        If servoPos < 2000 Then 'have we gone past the end?
            servoPos(i) = 2000    'yes so make it the end stop
            servoDir(i) = 1       'and turn it around
        Endif
        If servoPos(i)>4000 Then'same for other end
            servoPos(i) = 4000
            servoDir(i) = 0
        Endif
        INTCON.GIE = 1
    Next i
  If isDone then
    'deal with the received sentence here
    idDone=0
  Endif
Wend
End                                               

On High Interrupt  'go via location 0x0008
Save System
  If PIE1.TMR2IE And PIR1.TMR2IF Then  'Is it a timer 2 interrupt
    Cnt = Cnt + 1     'Increment count
    If Cnt >= 5 Then  'Has 5mS passed without a byte being received
      ifDone=0
      strCount=0
      cnt=0
    Endif
      PIR1.TMR2IF = 0  ' 0 = No TMR2 to PR2 match occurred
  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
    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'<<<<<<<<<<<<<<<<<<<<<<<<
          buff(strCount)=rec'start receiving
          strCount = strCount + 1
        Endif
      Endif
      If isDone = 0 And strCount < 79 Then  'have we collected a full string?
        Buff(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
      Endif
      If isDone=0 AND strCount=79 Then  
        'buffer has overflown
        strCount = 0
      Endif
    Endif
  Endif  'end RS232 if
Resume

Mike.
 
Whoops, the lack of elseif means that the buffer can still overflow so this code takes care of that (I think),
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


OSCCON = %01110000    '& h70
TRISA = %11000000     '7=OSC, 6=OSC,
TRISC = %11111010     '6=1-slave4431_cs, 2=74HC164 CLK, 0=74HC164 DATA
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
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
'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 enableINTCON.PEIE = 1
INTCON.GIE = 1
While 1
    'adjust servo positions here
    While servoCount = 0      'wait for 20mS to pass (=1/50th of a second)
    Wend
    While servoCount <> 0
    Wend
    For i = 0 To 7
        INTCON.GIE = 0
        If servoDir(i) = 1 Then
            servoPos(i)=servoPos(i)+40  'add 1/50th to the servo position
        Else
            servoPos(i)=servoPos(i)-40  'subtract it
        Endif
        If servoPos < 2000 Then 'have we gone past the end?
            servoPos(i) = 2000    'yes so make it the end stop
            servoDir(i) = 1       'and turn it around
        Endif
        If servoPos(i)>4000 Then'same for other end
            servoPos(i) = 4000
            servoDir(i) = 0
        Endif
        INTCON.GIE = 1
    Next i
  If isDone then
    'deal with the received sentence here
    idDone=0
  Endif
Wend
End                                              

On High Interrupt  'go via location 0x0008
Save System
  If PIE1.TMR2IE And PIR1.TMR2IF Then  'Is it a timer 2 interrupt
    Cnt = Cnt + 1     'Increment count
    If Cnt >= 5 Then  'Has 5mS passed without a byte being received
      ifDone=0
      strCount=0
      cnt=0
    Endif
      PIR1.TMR2IF = 0  ' 0 = No TMR2 to PR2 match occurred
  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
    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'<<<<<<<<<<<<<<<<<<<<<<<<
          buff(strCount)=rec'start receiving
          strCount = strCount + 1
        Endif
      Endif
      If isDone=0 And strCount<>0 Then  'have we collected a full string?
        if strCount<80 then
          buff(strCount)=rec  'no so carry on storing
          strCount = strCount + 1
        Endif
        If rec = "W" Then   'have we got the "endOfString" character'<<<<<<<<<<<<
          isDone = 1        'yes, so set done true
          'put break here
        Endif
      Endif
      If isDone=0 AND strCount>78 Then 
        'buffer has overflown
        strCount = 0
      Endif
    Endif
  Endif  'end RS232 if
Resume

Mike.
 
Note, I modified one line in the above,
if strCount<79 then
was changed to
if strCount<80 then


Mike.
Hi M,
Can you check [ ifdone ] [ isdone ]

EDIT: I hink I've worked it out.
Another ENDIF needed. perhaps more, so looking for it (Got to re-indent it all first :( )
C
 
Last edited:
I don't seem to have any ifDone, only isDone.
Here's a picture of the USART code in notepad++ (might be a good idea for you to get this, it's free),
USART.png

Note, all the If Endifs line up.
Note, you can cut/paste the above code (in #50) straight into Notepad++ and keep all the indenting.

Mike.
 
Just realized a possible error, strCount can get to 80 which could cause problems.

Here's the latest and (hopefully) correct 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


OSCCON = %01110000    '& h70
TRISA = %11000000     '7=OSC, 6=OSC,
TRISC = %11111010     '6=1-slave4431_cs, 2=74HC164 CLK, 0=74HC164 DATA
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
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
'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 enableINTCON.PEIE = 1
INTCON.GIE = 1
While 1
    'adjust servo positions here
    While servoCount = 0      'wait for 20mS to pass (=1/50th of a second)
    Wend
    While servoCount <> 0
    Wend
    For i = 0 To 7
        INTCON.GIE = 0
        If servoDir(i) = 1 Then
            servoPos(i)=servoPos(i)+40  'add 1/50th to the servo position
        Else
            servoPos(i)=servoPos(i)-40  'subtract it
        Endif
        If servoPos < 2000 Then 'have we gone past the end?
            servoPos(i) = 2000    'yes so make it the end stop
            servoDir(i) = 1       'and turn it around
        Endif
        If servoPos(i)>4000 Then'same for other end
            servoPos(i) = 4000
            servoDir(i) = 0
        Endif
        INTCON.GIE = 1
    Next i
  If isDone then
    'deal with the received sentence here
    idDone=0
  Endif
Wend
End                                               

On High Interrupt  'go via location 0x0008
Save System
  If PIE1.TMR2IE And PIR1.TMR2IF Then  'Is it a timer 2 interrupt
    Cnt = Cnt + 1     'Increment count
    If Cnt >= 5 Then  'Has 5mS passed without a byte being received
      ifDone=0
      strCount=0
      cnt=0
    Endif
      PIR1.TMR2IF = 0  ' 0 = No TMR2 to PR2 match occurred
  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
          'put break here
        Endif
      Endif
      If isDone=0 AND strCount>79 Then  
        'buffer has overflown
        strCount = 0
      Endif
    Endif
  Endif  'end RS232 if
Resume

Mike.
 
FYI, here's a picture of the RCIF section of the interrupt with the matching if..else..endif matched with blue lines and while...wend with a red line,
RCIF.png

Hope that's useful.

Mike.
 
Last edited:
Forgot to attach the text file.

Mike.
Hi M,
Working great:)

I usually copy and paste the file, but this time I opened your file in Osh,and some was indented, but not all. I'll investigate.

It works in SIM, with of course a test NMEA sentence, so doesn't change, and live will be too fast for me to see, I'll have to wire up the analyser for a series of DATA.

Reading the SIM, I see that BUFF() goes to (45) which it should, so BUFF(46) = 0 and to the end, so the array only needs to be 45 long. This was done to keep the STRING size down for PIC memory.

Where should I put the PARSE and rest of the CODE?
C
 
So there was and still is,
ifdone.png

That's what happens when you just write code with no way to test it.
I'll leave it to you to fix this in the text file.

Mike.
 

Latest threads

Back
Top