WHILE/WEND blocking [OSHONSOFT]

Irving

Joined Jan 30, 2016
4,065
Hi I,
I think you're correct with 20mS period?

This suggestion, is a bit beyond me, but is it possible to have 'say' a 1mS period, and cycle through the UART section, and the SERVO section, and the SPI section, only using FLAGS to interact with each of them?
C.
Yes, but once you get to that number of potentially time conflicting peripherals you may be better using an interrupt driven strategy.

Tell me more about the servo section. It seems to have 7 servos and every 20mS you adjust the position & direction from/to some array. There's no obvious connection to real servos and no apparent timing issues in that 'for' loop...
 

Thread Starter

camerart

Joined Feb 25, 2013
3,736
Yes, but once you get to that number of potentially time conflicting peripherals you may be better using an interrupt driven strategy.

Tell me more about the servo section. It seems to have 7 servos and every 20mS you adjust the position & direction from/to some array. There's no obvious connection to real servos and no apparent timing issues in that 'for' loop...
Hi I,
I was thinking about an INTERRUPT driven routine, but setting FLAGS to be used in the main loop. As I said, this is all a bit beyond me.

It has 8CH from and 8x PIN output of a SHIFT REGISTER.
I only need 5CH, but I don't think it makes any difference, as it is 8CH.

This is how I understand it:
Each CH time is between 1 to 2 mS. Each time is set by an input variable.
Each time is totalled, until all CHs have been read, which is then subtracted from the 20mS FRAME.
Then each CH switches on for it's time, and steps through the CHs, until the remainder time is finished, then started again, so each CH (SERVO) is on for 1-2 mS and off for 18-19mS
This is all controlled by PIC 3xPINs.
https://www.ti.com/lit/ds/symlink/sn74hc164.pdf
C.
 

Irving

Joined Jan 30, 2016
4,065
It has 8CH from and 8x PIN output of a SHIFT REGISTER.
I only need 5CH, but I don't think it makes any difference, as it is 8CH.

This is how I understand it:
Each CH time is between 1 to 2 mS. Each time is set by an input variable.
Each time is totalled, until all CHs have been read, which is then subtracted from the 20mS FRAME.
Then each CH switches on for it's time, and steps through the CHs, until the remainder time is finished, then started again, so each CH (SERVO) is on for 1-2 mS and off for 18-19mS
This is all controlled by PIC 3xPINs.
https://www.ti.com/lit/ds/symlink/sn74hc164.pdf
Hmm, OK, but none of that is in the code you showed, as far as I can see...

Is there more?
 

Thread Starter

camerart

Joined Feb 25, 2013
3,736
Hmm, OK, but none of that is in the code you showed, as far as I can see...

Is there more?
Hi I,
Sorry I thought I had posted it.
Here is the separate SERVO CODE.
I'm not sure whether you have Oshonsoft or not, but you can download it and have a free 30x trial. (or you used to be able to) then you could simulate it.
C
Code:
'18F4431 32MHz PCB9 REMOTE_SLAVE SERVO 020324 2100

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 CHAN_Count As Byte
Dim i As Word
Dim Servo_CHAN(8) As Word
Dim servoDir(8) As Byte
Dim frame As Long 'Word
Dim rec 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
Servo_CHAN(i) = i * 250 + 2000  '250=1/8th-1ms(2000) to 1.875(1 7/8ths - 3750)ms in 1/8th mS steps
'Servo_CHAN(i) = i * 1000 + 8000  '250=1/8th-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

