News:

Let's find out together what makes a PIC Tick!

Main Menu

help rs485 usart

Started by krizpin, Aug 09, 2022, 07:21 AM

Previous topic - Next topic

krizpin

good morning. please someone will have some example of communication between 2 pic using rs485 protocol?? I've been doing tests for 1 month and I'm going crazy :-)
thankss

rick.curl

Hi Krizpin-
What happened when you tried the code example Giuseppe sent you a couple of weeks ago?

-Rick

krizpin

So I can't get it to work. I need to connect 2 pics that are constantly sending data via rs485. I need to send a data frame, read it in another pic and send an ack and in turn that slave pic send data and be able to read it in the master pic, send ack etc

top204

#3
My recommendation would be to get the code working with standard USART serial data. Then convert it to RS485 using the external devices.

As long as you only have the two devices connected, slave and master, the same protocol will work with RS485. RS485 is used so that multiple devices can be connected on the same lines, if required, and at a longer distance because it uses a different modulation method. It does not have its own protocols, so when your code works using USARTs, you know it will work when converted to RS485.

Remember.... K.I.S.S. :-)


JonW

A good device to use for this experiment would be the SP336 from Maxlinear, I'm not aware of any other IC that has this capability, they are not cheap but you can digitally switch between protocols RS232/485 and loopback!

https://assets.maxlinear.com/web/documents/sipex/datasheets/sp336e.pdf

krizpin

Thank you very much for your recommendation. I am currently testing with maxim's max485 but it is a pain to manage the send and receive mode because it has to be done by software and since the reception is by interruption the madness of my code is total. thank you

krizpin

1660064000516.jpg

RGV250

#7
Hi,
I got some from Amazon that do not need direction control as the device does it.

I do not have access to the account at the moment but these look similar.
https://www.ebay.co.uk/itm/314079237297?chn=ps&_trkparms=ispr%3D1&amdata=enc%3A1ZfXGwwCfQ_Kdo01dA6PuYw36&norover=1&mkevt=1&mkrid=710-134428-41853-0&mkcid=2&itemid=314079237297&targetid=1647205088320&device=c&mktype=pla&googleloc=1006907&poi=&campaignid=17819795917&mkgroupid=137883623263&rlsatarget=pla-1647205088320&abcId=9301024&merchantid=263046164&gclid=EAIaIQobChMI87ztttK6-QIVCrTtCh0yagDLEAQYBSABEgKO5_D_BwE

Not Amazon but I think these are the same ones.
https://www.ebay.co.uk/itm/314094225806?_trkparms=amclksrc%3DITM%26aid%3D1110002%26algo%3DSPLICE.SOI%26ao%3D1%26asc%3D20201210111451%26meid%3D67c59876373a4f6b86973b5ab7d27225%26pid%3D101196%26rk%3D1%26rkt%3D12%26sd%3D314079237297%26itm%3D314094225806%26pmt%3D1%26noa%3D0%26pg%3D2047675%26algv%3DPromotedSellersOtherItemsV2WithMLRv3%26brand%3DUnbranded&_trksid=p2047675.c101196.m2219&amdata=cksum%3A31409422580667c59876373a4f6b86973b5ab7d27225%7Cenc%3AAQAHAAABALB59iZaq6L1SxCGLGoiBqHdpPz8nqKyKuGL1QIa0H%252B4jbbwhHcvEpFTAJ6P5yA6fHLZTsZ%252F7fhe3q4CI16%252Budr2aVCFOPEzZKj5njfc7b1FLg%252FZ%252BXLP2hSrpEOOhquo7MA2LpZmuGkErh8dxGWgFuafmagSUvg2uiH%252FSRMvYVLuXRSo0PCeKchYZUl5tjyTIvV8CnTGdNQ%252FSBACJpqSb%252BwfRU%252B7CEBNfv6u1s%252FF6sBOU%252FP6UpG5R7IoGy4FrdBkFn5ebETn0iysQKTy4FPgS9PQ0alffp9FwAIR7jNtPsmfV%252BPkFkXwj%252FxqnVa%252BKzVHRc8VdlQ%252BWgD0ZWnWdSCK6so%253D%7Campid%3APL_CLK%7Cclp%3A2047675

Bob

JonW

#8
I think you need to break down the process and find the issue.


As les mentions you need to code a simple protocol in logic (vss/vdd) and then get the signaling going. Then look at altering the signalling protocol..

Send 3 bytes address, command, data
Receive, process return

If you can play pong with a delay you then have a solid comms channel

Alternative after 1 month is to look for a consultant to do this.   Would take them a few hrs (not being condescending)

J

krizpin

You are absolutely right JONW.. I have to turn my head one more time and give up and seek help in another way. Thank you

RGV250

Hi Krizpin,
A couple of questions.
Why do you need RS485 if you are only using 2 devices, are you planning to add more later. If it is just for distance it might be simpler to use 4 of the transceivers (2 for TX and 2 for RX) to go full duplex and then the software can transmit and receive simultaneously.
You have only shown the module, not how you have connected it to the PIC or between them etc.

As Les said, keep it simple, if I were doing it I would try with one sending and the other receiving, have you seen the example on page 246 of the manual, it couldn't get much simpler. Try that without the MAX485 transceivers, once that is working add the transceivers and try to get communication with them.

Bob

John Lawton

I agree, go full duplex if you can.
RS232 is full duplex, i.e. you can transmit and receive simultaneously because there are separate TX and RX lines.
RS422/RS485 can be half duplex of full duplex depending on the number of lines used. Your Ebay board is half-duplex.

With full duplex RS485 (or RS422) it can therefore directly replace point to point serial (RS232) directly as it is simply a different hardware signalling system being balanced as opposed to the single ended RS232.

Does that help?

See_Mos

Reading post #2 you are sending a packet of data at a time in each direction but not at the same time, is that correct?

How far apart will the PICs be in the final design?  Is isolation required?

As others have said, keep it simple. Unless you need full duplex start by connecting the PICs directly

I have done this before, about fifteen years ago, with 16F877s.  PIC one sends a packet of data with a checksum to PIC two which processes the data then returns a packet of data to PIC one.  I posted the information on the old forum.  If this is what you need then let us know and I will find it for you.

top204

#13
Also... If both devices are operating as master, and both are sending data to each other without one asking for it first, this will cause issues that can only be remedied by an interrupt serial buffer. Otherwise, while one device is busy, it may receive data from the other and miss it. However, with a serial buffer, the data will still be received, and when the device is finished what it is doing, the data from the other device will be in the buffer, ready to be read and acted upon.

For serial coms of any sort, a buffer is almost mandatory because it is async and send/receive timing is critical with it. For that reason alone, look to use an 18F device, or at the least, an enhanced 14-bit core device because they have a mechanism for linear RAM when operating indirectly, and that is exactly what a buffer, of any kind, needs.

