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.

Hardware ESC 8xSERVO CONTROL on PIC (Oshonsoft BASIC)

Status
Not open for further replies.
Hi S,
Who is this addressed to?
C
Addressed to whoever was getting those strange values like 2244, 2238, etc. Whatever was calculating the ServoPos was doing interger truncation. So, I tried a test to see if it happened with the PIC18 IDE, and that truncation did not happen. However, I see later that using "i" as a Word instead of byte does fix the problem regardless.
It was just a FYI that in many cases, the initial servoPos calculation is correct, so those errant values may have been caused by something else, or a buggy compiler.
 
Addressed to whoever was getting those strange values like 2244, 2238, etc. Whatever was calculating the ServoPos was doing interger truncation. So, I tried a test to see if it happened with the PIC18 IDE, and that truncation did not happen. However, I see later that using "i" as a Word instead of byte does fix the problem regardless.
It was just a FYI that in many cases, the initial servoPos calculation is correct, so those errant values may have been caused by something else, or a buggy compiler.
Hi S,
Ok, thanks.
As you see there is a SERVO moving.
C
 
Here's some code that should get a string from the USART. Max length 80 characters and will go in Buff.
Code:
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


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
INTCON.PEIE=1
INTCON.GIE=1

While 1
  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
  'adjust servo positions here
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
      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
                Buff(StrCount) = rec      'start receiving
                StrCount = StrCount + 1
            endif
          ElseIf 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
            End If
          ElseIf done=0 then
            'still waiting to start or buffer overflow
            strCount=0
          End If
      End If
    End If              'end RS232 if
resume

Are you able to stop it on the line that says "'put break here" and see what's in Buff?

I'm sure the lines involving single characters are wrong '$' & 'W' but don't know the syntax.

Mike.
 
How often do the strings arrive and how long are they?
Do you have an example string?
Can you explain what's done with the string?

Mike.
 
Here's some code that should get a string from the USART. Max length 80 characters and will go in Buff.
Code:
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


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
INTCON.PEIE=1
INTCON.GIE=1

While 1
  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
  'adjust servo positions here
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
      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
                Buff(StrCount) = rec      'start receiving
                StrCount = StrCount + 1
            endif
          ElseIf 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
            End If
          ElseIf done=0 then
            'still waiting to start or buffer overflow
            strCount=0
          End If
      End If
    End If              'end RS232 if
resume

Are you able to stop it on the line that says "'put break here" and see what's in Buff?

I'm sure the lines involving single characters are wrong '$' & 'W' but don't know the syntax.

Mike.
Hi M,
There were a few minor errors, and maybe I corrected them?

Anyway, if correct, here's the result.
C
 

Attachments

  • #543.jpg
    #543.jpg
    199.6 KB · Views: 150
How often do the strings arrive and how long are they?
Do you have an example string?
Can you explain what's done with the string?

Mike.
Hi M,
The GPS STRINGS arrive 5/sec.

Here's the example I used in the above test: $GNRMC,162254.00,A,3723.02837,N,12159.39853,W,0.820,188.36,110706,,,A*74

The 1st section is TIME, if needed.
2nd 3rd LAT LONG.

There are a number of parameters? on this REMOTE, which are compared with the received DATA from BASE, and acted on to move it to the location and at what angle.

If you search the links I posted earlier, you'll find the GPS PARSE routine, which has extras bits in and uses the our recognised variables etc, in a BASE program posted there. What you find may change as it is being tidied up by my mate. (He's a bit busy at the moment)

It looks like this thread has been answered. So perhaps finish.

Your SERVO CODEs are much appreciated, thanks you.

I'll start another thread for adding the GPS into the existing CODE.
If you want any clarification, email or PM.
C
 
That gives a string of,
$GNRMC,162254.00,A,3723.02837,N,12159.39853,W

Does this look correct?

Does the W at the end represent West, if so it'll only work in the Western hemisphere.

Mike.
 
I'm assuming the A is Alpha meaning GMT+0
And N is North I.E. Northern hemisphere
And W is West I.E. Western hemisphere.

If so, the code could be changed to count six commas so it will work anywhere in the world.

Mike.
 
Seventh comma is after the "W". Could be used to terminate buffer, but data will still be coming in due to extra data in stream, which will be ignored of course.
There are ways to configure the NEMA datastreams (NEO GPS Utility?) so they send less extraneous data. That would reduce the amount of interrupt handling.
 
The ISR will only be a few cycles so time isn't a problem.
The buffer will need to be longer (128?) to get the whole string so the checksum can be checked.
Seems a valid string ends with 0x0d,0x0a.
Is there a limit on the number of decimal places a coordinate can have, an example I found had 11402.3291611
I.E. 114° 02.3291611'

Mike.
 
If so, the code could be changed to count six commas so it will work anywhere in the world.

Each NMEA data line from the GPS starts with a $ and ends with *HH (asterisk, two hex digit checksum) and then is terminated by carriage return, line feed; 0x0D, 0x0A.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top