'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'<<<<<<<<<<<<<<<<<<<<
CHAN_Count = 8  'cause it to reset
T1CON = %00100000  '=All values are divided by PRESCALE=4.
T1CON.0 = 1  '&00000001=EN start timer
CCP1CON = %1000  'will go high on interrupt - will start a 0.5mS pulse
frame = 1000  'start everything in 4000 cycles
PIR1.RCIF = 0  'RCIF: EUSART Receive Interrupt Flag bit
PIE1.RCIE = 1  'EUSART Receive Interrupt Enable bit
PIE1.CCP1IE = 1  'CCP1IE: CCP1 Interrupt Enable bit
INTCON.PEIE = 1  'PEIE/GIEL: Peripheral Interrupt Enable bit
INTCON.GIE = 1  'GIE/GIEH: Global Interrupt Enable bit

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

    While CHAN_Count = 0  'wait for 20mS to pass (=1/50th of a second)
    Wend
    While CHAN_Count <> 0
    Wend
    For i = 0 To 7
        dir = servoDir(i)  'doesn't matter if ISR happens as servo_CHAN isn't changed by ISR
        pos = Servo_CHAN(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
        Servo_CHAN(i) = pos
        INTCON.GIE = 1
        servoDir(i) = dir  'servoDir not used by ISR
    Next i

        '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 + 4000  'adding 4000 will make pulse 0.5mS long
    Else
        LATC.0 = 0  'clear the data pin
        CCP1CON = 0x08  'No so output the timed gap
        If CHAN_Count < 8 Then
            'still doing the servos so add remainder of time
            wordTemp = wordTemp + Servo_CHAN(CHAN_Count)
            wordTemp = wordTemp - 4000  'knock of the 4000 (0.5mS) already elapsed
            frame = frame - Servo_CHAN(CHAN_Count)
            CHAN_Count = CHAN_Count + 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)
            frame = 165000  '160,000(20mS) minus time of positive pulse(0.5mS)
            CHAN_Count = 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

Resume
Code:
'18F4431 32MHz XTL PCB9 REMOTE_SLAVE NO-MATCH FULL_SERVO E 060324 0900

Define CONFIG1L = 0x00
Define CONFIG1H = 0x06  '8mHz x4 =32
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

'OSH config
Define CLOCK_FREQUENCY = 32
Define SINGLE_DECIMAL_PLACES = 2
Define STRING_MAX_LENGTH = 45  '20 too short@
Define SEROUT_DELAYUS = 1000

'**********************************************************************
'*                                                                    *
'*      Register configuration                                        *
'*                                                                    *
'**********************************************************************
'------------- TARGET SETUP  ------------------
'Const PR2set = 125  'use this for the live board: gets 5ms per interrupt
Const PR2set = 2  'use this for fast timing to speed up simulator
Define SIMULATION_WAITMS_VALUE = 1  'Comment in for SIM out for PIC

ANSEL0 = %00000000
ANSEL1 = %00000000

'**********************************************************************
'*                                                                    *
'*          IO Port configuration                                     *
'*                                                                    *
'**********************************************************************
'IN or OUT
Const TRISAinit = %11000000  '7=OSC, 6=OSC, 4=/ 3=/ 2=TEMP SEROUT
Const TRISBinit = %00000000
'Const TRISCinit = %11000100  '7=1-RX, 6=1-slave4431_cs, 4-5=??, 3=74HC164 MR, 2=74HC164 CLK, 1=?, 0=74HC164 DATA'<<<<<<<<<<<<
Const TRISCinit = %11110010 '???????@
'Const = %11110010 '???????@
Const TRISDinit = %00100000  '6=led, 7=led, 5=synch, 2=MOSI
Const TRISEinit = %00000000  '2=TEST INDICATOR, 0= S2M_BUF_FULL

LATC.0 = 0  'ensure data is low
LATC.2 = 0  'and clock
LATC.3 = 1  'Master reset HIGH for run.'<<<<<<<<<<<<<<

TRISA = TRISAinit
TRISB = TRISBinit
TRISC = TRISCinit
TRISD = TRISDinit
TRISE = TRISEinit

'SET BITS ON/OFF before TRIS!
Const LATAinit = %00000000  'ON/OFF
Const LATBinit = %00000000
Const LATCinit = %00000000
Const LATDinit = %00000000
Const LATEinit = %00000000  'POSS MCLR RE3

'*******************************************************
'*                                                     *
'*       GLOBAL VARIABLE DECLARATIONS                  *
'*                                                     *
'*******************************************************
'Comms

Const rxbufsize = 50  'keep this the same as the buffer size, check this.
Dim gnrmcpsn As Byte  'POSITION of character in UART RX buffer STRING.
Dim RXerr As Bit  'Errors in receiving $DATA

Dim RXIRQchar As Byte
Dim dumpchar As Byte  'For clearing Over run errors

Dim spipsn As Byte  'VARIABLE USED IN SSPBUF SEND/RECEIVE ROUTINE
Dim spichar As Byte

'SLAVE GPS
Dim strtim As String
Dim strlat As String
Dim strlong As String

PIE1.RCIE = 0  '0= 'EUSART Receive Interrupt Enable bit