JonW

#14
Here is an interrupt driven serial buffer for the 18F27k42, it's based on Les' HW serial interrupt code but modified to continually keep topping up the receive buffer until it finds the EOM character (in this case %).  Once it receives the EOL character it calls the parse procedure.  You can then parse the received string and return whatever you want.  Connect RX to TX.  There is a delay in the DO LOOP to flash LED.  This whole interrupt routine works perfectly. It should be fairly easy to modify to suit your needs.  This is built for a 27k development board i made so you can remove the pulse_led proc

'*******************************************************************
'*  Name    : HARDWARE SERIAL INTERRUPT                            *
'*  Author  : JON WALKER                                          *
'*  Notice  : Copyright (c) 2019 ELECIUM LTD                      *
'*          : All Rights Reserved                                  *
'*  Date    : 07/07/2022                                          *
'*                                                                *
'*  Version : 0.1                                                  *
'*******************************************************************

    Device = 18F27K42                                  ' Tell the compiler what device to compile for
    Declare Xtal = 64                                  ' Tell the compiler that the device will be running at 64MHz
    Declare Access_Upper_64K = True                    ' Set the compiler to see all 128K of flash memory

    On_Hardware_Interrupt GoTo ISR_Handler              ' Point to the interrupt handler routine

    $DEFINE EOM_CHAR  "%"                              ' CHARACTER TO FLAG END OF MESSAGE
    Declare Hserial1_Baud = 115200                      ' Set the Baud rate for USART1
    Declare Hserout1_Pin  = PORTC.6                    ' Set the pin used for USART1 TX
    Declare HSerin1_Pin  = PORTC.7                    ' Set the pin used for USART1 RX

    Include "USART1_Buffer_K42.inc"                    ' Load the buffered USART1 library routines into the program


    Dim TEMP As Byte
    DIM EOM_FLAG AS BIT                          ; SET WHEN END OF SERIAL STRING RECEIVED %
    ' PORT SETUP

    Dim LED1        As LATB.7
    Dim LED2        As LATB.6
'------------------------------------------------------------------------------------------------
' The main program starts here
' WHEN THE END OF MESSAGE CHARACTER IS RECEIVED THEN THE EOM_FLAG WILL BE SET TO SHOW DATA IN THE BUFFER

Main:
    Setup()                                            ' Setup the program
    LED1 = 0
    LED2 = 1

    Do
      if EOM_FLAG = 1 then                  ' WAIT FOR THE EOL CHARACTER
          PARSE()                            ' PARSE THE BYTES IN BUFFER
          EOM_FLAG = 0                        ; CLEAR THE END OF MESSAGE FLAG
          USART1_ClearSerialBuffer()
      EndIf

      DELAYMS 300                            ;LOOP INDEFINITELY
      TOGGLE LED1
      TOGGLE LED2
    Loop

'------------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------------
 '------------------------------------------------------------------------------------------------
' PARSE SERIAL BUFFER
' Input    : None
' Output    : None
' Notes    : None

 PROC PARSE()
      HRSOUT "THERE ARE ",DEC  (USART1_bIndexIn - 1), " BYTES IN THE BUFFER",13,10
      FOR TEMP = 1 to USART1_bIndexIn - 1 ' READ THE BUFFER OUT
          HRSOUT USART1_bRingBuffer[TEMP]
      Next
      HRSOUT 13,10
EndProc



'------------------------------------------------------------------------------------------------
' FLASH LED
' Input    : None
' Output    : None
' Notes    : None

 PROC PULSE_LED()
      LED1 = 1
      LED2 = 0
      FOR TEMP = 1 TO 10
          TOGGLE LED1
          TOGGLE LED2
          DELAYMS 50
      NEXT
      LED1 = 1
      LED2 = 0
EndProc


'------------------------------------------------------------------------------------------------
' Setup the program
' Input    : None
' Output    : None
' Notes    : None
'
Proc Setup()
    USART1_Open()                                      ' Open USART1 ready for the interrupt buffer
    IntPeriph_Enable()                                  ' Enable peripheral interrupts
    IntGlobal_Enable()                                  ' Enable global interrupts
EndProc

'------------------------------------------------------------------------------------------------
' Interrupt handler routine
' Input    : None
' Output    : Array USART1_bRingBuffer holds the characters received from USART1
'          : USART1_bIndexIn points to the current location within the USART1 buffer
'          : Global_tByteInBuffer1 is true if a byte was received on USART1
' Notes    : Interrupts on USART1 receive
'
ISR_Handler:
    Context Save FSR1L, FSR1H                          ' Save any compiler system variables and any SFRs used before we perform the interrupt code
'
' Check the USART1 RX interrupt
'
    If USART1_RX_Flag() = True Then                    ' Was it a USART1 byte receive that triggered the interrupt?
        USART1_bRXByte = U1RXB                          ' Yes. So place the byte received into USART1_bRXByte
        IF USART1_bRXByte = EOM_CHAR then
          EOM_FLAG = 1
        EndIf
        Inc USART1_bIndexIn                            ' Move up the buffer
        If USART1_bIndexIn >= _cUSART1_BufferSize Then  ' End of buffer reached?
            USART1_bIndexIn = 0                        ' Yes. So reset USART1_bIndexIn
        EndIf
        USART1_wFSR1 = AddressOf(USART1_bRingBuffer)    ' Point FSR1L\H to USART1_bRingBuffer
        USART1_wFSR1 = USART1_wFSR1 + USART1_bIndexIn  ' Add the buffer position to FSR1L\H
        INDF1 = USART1_bRXByte                          ' Place the received byte into the buffer
        Global_tByteInBuffer1 = True                    ' Indicate that there is a byte in the buffer
    EndIf

    Context Restore                                    ' Restore any compiler system variables and SFRs, then exit the interrupt routine



