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

The code will output on RC1 and the sim needs to read on RC7. Or the sim needs to do nothing exept connecting RC7 to RC1 so the output of the software Serial is fed to the RX pin.
Both of those settings were there together, maybe this caused a problem, I've now changed it to %11111010 only.
They both need to be %11111000 so RC1 is output.
Still doesn't explain how RC7 can be high.

Mike.
 
Hi M,
TRIS only needs one set-up.

Here's the CODE woith the changes I made, marked <<<<<<<<<<<<<<
I hope theu are ok.

Note the title at the top of the CODE for my benefit. Sometimes small changes are made between differnt times.

I'm afraid we loose the TAD indentures, during feeding into OSH. They seem to cause errors. If tyou need them, then I'll add them all in and post again.

C
Code:
'18F4431 32MHz XTL REMOTE_SLAVE UART_GPS 270323 1000

'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 Long
Dim tick As Long

Dim str As String

Dim serialcount As Byte  'ADDED<<<<<<<<<<<<<<<<<<<<<<
Dim length As Byte  'ADDED<<<<<<<<<<<<<<<<<<<<<<<<

OSCCON = %01110000  '& h70
Gosub initIO
Gosub initServos
Gosub initSerial
Gosub initTMR1
Gosub initTMR2  'gosun initTMR2 CHANGE<<<<<<<<<<<<<<<<<
tick = 0
ms = 0
INTCON = 0xc0  'only PEIE and GIE set
WaitMs 2  'pause(2)  'let serial flush and get stable CHANGE <<<<<<<<<<<<<<
str = "$test stringW"
For i = 0 To Len(str) - 1
Call putfifo(str(i))
Next i
While 1
'adjust servo positions here
INTCON.GIE = 0  'disable interrupts so ms can't change
If (ms - tick) > 20 Then  '50 Then CHANGE<<<<<<<<<<<<<<<
tick = ms
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
Endif
INTCON.GIE = 1
If isDone Then
'put a break here and see what's in buff.
'deal with the received sentence here
'This code can be any length but ideally less than 20mS
isDone = 0
Endif
'other code here.
Wend
End                                               

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=1-OSC, 6=1-OSC,
TRISC = %11111000  '7=1-TEST INPUT?, 6=1-slave4431_cs, 2=0-74HC164 CLK, 1=0-Serial out, 0=0-74HC164 DATA  NOTE: Only one TRISC<<<<<<<<<<
'TRISC = %11111000  '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? CHANGE<<<<<<<<<<<
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
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
 
Will have a look tomorrow, 10pm here and school tomorrow. I'll change the bits that need changing and post a new file with the tabs as I find that much easier to follow.

Mike.
 
Str is a string variable and you cannot index it like a byte array. So str(i) is not a valid string function. One should use “midstr(str,i,1)“ to extract single characters to a byte.
PS: i=1 is the first character, i cannot be zero
 
Last edited:
Hi,

Here's an old example of [ midstr ] that may help. I can see errors etc in it, but if it helps, just use it as a guide?

P.S. Check STR as STRING, as it could have been me that set it to STRING, not sure.
C
 

Attachments

  • midstr.txt
    579 bytes · Views: 220
I tried the ALL CODE. I changed a few minor lines, so it compiles, and this CODE fills the FIFO() buffer with [ "$test srtingw" ] ok.
If this is true then the mid() isn't needed as the str(n) worked as expected. Can you confirm this? It also means that the first character of a sting is zero and not one. Maybe mid is just another way to access it.

Mike.
 
If this is true then the mid() isn't needed as the str(n) worked as expected. Can you confirm this? It also means that the first character of a sting is zero and not one. Maybe mid is just another way to access it.

Mike.
Hi M,
Yes, ALL produces both strings, see top of image and bottom.

From memory:
I think [ midstr ] gets characters from a message like [ $abcdef ] and the BUFF can be used by e,g, [ X = BUFF(1) ]
C
 

Attachments

  • Variables.jpg
    192.3 KB · Views: 197
I did a quick test of STR as a string, and indexing it as STR(0), STR(1), etc. It seems to work, provided you do not let the index counter go past the string size. By default, strings are defined as 16 bytes in length no matter how much of the 16 bytes you use. If you define maximum string length longer, then you can use longer strings and "byte array index access" seems to work in this particular compiler. However, if the index goes past the string length, it will continue to return values of whatever is stored in the next variable storage location. Other than a possible compiler warning for a fixed loop counter, there are no checks at runtime to validate that the STR index pointer is valid.
On the other hand, the ASC(MIDSTR(STR,x,1)) function will also ignore an invalid index "x", but always seems to return a zero if trying to access beyond the string storage boundary.
So, either method works. I suspect the STR(i) will be faster in terms of processing cycles. While it is not really a valid BASIC syntax, it seems to work with Oshonsoft BASIC.
 
Hi S,
I'm a bit out of my depth replying, but STR(i) has been used quite a lot in my programs. Mostly for NMEA sentences. I used to retrieve the whole sentence $ to CRLF, (70ish) then for efficiency, cut it down to what I need $ to W, (44ish) which works.
From what I recall, "$abcdef" type sentences are used at the beginning of the NMEA sentence to show what it is, e,g, "NMEA RMC" STR(0) STR (1) etc.

Note I have never written these by myself, and have been written by valuable members (thanks).

C.
 
This is all very interesting and very useful (thanks both). In the above code STRING_MAX_LENGTH is set to 20 so there shouldn't be a problem as the longest string is "$test stringW" which is only 13 long.
Out of curiosity, if you define a string longer than allowed, what does len(str) return?
With STRING_MAX_LENGTH left at 16 and str="01234567890123456789" (20 long) what does len(str) return?

Mike.
 
Hi M,
I'll answer this tomorrow! I'm sure I've seen LEN = more than STRING_MAX_LENGTH.


Note whatever the 'max string length' is set to means all strings in the CODE have space this long, (I think) so if there are a lot of even small strings it uses a lot of space.
This is why I shortened the NMEA sentences to app 44.

I'm pretty sure I also found out why RC7 stays on! It's because (I think) the simulator SW interface RX is set to that pin.

My bottom eye lids are going upwards to meet the top ones, so that's it tonight.
C
 
Compiler rejects the longer str= statement, stating that it is too long and one has to define the STRING_MAX_LENGTH to a larger value. It just won't compile...
 
What happens if you extend it programatically?
I.E.
Code:
for i=1 to 20
    str=str&"A"
next i
What does it return for len(str) then?

Not that it matters, I'm just curious.

Mike.
Edit, I don't know how to concatenate strings.
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…