'FLAGS To indicate updated data
Symbol spi_pin_rdy = PORTE.0  'READY to send SPI DATA.
spi_pin_rdy = 0
Symbol slave4431_cs = PORTC.6  'The port used as chip select
Dim slave4431_cs_data As Bit  'The data state of the chip select line D added
Dim gnrmc_buf_filling As Bit  'Message loading
Dim gnrmc_buf_full As Bit  'GPS-Buffer $ to W   1 = FULL 0 = Not FULL
Dim gnrmc_buf(45) As Byte  'received message comes to buf'Check size (Only for GNRMC)
Dim s2m(34) As Byte  '(34) As Byte  'Used to transfer data via SPI
'from the ssp buffer for receiving via the spi bus. The array has to be the same length as s2m buffer.
'onto the ssp buffer for transmitting via the spi bus. data includes the gps string,
'battery voltage and spare info.
Dim m2s(34) As Byte  'Used to transfer data to SLAVE via SPI

'********************* SERVO *******************************
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 strCount As Byte
Dim rec As Byte
Dim isDone As Bit

Dim pos As Word'SERVO'<<<<<<<<<<<<<<<<<
Dim dir As Byte

Dim batvolt As Byte  'TEST Battery voltage from BASE-SLAVE
Dim sparedata As Byte  'TEST Spare data from BASE-SLAVE.

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

'*******************************************************
'*                                                     *
'*            End of variable declarations             *
'*                                                     *
'*******************************************************
'*******************************************************
'*                                                     *
'*            START UP CODE BEGINS HERE                *
'*                                                     *
'*******************************************************

'START UP LEDS
rled = 1
WaitMs 1000
rled = 0
WaitMs 1000
yled = 1
WaitMs 1000
yled = 0
WaitMs 1000

Disable High  'Disable interrupts
Disable Low  'Disable interrupts

'setup USART for 9600 baud receive
'Hseropen 9600 '38400
'TXSTA = 0

RCSTA = %10010000  '7=SPEN: Serial Port Enable bit, 6=RX9: 9-Bit Receive Enable bit, 5=SREN: Single Receive Enable bit, 4=CREN: Continuous Receive Enable bit
TXSTA = 0
TXSTA.BRGH = 1  'BRGH: High Baud Rate Select bit
BAUDCON.BRG16 = 1  '16-Bit Baud Rate Register Enable bi
SPBRG = 207
PIR1.RCIF = 0  'RCIF: EUSART Receive Interrupt Flag bit
PIE1.RCIE = 1  'EUSART Receive Interrupt Enable bit
PIE1.CCP1IE = 1  'CCP1IE: CCP1 Interrupt Enable bit
'INTCON.PEIE = 1  'PEIE/GIEL: Peripheral Interrupt Enable bit
'INTCON.GIE = 1  'GIE/GIEH: Global Interrupt Enable bit

'fire up the UART
Enable High  'enable the high interrupts

Gosub irqinitbuf  'INIT RX'<<<<<<<<<<<<<<<¦
Serout PORTB.0, 9600, "RDY  ", CrLf  '"slave ready", CrLf  'USART?<<<<<<<<<<<<<<<<<<<<<<<<<<

'INITIALIZE SPI
Call init_spi()  'initialise spi -here SSPEN=1 sets the pin directions for SPI

'ms20_reporttimer = 0  'force reports on entry to main loop

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

''*******************************************************
''*                                                     *
''*            Main loop BEGINS                         *
''*                                                     *
''*******************************************************

'$GNRMC,111111.00,A,3723.02837,N,00150.39853,W,0.820,188.36,110706,,,A*74
'$GNRMC,000000.00,A,3723.02837,N,00150.00000,W,0.820,188.36,110706,,,A*74$GNRMC,111111.00,A,3723.02837,N,00150.11111,W,0.820,188.36,110706,,,A*74$GNRMC,222222.00,A,3723.02837,N,00150.22222,W,0.820,188.36,110706,,,A*74$GNRMX,333333.00,A,3723.02837,N,00150.33333,W,0.820,188.36,110706,,,A*74$GNRMC, 444444.00, A, 3723.02837, N, 00150.55555, W, 0.820, 188.36, 110706,,, A * 74$GNRMC, 555555.00, A, 3723.02837, N, 00150.39853, W, 0.820, 188.36, 110706,,, A * 74$GNRMC,666666.00,A,3723.02837,N,00150.66666,W,0.820,188.36,110706,,,A*74$GNRMX,777777.00,A,3723.02837,N,00150.77777,W,0.820,188.36,110706,,,A   [FOR SIM}