'---------------------------------------------------------------------------------------
' Setup for internal oscillator operating at 64MHz on a PIC18F27K42 device
'
Config_Start
    RSTOSC = HFINTOSC_64MHZ    ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
    FEXTOSC = Off              ' HS off
    WDTE = Off                  ' WDT Disabled. SWDTEN is ignored
    CLKOUTEN = Off              ' CLKOUT function is disabled
    PR1WAY = Off                ' PRLOCK bit can be set and cleared repeatedly
    CSWEN = On                  ' Writing to NOSC and NDIV is allowed
    Debug = Off                ' Background debugger disabled
    FCMEN = Off                ' Fail-Safe Clock Monitor disabled
    MCLRE = EXTMCLR            ' If LVP = 0, MCLR pin is MCLR. If LVP = 1, RE3 pin function is MCLR
    PWRTS = PWRT_Off            ' PWRT is disabled
    MVECEN = Off                ' Interrupt contoller does not use vector table to prioritise interrupts
    IVT1WAY = Off              ' IVTLOCK bit can be cleared and set repeatedly
    LPBOREN = Off              ' ULPBOR disabled
    BOREN = Off                ' Brown-out Reset disabled
    BORV = VBOR_2P45            ' Brown-out Reset Voltage (VBOR) set to 2.45V
    ZCD = Off                  ' ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off              ' PPSLOCK bit can be set and cleared repeatedly (subject to the unlock sequence)
    STVREN = Off                ' Stack full/underflow will not cause Reset
    XINST = Off                ' Extended Instruction Set and Indexed Addressing Mode disabled
    WDTCPS = WDTCPS_2          ' Divider ratio 1:128
    WDTCWS = WDTCWS_0          ' Window delay = 87.5. No software control. Keyed access required
    WDTCCS = LFINTOSC          ' WDT reference clock is the 31.0 kHz LFINTOSC
    BBSIZE = BBSIZE_1024        ' Boot Block size is 1024 words
    BBEN = Off                  ' Boot block disabled
    SAFEN = Off                ' SAF disabled
    WRTAPP = Off                ' Application Block not write protected
    WRTB = Off                  ' Configuration registers not write-protected
    WRTC = Off                  ' Boot Block not write-protected
    WRTD = Off                  ' EEPROM not write-protected
    WRTSAF = Off                ' SAF not Write Protected
    LVP = Off                  ' HV on MCLR/VPP must be used for programming
    Cp = Off                    ' PFM and EEPROM code protection disabled
Config_End



Here is the include file if you don't have it


$ifndef _Buffered_Serial_
$define _Buffered_Serial_
'
'  /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\    \/\\\                                                /\\\          /\\\
'  \/\\\\\\\\\\\/        /\\\\\    /\\\\\\\\\\    /\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'    \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\    \/\\\        \/\\\        /\\\\\\\\\\
'      \/\\\    \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\    \/\\\ /\\  /\\\/////\\\
'      \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\  \//\\\\\\\\/\\
'        \///        \///    \/////    \//////////    \//////////      \/////        \/////    \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Interrupt-driven serial buffer for USART1 receive using a hardware high priority interrupt.
' This subroutine replaces the compiler's Hserin1/Hrsin1, HSerout1/HRsout1 commands library subroutines
'
' Written by Les Johnson for the Positron8 compiler
'
' The library routine is for PIC18F27K42 and PIC18F47K42 devices only
'
$if _device <> _18F27K42 And _device <> _18F47K42
    $error "This library is only for the PIC18F27K42 or PIC18F47K42 devices"
$endif

    #Disable HRSIn1, HRSIn1To, HRSIn1_RCREG_Read, HRSOut1    ' Disable the library subroutines for Hrsin with and without timeouts, and Hrsout

$ifndef True
    $define True 1
$endif
$ifndef False
    $define False 0
$endif
'
' Create some Compiler system variables
'
    Dim BPF  As Byte System                                    ' A compiler system variable used by the LCD routines to initialise it after power up
    Dim GEN  As Byte System                                    ' \
    Dim GENH As Byte System                                    ' / Buffered Hrsin1 Timeout value storage
    Dim PP0  As Byte System                                    ' \
    Dim PP0H As Byte System                                    ' / Storage for FSR0L\H registers
    Dim PP1  As Byte System                                    ' \
    Dim PP1H As Byte System                                    ' / Buffred Hrsin1 Timeout inside loop counter
'
' Create variables for the interrupt buffered serial receiver
'
    Dim Global_tByteInBuffer1 As Bit                            ' Set true if a byte is received in the USART1 buffer
    Dim USART1_bTimeoutInt    As GEN                            ' \ Create some fill-in variables so they can be combined into 16-bits
    Dim USART1_bTimeoutIntH  As GENH                          ' /
    Dim USART1_wTimeoutValue  As USART1_bTimeoutInt.Word        ' Alias the timeout value to GEN\H
    Dim USART1_wFSR0Save      As Word Heap                      ' Alias the FSR0L\H storage to PP0\H
    Dim USART1_bInsideLoopInt As PP1                            ' \ Create some fill-in variables so they can be combined into 16-bits
    Dim USART1_bInsideLoopIntH As PP1H                          ' /
    Dim USART1_wInsideLoop    As USART1_bInsideLoopInt.Word    ' Alias the inside loop to PP1\H
    Dim USART1_wOutsideLoop  As PRODL.Word                    ' Alias the outside loop to PRODL\H registers
    Dim USART1_bIndexIn      As Byte Access                    ' Pointer to the next empty location in the buffer
    Dim USART1_bIndexOut      As Byte Access                    ' Pointer to the location of the oldest character in the buffer
    Dim USART1_bRXByte        As Byte Access                    ' Holds the byte received from USART1
'
' Create the actual serial buffer in high RAM
'
$define _cUSART1_BufferSize 128                                ' The amount of RAM reserved for the buffer (Max 255)
    Dim USART1_bRingBuffer[_cUSART1_BufferSize] As Byte Heap    ' Array for holding received bytes (in high RAM because it is used indirectly, so needs no RAM bank switching mnemonics)

    Dim USART1_wFSR0 As FSR0L.Word                              ' Combine SFRs FSR0L\H into a 16-bit SFR
    Dim USART1_wFSR1 As FSR1L.Word                              ' Combine SFRs FSR1L\H into a 16-bit SFR

'------------------------------------------------------------------------------
$ifndef IntGlobal_Enable
    $define IntGlobal_Enable()  INTCON0bits_GIE = 1    ' Enable global interrupts
$endif
$ifndef IntGlobal_Disable
    $define IntGlobal_Disable() INTCON0bits_GIE = 0    ' Disable global interrupts
$endif

'------------------------------------------------------------------------------
$ifndef IntPeriph_Enable
    $define IntPeriph_Enable()  INTCON0bits_GIEL = 1    ' Enable peripheral interrupts
$endif
$ifndef IntPeriph_Disable
    $define IntPeriph_Disable() INTCON0bits_GIEL = 0    ' Disable peripheral interrupts
$endif

'------------------------------------------------------------------------------
$define USART1_RX_IntEnable()  PIE3bits_U1RXIE = 1      ' Enable interrupt on USART1 receive
$define USART1_RX_IntDisable() PIE3bits_U1RXIE = 0      ' Disable interrupt on USART1 receive

'------------------------------------------------------------------------------
$define USART1_TX_IntEnable()  PIE3bits_U1TXIE = 1      ' Enable interrupt on USART1 transmit
$define USART1_TX_IntDisable() PIE3bits_U1TXIE = 0      ' Disable interrupt on USART1 transmit

'------------------------------------------------------------------------------
' Disable USART1 RX and TX
'
$define USART1_Disable() '
    U1CON0bits_TXEN = 0  '
    U1CON0bits_RXEN = 0