main_loop:  '/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\

Toggle rled

'Toggle PORTE.0

'Serout PORTB.0, 9600, "TEST", CrLf '<<<<<<<<<<<<<<<<<

If gnrmc_buf_full = 1 Then
    'Break  '<<<<<<<<<<<
    'If spi_pin_rdy = 1 Then  'Tell MASTER SPI ready.<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    Serout PORTB.0, 9600, "SLAVE GNRMC PARSED  ", s2m(0), s2m(1), s2m(2), s2m(3), s2m(4), s2m(5), s2m(6), s2m(7), s2m(8), s2m(9), s2m(10), s2m(11), s2m(12), s2m(13), s2m(14), s2m(15), s2m(16), s2m(17), s2m(18), s2m(19), s2m(20), s2m(21), s2m(22), s2m(23), s2m(24), s2m(25), s2m(26), s2m(27), s2m(28), s2m(29), s2m(30), s2m(31), #s2m(32), #s2m(33), CrLf
    'WaitMs 1  'Lower till not work
    'Gosub irqinitbuf
'Endif
    'If gnrmc_buf_parsed = 0 Then  'parse tried but string was unknown, corrupt or wrong length
        'Hserout "Parse fail ", CrLf
        'Gosub IRQinitBuf  '++++++¦
    'endif
    'Return

    Gosub gnrmc_parse

    'Update the transmit to master buffer with current data
    batvolt = 12
    sparedata = 123
Endif

    yled = 1

    If slave4431_cs = 0 Then
        For spipsn = 0 To 33  'GPS=0to29-$toW INC, QEI=30,31 BATVOLT=32 SPARE DATA=33 'QEI?@
            SSPBUF = s2m(spipsn)  'Transfer S2M(spipsn) into SSPBUF
            While SSPSTAT.BF = 0
            Wend
            m2s(spipsn) = SSPBUF  'Transfer M2S(spipsn) BYTE from SSPBUF into M2S(spipsn)
        Next spipsn
    Else
        Goto skip
    Endif
    spi_pin_rdy = 0

    skip:

    spipsn = 0
    yled = 0
    RCSTA.CREN = 1
    PIE1.RCIE = 1

    While ServoCount = 0  'wait for 20mS to pass (=1/50th of a second)
    Wend
    While ServoCount <> 0
    Wend
    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
        'Disable High
        ServoPos(i) = pos
        INTCON.GIE = 1
        'Enable High
        servoDir(i) = dir  'servoDir not used by ISR
    Next i

Goto main_loop

End

'*******************************************************
'*                                                     *
'*            Functions BEGIN                          *
'*                                                     *
'*******************************************************
'---------------------- RX/TMR2 INTERRUPT SERVICE  ----------------------
'Captures one sentence from '$' to 'W' in buf.
'Sentences must fit entirely in buf from $ to W
'Re-inits buf on any error and when any $ is received, even if in middle of sentence
'Stops UART and sets gps_buf_done when 'W' is received.

'Sentence in progress will be discarded, buffer reset and UART re-enabled when:
'Any UART error occurs
'A new '$' in the middle of a reception is found
'The buffer overflows before a 'W' is received. Non-fatal, it will just begin looking for the next
'sentence.  err will be set when this happens so that main knows about it.

'Returns gps_buf_done=1 and buffer loaded with $,data,W on successful receipt of a complete sentence.
'Requires:
'rxBufSize defined as the size of buf in bytes.  Declare the buffer like this:
'Const rxBufSize = 50
'Dim buf(50) As Byte  'Valid buf index range is 0 to rxBufSize-1.  After $, index points to last character stored

'Expects:
'Call IRQinitBuf with PIE1.RCIE = 0 to set up for next sentence
'$GNRMC,111111.00,A,3723.02837,N,00159.39853,W,0.820,188.36,110706,,,A*74'For SIM

On High Interrupt
Save System

'OVERRUN ERROR
If PIE1.RCIE = 1 Then  'EUSART Receive Interrupt Enable bit
    If RCSTA.OERR = 1 Then
        Gosub irqinitbuf  're-init buffer, discard bad sentence
        Goto RXIRQdone  'done, wait for next character
    Endif  'OERR

    'FRAMING ERROR
    If RCSTA.FERR = 1 Then
        dumpchar = RCREG  'Read char to clear RCIF and FERR
        Gosub irqinitbuf  'Re-init buffer, discard bad sentence
        Goto RXIRQdone  'wait for next
    Endif  'FERR

    'No UART errors, process character
    'If PIR1.RCIF = 1 Then
    If PIR1.RCIF = 1 And PIE1.RCIE=1 Then'POMMIE@
        RXIRQchar = RCREG  'read the received char, clears RCIF

        'Look for $, start/restart filling buf when found
        If RXIRQchar = "$" Then  'Start (re)filling buf on any $
            Gosub irqinitbuf  'init buffer, index and flags@
            gnrmc_buf(gnrmcpsn) = RXIRQchar  'store $ $ ADDED instead of RXIRQchar, because no $ was being stored
            gnrmc_buf_filling = 1  'start storing the sentence
            Goto RXIRQdone  'done with this character
        Endif  'char was $



        'no UART errors and character was not $
        'If $ was found previously, process character looking for W and no buffer overflow.
        'If haven't found $ yet, just ignore character.

        If gnrmc_buf_filling = 1 Then  'if filling buffer, see if there is room in buf
        'Break  '<<<<<<<<<<<,
            If gnrmcpsn >= (rxbufsize - 1) Then  'last char was at end of buf - buffer overflow so..
                Gosub irqinitbuf  'restart buffer, discard sentence
                RXerr = 1  'let main know that the buffer overflowed and is restarting
                Goto RXIRQdone  'done, resume looking for next $
            Endif  'buffer overflow

            gnrmcpsn = gnrmcpsn + 1  'else, there's room in buf so bump index and store character, might be W
            gnrmc_buf(gnrmcpsn) = RXIRQchar

            If RXIRQchar = "W" Then  'if end of sentence..
                RCSTA.CREN = 0  'shut down UART
                PIE1.RCIE = 0  'Enable off
                gnrmc_buf_filling = 0
                gnrmc_buf_full = 1
                Goto RXIRQdone  'and bye!
            Endif  'RXIRQchar was W
        Endif  'If gnrmc_buf_filling = 1
    Endif  'RCIF=1
Endif  'RCIE=1

    'Exit point for each RXinterrupt. Process timers
    RXIRQdone:

'Resume
'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
Resume

'--------------- PARSE COMPLETE SENTENCE IN BUFFER -------------------------
'parse: extracts the main values from GPS,REMOTE and QEIDEG sentences in RXbuf 'QEI@
'into named value messages using the parse utilities above.
'Flags:
'returns prsed_gnrmc =1 if it found A good sentence
'if prsed_gnrmc =0, has bad sentence
'posted to respective string(s).?¦

'Expects: gnrmcpsn = index in buffer of the termininating 'W' char (one less than number of chars):
'Const ixGNRMC_W = 15  '$gnrmc,025,4,75,W
Const ixGNRMC_W = 44

gnrmc_parse:
    'Break  '<<<<<<<<<<<<<<<<<<<<<<<<<
    gnrmc_buf_full = 0
    'Dim tempIX As Byte  'used as index for building/adding to strings
    'tempIX = 0  'string building begins at 0 for any

    If gnrmcpsn <> ixGNRMC_W Then Goto gnrmc_buf_parsed  '-->
    'Endif
    s2m(0) = "&"  '  [TOT 34 BYTES ] $TEST¦
    s2m(1) = gnrmc_buf(7)  'Time
    s2m(2) = gnrmc_buf(8)  'Time
    s2m(3) = gnrmc_buf(9)  'Time
    s2m(4) = gnrmc_buf(10)  'Time
    s2m(5) = gnrmc_buf(11)  'Time
    s2m(6) = gnrmc_buf(12)  'Time
    s2m(7) = gnrmc_buf(14)  'Time
    s2m(8) = gnrmc_buf(15)  'Time
    s2m(9) = gnrmc_buf(19)  'Lat
    s2m(10) = gnrmc_buf(20)  'Lat
    s2m(11) = gnrmc_buf(21)  'Lat
    s2m(12) = gnrmc_buf(22)  'Lat
    s2m(13) = gnrmc_buf(24)  'Lat
    s2m(14) = gnrmc_buf(25)  'Lat
    s2m(15) = gnrmc_buf(26)  'Lat
    s2m(16) = gnrmc_buf(27)  'Lat
    s2m(17) = gnrmc_buf(28)  'Lat
    s2m(18) = gnrmc_buf(30)  'N
    s2m(19) = gnrmc_buf(32)  'Lon
    s2m(20) = gnrmc_buf(33)  'Lon
    s2m(21) = gnrmc_buf(34)  'Lon
    s2m(22) = gnrmc_buf(35)  'Lon
    s2m(23) = gnrmc_buf(36)  'Lon
    s2m(24) = gnrmc_buf(38)  'Lon
    s2m(25) = gnrmc_buf(39)  'Lon
    s2m(26) = gnrmc_buf(40)  'Lon
    s2m(27) = gnrmc_buf(41)  'Lon
    s2m(28) = gnrmc_buf(42)  'Lon
    s2m(29) = gnrmc_buf(44)  'W
    's2m(30) = POSCNTL  'QEIDEGLB
    's2m(31) = POSCNTH  'QEIDEGHB
    s2m(32) = batvolt  'Bat volt
    s2m(33) = sparedata  'Spare DATA

    gnrmc_buf_parsed:  '<-- <--

    spi_pin_rdy = 1  'S2M Buffer ready to SPI to MASTER
    Break  '<<<<<<<<<<<<  CS RC6 OFF
    'ms20_gnrmcguard = gnrmcguardset  '??????????