'------------------------------------------------------------------------------
' Enable USART1 RX and TX
'
$define USART1_Enable() '
    U1CON0bits_TXEN = 1 '
    U1CON0bits_RXEN = 1

'------------------------------------------------------------------------------
$define USART1_TX_Disable() U1CON0bits_TXEN = 0        ' Disable USART1 TX
$define USART1_TX_Enable()  U1CON0bits_TXEN = 1        ' Enable USART1 TX

'------------------------------------------------------------------------------
$define USART1_RX_Disable() U1CON0bits_RXEN = 0        ' Disable USART1 RX
$define USART1_RX_Enable()  U1CON0bits_RXEN = 1        ' Enable USART1 RX

'------------------------------------------------------------------------------
$define USART1_RX_Flag() PIR3bits_U1RXIF                ' The bit that indicates a byte has been received on USART1
$define USART1_TX_Flag() PIR3bits_U1TXIF                ' The bit that indicates a byte is being transmitted by USART1

'------------------------------------------------------------------------------

    GoTo _USART1_Main                                  ' Jump over the command replacement subroutines

'------------------------------------------------------------------------------
' Wait for a byte from the interrupt driven circular buffer with timeout
' Input    : GEN\GENH hold the timeout value in approx ms (0 to 65535)
' Output    : PP0 and WREG hold the value received
'          : Carry Flag (STATUS.0) Clear if timeout out
' Notes    : Replaces the compiler's HRsin1/HSerin1 library routine with timeout
'          : Uses PRODL\H as temporary variable storage
'          : Uses FSR0L\H as buffer the pointer
'
__HRsin1_With_TimeOut__:
    USART1_wOutsideLoop = USART1_wTimeoutValue          ' Save the timeout value so it doesn't get overwritten
    USART1_wInsideLoop = 0                              ' Reset the inside loop counter
_USART1_OutsideLoop:
    DelayCS 2                                          ' Delay for 2 cycles within the outside loop
_USART1_InsideLoop:
    DelayCS 1                                          ' Delay for 1 cycle within the inside loop
    WREG = USART1_bIndexIn                              ' \
    Subwf    USART1_bIndexOut,w                        ' / Is there anything in the serial buffer?
    Bnz      USART1_GetByte                            ' Yes. So fetch it
    WREG = 255                                          ' \
    Addwf    USART1_wInsideLoop,f                      ' |
    Addwfc    USART1_wInsideLoopH,f                    ' | Decrement the inside and outside loops
    Addwfc    USART1_wOutsideLoop,f                    ' |
    Addwfc    USART1_wOutsideLoopH,f                    ' /
    Btfss    STATUSbits_C
    Ret                                                ' Return with the Carry flag clear to indicate timed out
    Infsnz    USART1_wInsideLoop,w
    Incfsz    USART1_wInsideLoopH,w
    GoTo _USART1_OutsideLoop
    USART1_wInsideLoop = ((60 * Xtal) / 4)              ' Set the inside loop counter based upon the Xtal frequency
    GoTo _USART1_InsideLoop

'------------------------------------------------------------------------------
' Wait for a byte from the interrupt driven circular USART1 buffer without timeout
' Input    : None
' Output    : WREG holds the value received
' Notes    : Replaces the compiler's HRsin1/HSerin1 library routine without timeout
'          : Uses FSR0L\H as buffer pointers
'
__HRsin1__:
    While USART1_bIndexIn = USART1_bIndexOut            ' Wait for a byte to appear in the serial buffer
    Wend
'
' Fall through to USART1_GetByte
'------------------------------------------------------------------------------
' Read a byte from the USART1 interrupt driven circular buffer
' Input    : None
' Output    : PP0 and WREG hold the value received
' Notes    : Uses FSR0L\H as buffer pointers
'
Sub USART1_GetByte()
    Inc USART1_bIndexOut                                    ' Increment USART1_bIndexOut pointer (0 to 255)
    If USART1_bIndexOut >= _cUSART1_BufferSize Then        ' End of buffer reached?
        USART1_bIndexOut = 0                                ' Yes. So clear USART1_bIndexOut.
    EndIf
    USART1_wFSR0Save = USART1_wFSR0                        ' Save FSR0L\H registers
    USART1_wFSR0 = AddressOf(USART1_bRingBuffer)            ' Point FSR0L\H to USART1_bRingBuffer
    USART1_wFSR0 = USART1_wFSR0 + USART1_bIndexOut          ' Add the buffer position to FSR0L\H
    PP0 = INDF0                                            ' Read buffer location (USART1_bIndexOut) into PP0
    USART1_wFSR0 = USART1_wFSR0Save                        ' Restore FSR0\H registers
    WREG = PP0                                              ' Also place it into WREG
    STATUSbits_C = 1                                        ' Set the Carry flag to indicate a byte received
EndSub

'--------------------------------------------------------------------------------
' Replace the compiler's Hrsout1/HSerout1 library routine with this routine
' Input    : WREG holds the byte to transmit
' Output    : WREG still holds the byte transmitted
' Notes    : None
'
Sub __HRsout1__()
    PP0 = WREG                                              ' Save the byte to transmit
    Repeat: Until USART1_TX_Flag() = 1                      ' Wait for the TX buffer to be ready
    U1TXB = PP0                                            ' Send the byte
    WREG = PP0                                              ' Restore the contents of WREG
EndSub                                                      ' Exit the subroutine

'--------------------------------------------------------------------------------
' Initialise the USART1 RX interrupt
' Input    : None
' Output    : None
' Notes    : Enables interrupt on USART1 receive
'
Proc USART1_InitInterrupt()
    Global_tByteInBuffer1 = False                          ' Reset the byte in buffer flag
    USART1_bIndexIn = 0                                    ' Clear the buffer internal pointer
    USART1_bIndexOut = 0                                    ' Clear the buffer external pointer
    USART1_RX_IntEnable()                                  ' Enable interrupt on USART1 receive
EndProc

'--------------------------------------------------------------------------------
' Disable the USART1 RX interrupt
' Input    : None
' Output    : None
' Notes    : Disables interrupt on USART1 receive
'
Proc USART1_DisableInterrupt()
    Global_tByteInBuffer1 = False
    USART1_bIndexIn = 0                                    ' Clear the buffer internal pointer
    USART1_bIndexOut = 0                                    ' Clear the buffer external pointer
    USART1_RX_IntDisable()                                  ' Disable interrupt on USART1 receive
EndProc

'--------------------------------------------------------------------------------
' Clear the Serial Buffer
' Input    : None
' Output    : None
' Notes    : Also resets the index pointers to the serial buffer
'
Proc USART1_ClearSerialBuffer()
    USART1_RX_IntDisable()                              ' Disable interrupt on USART1 receive
    WREG = U1RXB                                        ' \ Empty the USART's 2-byte serial buffer
    WREG = U1RXB                                        ' /
    USART1_RX_Flag() = False                            ' Clear the byte received flag
    Clear USART1_bRingBuffer                            ' Clear the serial buffer
    Global_tByteInBuffer1 = False                      ' Reset the byte in buffer flag
    USART1_bIndexIn = 0                                ' Clear the buffer internal pointer
    USART1_bIndexOut = 0                                ' Clear the buffer external pointer
    USART1_RX_IntEnable()                              ' Re-Enable interrupt on USART1 receive
EndProc

'--------------------------------------------------------------------------------
' Enable USART1 and set it up for the buffer
' Input    : None
' Output    : None
' Notes    : None
'
Proc USART1_Open()
    Clear USART1_RX_Flag()                              ' Clear the RX flag
    USART1_Enable()                                    ' Enable USART1
    USART1_ClearSerialBuffer()                          ' Clear serial buffers
    USART1_InitInterrupt()                              ' Enable USART1 interrupt
EndProc

'--------------------------------------------------------------------------------
' Disable USART1
' Input    : None
' Output    : None
' Notes    : None
'
Proc USART1_Close()
    USART1_DisableInterrupt()                          ' Disable USART1 interrupt
    USART1_Disable()                                    ' Disable USART1
    Clear USART1_RX_Flag()                              ' Clear the RX flag
    USART1_ClearSerialBuffer()                          ' Clear serial buffers
EndProc

'--------------------------------------------------------------------------------
_USART1_Main:

$endif      ' _Buffered_Serial_



Place both files in the same directory and compile.

Screen shot from a terminal showing it working

SERIAL INT27K.jpg

krizpin

Quote from: RGV250 on Aug 09, 2022, 10:53 PMHi Krizpin,
A couple of questions.
Why do you need RS485 if you are only using 2 devices, are you planning to add more later. If it is just for distance it might be simpler to use 4 of the transceivers (2 for TX and 2 for RX) to go full duplex and then the software can transmit and receive simultaneously.
You have only shown the module, not how you have connected it to the PIC or between them etc.

As Les said, keep it simple, if I were doing it I would try with one sending and the other receiving, have you seen the example on page 246 of the manual, it couldn't get much simpler. Try that without the MAX485 transceivers, once that is working add the transceivers and try to get communication with them.

Bob
good morning. I will indeed connect more devices in the future. I have controlled the sending and receiving, it works correctly. The problem is that since I want them to work independently, sending and receiving data, I find myself with a lot of data conflict between sending/receiving. I can't find a code that organizes the flow back and forth well

krizpin

Quote from: See_Mos on Aug 10, 2022, 09:44 AMReading post #2 you are sending a packet of data at a time in each direction but not at the same time, is that correct?

How far apart will the PICs be in the final design?  Is isolation required?

As others have said, keep it simple. Unless you need full duplex start by connecting the PICs directly

I have done this before, about fifteen years ago, with 16F877s.  PIC one sends a packet of data with a checksum to PIC two which processes the data then returns a packet of data to PIC one.  I posted the information on the old forum.  If this is what you need then let us know and I will find it for you.
It is correct if, as I said, I have no problem sending data to the slave, processing it and sending it back to the master. but I want to do the same thing from the slave to the master regardless of who sends first, simply when one of the 2 pics performs some readings, send data to the other regardless of whether the other has already done them or not, I don't know if I'm explaining myself...

krizpin

Quote from: top204 on Aug 10, 2022, 10:07 AMAlso... If both devices are operating as master, and both are sending data to each other without one asking for it first, this will cause issues that can only be remedied by an interrupt serial buffer. Otherwise, while one device is busy, it may receive data from the other and miss it. However, with a serial buffer, the data will still be received, and when the device is finished what it is doing, the data from the other device will be in the buffer, ready to be read and acted upon.

For serial coms of any sort, a buffer is almost mandatory because it is async and send/receive timing is critical with it. For that reason alone, look to use an 18F device, or at the least, an enhanced 14-bit core device because they have a mechanism for linear RAM when operating indirectly, and that is exactly what a buffer, of any kind, needs.
Thanks for the information, it is very interesting but honestly it is totally beyond my knowledge. I learned to program proton based on reading, seeing examples, asking in forums, etc. Therefore, I do not have a solid foundation in programming like the rest of the people, I have simply been doing things and solving problems over time until I reached this point where I need to do precisely what you mention. A fellow forum member had told me about some rs485 devices that control the data flow by hardware. I guess that would be enough. thank you

krizpin

Quote from: JONW on Aug 10, 2022, 10:49 AMHere is an interrupt driven serial buffer for the 18F27k42, it's based on Les' HW serial interrupt code but modified to continually keep topping up the receive buffer until it finds the EOM character (in this case %).  Once it receives the EOL character it calls the parse procedure.  You can then parse the received string and return whatever you want.  Connect RX to TX.  There is a delay in the DO LOOP to flash LED.  This whole interrupt routine works perfectly. It should be fairly easy to modify to suit your needs.  This is built for a 27k development board i made so you can remove the pulse_led proc

'*******************************************************************
'*  Name    : HARDWARE SERIAL INTERRUPT                            *
'*  Author  : JON WALKER                                          *
'*  Notice  : Copyright (c) 2019 ELECIUM LTD                      *
'*          : All Rights Reserved                                  *
'*  Date    : 07/07/2022                                          *
'*                                                                *
'*  Version : 0.1                                                  *
'*******************************************************************

    Device = 18F27K42                                  ' Tell the compiler what device to compile for
    Declare Xtal = 64                                  ' Tell the compiler that the device will be running at 64MHz
    Declare Access_Upper_64K = True                    ' Set the compiler to see all 128K of flash memory

    On_Hardware_Interrupt GoTo ISR_Handler              ' Point to the interrupt handler routine

    $DEFINE EOM_CHAR  "%"                              ' CHARACTER TO FLAG END OF MESSAGE
    Declare Hserial1_Baud = 115200                      ' Set the Baud rate for USART1
    Declare Hserout1_Pin  = PORTC.6                    ' Set the pin used for USART1 TX
    Declare HSerin1_Pin  = PORTC.7                    ' Set the pin used for USART1 RX

    Include "USART1_Buffer_K42.inc"                    ' Load the buffered USART1 library routines into the program


    Dim TEMP As Byte
    DIM EOM_FLAG AS BIT                          ; SET WHEN END OF SERIAL STRING RECEIVED %
    ' PORT SETUP

    Dim LED1        As LATB.7
    Dim LED2        As LATB.6
'------------------------------------------------------------------------------------------------
' The main program starts here
' WHEN THE END OF MESSAGE CHARACTER IS RECEIVED THEN THE EOM_FLAG WILL BE SET TO SHOW DATA IN THE BUFFER