Return


'------------- UART SETUP UTILITIES  -----------------

'Stops UART, selects channel indicated by datasw (0-2)
'Inits RX buffer then restarts UART and enables RX interrupt
'Expects:
'GIE is enabled
'port directions and basic TX/RX

'--------------------  INIT SENTENCE BUFFER  ------------------
'Sets up index and flags for next sentence.  Overwrites
'old buffer data
'May be used by main (non-interrupt code) when PIR1.RCIE = 0

irqinitbuf:
    gnrmcpsn = 0  'init index
    RXerr = 0  'no error
    RCSTA.CREN = 1
    dumpchar = RCREG  '1    'clear UART RX registers
    dumpchar = RCREG  '2
    PIE1.RCIE = 1
Return

'*******************************************************
'*                                                     *
'*            START UP SPI ROUTINE                     *
'*                                                     *
'*******************************************************

Proc init_spi()  'PIC 18F4431
'4431
TRISC.6 = 1  '4431_CS=1
TRISD.3 = 1  'SCK from MASTER ******INPUT*****
TRISD.1 = 0  'MISO  ****** OUTPUT *******
TRISD.2 = 1  'MOSI  ****** INPUT *******

'MODE 0,0
SSPSTAT.SMP = 0  'Input data sampled at middle of data output time ** not about clock generation **
SSPSTAT.CKE = 0  '0 Output data changes on clock transition from active to idle ** AS ABOVE **
SSPSTAT.5 = 0  'I2C only
SSPSTAT.4 = 0  'I2C only
SSPSTAT.3 = 0  'I2C only
SSPSTAT.2 = 0  'I2C only
SSPSTAT.1 = 0  'I2C only

SSPCON = 0  'RESET THE CONTROL REGISTER
SSPCON.WCOL = 0  'Collision detect
SSPCON.SSPOV = 0  'Overflow
SSPCON.SSPEN = 1  'Configure SCK,SD0,SDI,/SS ** HAS TO BE 1. To reset or reconfigure SPI mode, clear the SSPEN bit,
'reinitialize the sspcon registers And Then set the SSPEN Bit from the datasheet !!!!!!!!!!!!!!!!
SSPCON.CKP = 1  '0 = Idle state for clock is a HIGH level
SSPCON.SSPM3 = 0  '0100 = SPI SLAVE mode, clock = FOSC/64
SSPCON.SSPM2 = 1
SSPCON.SSPM1 = 0  'SLAVE MODE
SSPCON.SSPM0 = 0
End Proc
 

Attachments

Last edited:

Thread Starter

camerart

Joined Feb 25, 2013
3,736
Hi,
I've added the FULL and SERVO program into #24.
If you're interested in trying it in the Oshonsoft SIM, I can help you with running it. (Some of the BITs and PINs need switching)
C.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,736
Hi,
I've added a FULL-SERVO program Simulation into #24.
Set SSPSTAT.BF = 1
Enter $-W sentences from just above \/\/\/\/\/\/\/\/\/\/\/ line into HARDWARE UART SEND STRING.
Set RC6 opposite to SPI-PIN-READY.
Run without BASIC PROGRAM TRACKING, until STEP apears next to HELP.
Any questions?
C
 

Thread Starter

camerart

Joined Feb 25, 2013
3,736
Hi,
Importants note:
This PIC will be the one that needs to carry out calculations and the CODE for controlling the SERVO/MOTORS from DATA sent to it via radio link.
I have little idea of how much memory will be needed, ot what it entails.
This is what my whole project has been leading up to.
C
 

Thread Starter

camerart

Joined Feb 25, 2013
3,736
Hi,
I've just checked the programs in #24.
As it is there all CH of the SERVO sweep backwards and forwards. This was setup for testing, but in reality, there would be no DIR or +-40, as the actuall number from MASTER would be used.
Also there is a line 'Stops UART, selects channel indicated by datasw (0-2) this is historic and needs removing. The is no DATA SW any more!
[There may be more errors!]
C
 

Thread Starter

camerart

Joined Feb 25, 2013
3,736
Hi I,
I just looked up 'your version' of THREADS!
If I understand correctly, they use POINTERS? If this is so, then even though Oshonsoft 'does' POINTERS they may not be the correct type. (As pointed out in another THREAD posted by me)
I'm not sure how to find out, apart from a simple test, in SIM, then 'LIVE', which I could carry out, but am not skilled enough to be able to program.
C.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,736
Hi,!!
I've just had a thought
I only need 5 SERVO Channels. So 5 at MAX = 10mS in a 20mS FRAME, leaves 10mS. Could other progrmming be carried out in this time?
C
 

Thread Starter

camerart

Joined Feb 25, 2013
3,736
Hmm, OK, but none of that is in the code you showed, as far as I can see...

Is there more?
Hi I,
I think you may have finished with this?
I'm running it in the simulator, and trying to watch the timings and how it works.
Thanks for all of your input.
C
 

Irving

Joined Jan 30, 2016
4,065
Hi,

Still here, just needed to focus on a PCB layout for a client that I need to get into manufacture next week.
I was trying to understand your servo driving approach. Seems complicated to me, unless there's some hardware specific needs... What's the end purpose?
 

Thread Starter

camerart

Joined Feb 25, 2013
3,736
Hi,

Still here, just needed to focus on a PCB layout for a client that I need to get into manufacture next week.
I was trying to understand your servo driving approach. Seems complicated to me, unless there's some hardware specific needs... What's the end purpose?
Hi I,
Glad you're still here, sometimes people dissapear, for whatever reason.
The SERVO section was written by an ETO member, and there was a discussion, about the best way to have 5xChannels from the 18F4431 PIC (Chosen for it's QEI module, not used here) This PIC only has 2x actuall PWM PINs, so the Shift register method was adopted.
What I'm trying to do at the moment is looking at the SERVO section only, and the prescaler, which confuses things as many of the numbers are /4. I'm trying to remove the prescaler to make an example simple more obvious CODE.
C.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,736
Hi,
I think I now know what the SHIFT REGISTER does, in this application
At the start,
Load BYTE 00000001 = CH0 (CHANNEL1) which appear at the output PINS, wait for between 1 and 2ms then shift it out of the way.
Load BYTE 00000010 = CH1 (CHANNEL2) which appear at the output PINS, wait for between 1 and 2ms then shift it out of the way.
Repeat for all Channels.
Total up all of the times, 'say' 8X1.5ms =12ms
Subtract that from the FRAME time of 20ms = 8ms then wait for the FRAME time to finish, and repeat with new values.
EDITED.
C
 
Last edited:

Thread Starter

camerart

Joined Feb 25, 2013
3,736
Hi C,
Compare the definition of a While .... Wend.

You say : While slave4431_cs = 1 'If 1 then it waits till the CS makes it 0 then it LOOPs

Clip:
This example uses the While...Wend statement to increment a counter variable.
The statements in the loop are executed as long as the condition evaluates to True.


VB
Dim Counter
Counter = 0 ' Initialize variable.
While Counter < 20 ' Test value of Counter. // While the count is less than 20 it performs the Code in the Loop
Counter = Counter + 1 ' Increment Counter.
Wend ' End While loop when Counter > 19.
Debug.Print Counter ' Prints 20 in the Immediate window.
Hi E,
It looks to me that the IF/ENDIF has the same affect as WHILE/WEND!
In your example While slave4431_cs = 1 'If 1 then it waits till the CS makes it 0 then it LOOPs
the CODE will block if it doesn't 'see' a slave4431_cs = 0
Have I understood correctly?
C.
 
Top