Main:
    Setup()                                            ' Setup the program
    LED1 = 0
    LED2 = 1

    Do
      if EOM_FLAG = 1 then                  ' WAIT FOR THE EOL CHARACTER
          PARSE()                            ' PARSE THE BYTES IN BUFFER
          EOM_FLAG = 0                        ; CLEAR THE END OF MESSAGE FLAG
          USART1_ClearSerialBuffer()
      EndIf

      DELAYMS 300                            ;LOOP INDEFINITELY
      TOGGLE LED1
      TOGGLE LED2
    Loop

'------------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------------
 '------------------------------------------------------------------------------------------------
' PARSE SERIAL BUFFER
' Input    : None
' Output    : None
' Notes    : None

 PROC PARSE()
      HRSOUT "THERE ARE ",DEC  (USART1_bIndexIn - 1), " BYTES IN THE BUFFER",13,10
      FOR TEMP = 1 to USART1_bIndexIn - 1 ' READ THE BUFFER OUT
          HRSOUT USART1_bRingBuffer[TEMP]
      Next
      HRSOUT 13,10
EndProc



'------------------------------------------------------------------------------------------------
' FLASH LED
' Input    : None
' Output    : None
' Notes    : None

 PROC PULSE_LED()
      LED1 = 1
      LED2 = 0
      FOR TEMP = 1 TO 10
          TOGGLE LED1
          TOGGLE LED2
          DELAYMS 50
      NEXT
      LED1 = 1
      LED2 = 0
EndProc


'------------------------------------------------------------------------------------------------
' Setup the program
' Input    : None
' Output    : None
' Notes    : None
'
Proc Setup()
    USART1_Open()                                      ' Open USART1 ready for the interrupt buffer
    IntPeriph_Enable()                                  ' Enable peripheral interrupts
    IntGlobal_Enable()                                  ' Enable global interrupts
EndProc

'------------------------------------------------------------------------------------------------
' Interrupt handler routine
' Input    : None
' Output    : Array USART1_bRingBuffer holds the characters received from USART1
'          : USART1_bIndexIn points to the current location within the USART1 buffer
'          : Global_tByteInBuffer1 is true if a byte was received on USART1
' Notes    : Interrupts on USART1 receive
'
ISR_Handler:
    Context Save FSR1L, FSR1H                          ' Save any compiler system variables and any SFRs used before we perform the interrupt code
'
' Check the USART1 RX interrupt
'
    If USART1_RX_Flag() = True Then                    ' Was it a USART1 byte receive that triggered the interrupt?
        USART1_bRXByte = U1RXB                          ' Yes. So place the byte received into USART1_bRXByte
        IF USART1_bRXByte = EOM_CHAR then
          EOM_FLAG = 1
        EndIf
        Inc USART1_bIndexIn                            ' Move up the buffer
        If USART1_bIndexIn >= _cUSART1_BufferSize Then  ' End of buffer reached?
            USART1_bIndexIn = 0                        ' Yes. So reset USART1_bIndexIn
        EndIf
        USART1_wFSR1 = AddressOf(USART1_bRingBuffer)    ' Point FSR1L\H to USART1_bRingBuffer
        USART1_wFSR1 = USART1_wFSR1 + USART1_bIndexIn  ' Add the buffer position to FSR1L\H
        INDF1 = USART1_bRXByte                          ' Place the received byte into the buffer
        Global_tByteInBuffer1 = True                    ' Indicate that there is a byte in the buffer
    EndIf

    Context Restore                                    ' Restore any compiler system variables and SFRs, then exit the interrupt routine



'---------------------------------------------------------------------------------------
' Setup for internal oscillator operating at 64MHz on a PIC18F27K42 device
'
Config_Start
    RSTOSC = HFINTOSC_64MHZ    ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
    FEXTOSC = Off              ' HS off
    WDTE = Off                  ' WDT Disabled. SWDTEN is ignored
    CLKOUTEN = Off              ' CLKOUT function is disabled
    PR1WAY = Off                ' PRLOCK bit can be set and cleared repeatedly
    CSWEN = On                  ' Writing to NOSC and NDIV is allowed
    Debug = Off                ' Background debugger disabled
    FCMEN = Off                ' Fail-Safe Clock Monitor disabled
    MCLRE = EXTMCLR            ' If LVP = 0, MCLR pin is MCLR. If LVP = 1, RE3 pin function is MCLR
    PWRTS = PWRT_Off            ' PWRT is disabled
    MVECEN = Off                ' Interrupt contoller does not use vector table to prioritise interrupts
    IVT1WAY = Off              ' IVTLOCK bit can be cleared and set repeatedly
    LPBOREN = Off              ' ULPBOR disabled
    BOREN = Off                ' Brown-out Reset disabled
    BORV = VBOR_2P45            ' Brown-out Reset Voltage (VBOR) set to 2.45V
    ZCD = Off                  ' ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off              ' PPSLOCK bit can be set and cleared repeatedly (subject to the unlock sequence)
    STVREN = Off                ' Stack full/underflow will not cause Reset
    XINST = Off                ' Extended Instruction Set and Indexed Addressing Mode disabled
    WDTCPS = WDTCPS_2          ' Divider ratio 1:128
    WDTCWS = WDTCWS_0          ' Window delay = 87.5. No software control. Keyed access required
    WDTCCS = LFINTOSC          ' WDT reference clock is the 31.0 kHz LFINTOSC
    BBSIZE = BBSIZE_1024        ' Boot Block size is 1024 words
    BBEN = Off                  ' Boot block disabled
    SAFEN = Off                ' SAF disabled
    WRTAPP = Off                ' Application Block not write protected
    WRTB = Off                  ' Configuration registers not write-protected
    WRTC = Off                  ' Boot Block not write-protected
    WRTD = Off                  ' EEPROM not write-protected
    WRTSAF = Off                ' SAF not Write Protected
    LVP = Off                  ' HV on MCLR/VPP must be used for programming
    Cp = Off                    ' PFM and EEPROM code protection disabled
Config_End



Here is the include file if you don't have it


$ifndef _Buffered_Serial_
$define _Buffered_Serial_
'
'  /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\    \/\\\                                                /\\\          /\\\
'  \/\\\\\\\\\\\/        /\\\\\    /\\\\\\\\\\    /\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'    \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\    \/\\\        \/\\\        /\\\\\\\\\\
'      \/\\\    \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\    \/\\\ /\\  /\\\/////\\\
'      \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\  \//\\\\\\\\/\\
'        \///        \///    \/////    \//////////    \//////////      \/////        \/////    \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Interrupt-driven serial buffer for USART1 receive using a hardware high priority interrupt.
' This subroutine replaces the compiler's Hserin1/Hrsin1, HSerout1/HRsout1 commands library subroutines
'
' Written by Les Johnson for the Positron8 compiler
'
' The library routine is for PIC18F27K42 and PIC18F47K42 devices only
'
$if _device <> _18F27K42 And _device <> _18F47K42
    $error "This library is only for the PIC18F27K42 or PIC18F47K42 devices"
$endif

    #Disable HRSIn1, HRSIn1To, HRSIn1_RCREG_Read, HRSOut1    ' Disable the library subroutines for Hrsin with and without timeouts, and Hrsout

$ifndef True
    $define True 1
$endif
$ifndef False
    $define False 0
$endif
'
' Create some Compiler system variables
'
    Dim BPF  As Byte System                                    ' A compiler system variable used by the LCD routines to initialise it after power up
    Dim GEN  As Byte System                                    ' \
    Dim GENH As Byte System                                    ' / Buffered Hrsin1 Timeout value storage
    Dim PP0  As Byte System                                    ' \
    Dim PP0H As Byte System                                    ' / Storage for FSR0L\H registers
    Dim PP1  As Byte System                                    ' \
    Dim PP1H As Byte System                                    ' / Buffred Hrsin1 Timeout inside loop counter
'
' Create variables for the interrupt buffered serial receiver
'
    Dim Global_tByteInBuffer1 As Bit                            ' Set true if a byte is received in the USART1 buffer
    Dim USART1_bTimeoutInt    As GEN                            ' \ Create some fill-in variables so they can be combined into 16-bits
    Dim USART1_bTimeoutIntH  As GENH                          ' /
    Dim USART1_wTimeoutValue  As USART1_bTimeoutInt.Word        ' Alias the timeout value to GEN\H
    Dim USART1_wFSR0Save      As Word Heap                      ' Alias the FSR0L\H storage to PP0\H
    Dim USART1_bInsideLoopInt As PP1                            ' \ Create some fill-in variables so they can be combined into 16-bits
    Dim USART1_bInsideLoopIntH As PP1H                          ' /
    Dim USART1_wInsideLoop    As USART1_bInsideLoopInt.Word    ' Alias the inside loop to PP1\H
    Dim USART1_wOutsideLoop  As PRODL.Word                    ' Alias the outside loop to PRODL\H registers
    Dim USART1_bIndexIn      As Byte Access                    ' Pointer to the next empty location in the buffer
    Dim USART1_bIndexOut      As Byte Access                    ' Pointer to the location of the oldest character in the buffer
    Dim USART1_bRXByte        As Byte Access                    ' Holds the byte received from USART1
'
' Create the actual serial buffer in high RAM
'
$define _cUSART1_BufferSize 128                                ' The amount of RAM reserved for the buffer (Max 255)
    Dim USART1_bRingBuffer[_cUSART1_BufferSize] As Byte Heap    ' Array for holding received bytes (in high RAM because it is used indirectly, so needs no RAM bank switching mnemonics)

    Dim USART1_wFSR0 As FSR0L.Word                              ' Combine SFRs FSR0L\H into a 16-bit SFR
    Dim USART1_wFSR1 As FSR1L.Word                              ' Combine SFRs FSR1L\H into a 16-bit SFR

'------------------------------------------------------------------------------
$ifndef IntGlobal_Enable
    $define IntGlobal_Enable()  INTCON0bits_GIE = 1    ' Enable global interrupts
$endif
$ifndef IntGlobal_Disable
    $define IntGlobal_Disable() INTCON0bits_GIE = 0    ' Disable global interrupts
$endif

'------------------------------------------------------------------------------
$ifndef IntPeriph_Enable
    $define IntPeriph_Enable()  INTCON0bits_GIEL = 1    ' Enable peripheral interrupts
$endif
$ifndef IntPeriph_Disable
    $define IntPeriph_Disable() INTCON0bits_GIEL = 0    ' Disable peripheral interrupts
$endif

'------------------------------------------------------------------------------
$define USART1_RX_IntEnable()  PIE3bits_U1RXIE = 1      ' Enable interrupt on USART1 receive
$define USART1_RX_IntDisable() PIE3bits_U1RXIE = 0      ' Disable interrupt on USART1 receive

'------------------------------------------------------------------------------
$define USART1_TX_IntEnable()  PIE3bits_U1TXIE = 1      ' Enable interrupt on USART1 transmit
$define USART1_TX_IntDisable() PIE3bits_U1TXIE = 0      ' Disable interrupt on USART1 transmit

'------------------------------------------------------------------------------
' Disable USART1 RX and TX
'
$define USART1_Disable() '
    U1CON0bits_TXEN = 0  '
    U1CON0bits_RXEN = 0

'------------------------------------------------------------------------------
' Enable USART1 RX and TX
'
$define USART1_Enable() '
    U1CON0bits_TXEN = 1 '
    U1CON0bits_RXEN = 1

'------------------------------------------------------------------------------
$define USART1_TX_Disable() U1CON0bits_TXEN = 0        ' Disable USART1 TX
$define USART1_TX_Enable()  U1CON0bits_TXEN = 1        ' Enable USART1 TX

'------------------------------------------------------------------------------
$define USART1_RX_Disable() U1CON0bits_RXEN = 0        ' Disable USART1 RX
$define USART1_RX_Enable()  U1CON0bits_RXEN = 1        ' Enable USART1 RX

'------------------------------------------------------------------------------
$define USART1_RX_Flag() PIR3bits_U1RXIF                ' The bit that indicates a byte has been received on USART1
$define USART1_TX_Flag() PIR3bits_U1TXIF                ' The bit that indicates a byte is being transmitted by USART1

'------------------------------------------------------------------------------

    GoTo _USART1_Main                                  ' Jump over the command replacement subroutines

'------------------------------------------------------------------------------
' Wait for a byte from the interrupt driven circular buffer with timeout
' Input    : GEN\GENH hold the timeout value in approx ms (0 to 65535)
' Output    : PP0 and WREG hold the value received
'          : Carry Flag (STATUS.0) Clear if timeout out
' Notes    : Replaces the compiler's HRsin1/HSerin1 library routine with timeout
'          : Uses PRODL\H as temporary variable storage
'          : Uses FSR0L\H as buffer the pointer
'
__HRsin1_With_TimeOut__:
    USART1_wOutsideLoop = USART1_wTimeoutValue          ' Save the timeout value so it doesn't get overwritten
    USART1_wInsideLoop = 0                              ' Reset the inside loop counter
_USART1_OutsideLoop:
    DelayCS 2                                          ' Delay for 2 cycles within the outside loop
_USART1_InsideLoop:
    DelayCS 1                                          ' Delay for 1 cycle within the inside loop
    WREG = USART1_bIndexIn                              ' \
    Subwf    USART1_bIndexOut,w                        ' / Is there anything in the serial buffer?
    Bnz      USART1_GetByte                            ' Yes. So fetch it
    WREG = 255                                          ' \
    Addwf    USART1_wInsideLoop,f                      ' |
    Addwfc    USART1_wInsideLoopH,f                    ' | Decrement the inside and outside loops
    Addwfc    USART1_wOutsideLoop,f                    ' |
    Addwfc    USART1_wOutsideLoopH,f                    ' /
    Btfss    STATUSbits_C
    Ret                                                ' Return with the Carry flag clear to indicate timed out
    Infsnz    USART1_wInsideLoop,w
    Incfsz    USART1_wInsideLoopH,w
    GoTo _USART1_OutsideLoop
    USART1_wInsideLoop = ((60 * Xtal) / 4)              ' Set the inside loop counter based upon the Xtal frequency
    GoTo _USART1_InsideLoop

'------------------------------------------------------------------------------
' Wait for a byte from the interrupt driven circular USART1 buffer without timeout
' Input    : None
' Output    : WREG holds the value received
' Notes    : Replaces the compiler's HRsin1/HSerin1 library routine without timeout
'          : Uses FSR0L\H as buffer pointers
'
__HRsin1__:
    While USART1_bIndexIn = USART1_bIndexOut            ' Wait for a byte to appear in the serial buffer
    Wend
'
' Fall through to USART1_GetByte
'------------------------------------------------------------------------------
' Read a byte from the USART1 interrupt driven circular buffer
' Input    : None
' Output    : PP0 and WREG hold the value received
' Notes    : Uses FSR0L\H as buffer pointers
'
Sub USART1_GetByte()
    Inc USART1_bIndexOut                                    ' Increment USART1_bIndexOut pointer (0 to 255)
    If USART1_bIndexOut >= _cUSART1_BufferSize Then        ' End of buffer reached?
        USART1_bIndexOut = 0                                ' Yes. So clear USART1_bIndexOut.
    EndIf
    USART1_wFSR0Save = USART1_wFSR0                        ' Save FSR0L\H registers
    USART1_wFSR0 = AddressOf(USART1_bRingBuffer)            ' Point FSR0L\H to USART1_bRingBuffer
    USART1_wFSR0 = USART1_wFSR0 + USART1_bIndexOut          ' Add the buffer position to FSR0L\H
    PP0 = INDF0                                            ' Read buffer location (USART1_bIndexOut) into PP0
    USART1_wFSR0 = USART1_wFSR0Save                        ' Restore FSR0\H registers
    WREG = PP0                                              ' Also place it into WREG
    STATUSbits_C = 1                                        ' Set the Carry flag to indicate a byte received
EndSub

'--------------------------------------------------------------------------------
' Replace the compiler's Hrsout1/HSerout1 library routine with this routine
' Input    : WREG holds the byte to transmit
' Output    : WREG still holds the byte transmitted
' Notes    : None
'
Sub __HRsout1__()
    PP0 = WREG                                              ' Save the byte to transmit
    Repeat: Until USART1_TX_Flag() = 1                      ' Wait for the TX buffer to be ready
    U1TXB = PP0                                            ' Send the byte
    WREG = PP0                                              ' Restore the contents of WREG
EndSub                                                      ' Exit the subroutine

'--------------------------------------------------------------------------------
' Initialise the USART1 RX interrupt
' Input    : None
' Output    : None
' Notes    : Enables interrupt on USART1 receive
'
Proc USART1_InitInterrupt()
    Global_tByteInBuffer1 = False                          ' Reset the byte in buffer flag
    USART1_bIndexIn = 0                                    ' Clear the buffer internal pointer
    USART1_bIndexOut = 0                                    ' Clear the buffer external pointer
    USART1_RX_IntEnable()                                  ' Enable interrupt on USART1 receive
EndProc

'--------------------------------------------------------------------------------
' Disable the USART1 RX interrupt
' Input    : None
' Output    : None
' Notes    : Disables interrupt on USART1 receive
'
Proc USART1_DisableInterrupt()
    Global_tByteInBuffer1 = False
    USART1_bIndexIn = 0                                    ' Clear the buffer internal pointer
    USART1_bIndexOut = 0                                    ' Clear the buffer external pointer
    USART1_RX_IntDisable()                                  ' Disable interrupt on USART1 receive
EndProc

'--------------------------------------------------------------------------------
' Clear the Serial Buffer
' Input    : None
' Output    : None
' Notes    : Also resets the index pointers to the serial buffer
'
Proc USART1_ClearSerialBuffer()
    USART1_RX_IntDisable()                              ' Disable interrupt on USART1 receive
    WREG = U1RXB                                        ' \ Empty the USART's 2-byte serial buffer
    WREG = U1RXB                                        ' /
    USART1_RX_Flag() = False                            ' Clear the byte received flag
    Clear USART1_bRingBuffer                            ' Clear the serial buffer
    Global_tByteInBuffer1 = False                      ' Reset the byte in buffer flag
    USART1_bIndexIn = 0                                ' Clear the buffer internal pointer
    USART1_bIndexOut = 0                                ' Clear the buffer external pointer
    USART1_RX_IntEnable()                              ' Re-Enable interrupt on USART1 receive
EndProc

'--------------------------------------------------------------------------------
' Enable USART1 and set it up for the buffer
' Input    : None
' Output    : None
' Notes    : None
'
Proc USART1_Open()
    Clear USART1_RX_Flag()                              ' Clear the RX flag
    USART1_Enable()                                    ' Enable USART1
    USART1_ClearSerialBuffer()                          ' Clear serial buffers
    USART1_InitInterrupt()                              ' Enable USART1 interrupt
EndProc

'--------------------------------------------------------------------------------
' Disable USART1
' Input    : None
' Output    : None
' Notes    : None
'
Proc USART1_Close()
    USART1_DisableInterrupt()                          ' Disable USART1 interrupt
    USART1_Disable()                                    ' Disable USART1
    Clear USART1_RX_Flag()                              ' Clear the RX flag
    USART1_ClearSerialBuffer()                          ' Clear serial buffers
EndProc

'--------------------------------------------------------------------------------
_USART1_Main:

$endif      ' _Buffered_Serial_



its built for a 27k42, place both files in the same directory and compile.

Screen shot from a terminal showing it working

SERIAL INT27K.jpg

Thank you very much, I will study the code and try to test it. thank you all really and sorry for my english... google translator...

JonW

#19
Have you tried arbitration, basically before sending any packet on the bus, monitor the bus for silence then insert a random delay before sending packets, this may help to reduce conflicts when transmitting data onto the bus. Keep data packets small or use compression to reduce the data packet size if its large
Look in the manual for creating random numbers using SEED command.  Remember that the above routine will keep topping up the circular buffer and wont break until EOM character is received.  You will need to build your own protocol to ensure packets are processed correctly.