News:

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

Main Menu

Interrupt for USART

Started by chris_cb_uk, Oct 27, 2021, 05:21 PM

Previous topic - Next topic

chris_cb_uk

Hi all, I'm establishing a 2 way communication between pics separated over fibre over quite a distance.  I have comms working of a fashion using timeout's to jump to the next sequence to avoid hanging i.e. using the wait function, however thinking that having the pics running on interrupts for their receive would be the best solution to make sure I'm not missing bytes from overflowing and or the programs are running efficiently.  I'm poking I2C sensors and Dallas devices to transmit their values and waiting for these to reply is causing some issues.

I'm using 18F4550 using hrsout on the hardware EUSART ports, I've never dealt with interrupts but understand the flags I'm looking for are RCIF 1 being full, 0 being empty.  I just need a little help in how to correctly assign the interrupt, calling the function and how to restore out of it.

Any help appreciated.

Chris

TimB

#1
Les in the samples has a USART interrupt example

I have included some I got from a bit of code I have. Loads of non useful stuff but it covers most of what you need.

I highly recommend you use a timed packet system. Where you time the period between data. If the data does not all come through then after it times out you reset your statemachine to ignore that packet and wait for the next one.

The Modbus system kind of works like that. With work you can also implement an ACK system so if the data sent has a CRC (it needs to) you can send that back to say OK got some data.
The RX code should also check the CRC is right before sending the ACK. The TX side can time for the ACK. If it does not get it within x ms then it resends. Perhaps for for x times. If after x retries it can signal data lost to slave and take action.

; Set up the usart to run at the right speed and interrupt on high level ints

;Usart 1
;Calculated Baudrate = 38462 @ Xtal 48MHz, Error = 0.16%
    RCSTA = 144 ; Enable continuous receive
    TXSTA = 36  ; Enable transmit, BRGH = 1
    SPBRG = 77  ; Baud Rate Generator Value

    ;Calculated Baudrate = 38462 @ Xtal 48MHz, Error = 0.16%
    RCSTA2 = 144 ; Enable continuous receive
    TXSTA2 = 36  ; Enable transmit, BRGH = 1
    SPBRG2 = 77  ; Baud Rate Generator Value

;Usart 2
; ENABLE USART RECEIVE INTERRUPTS
    RC1IP = 1                                                                     ; USART1 HAS HIGH PRIORITY
    RC2IP = 1                                                                     ; USART2 HAS HIGH PRIORITY
    RCIE = 1
    RCIE = 1
    RC2IE = 1
    CREN1 = 1
    CREN2 = 1
    SPEN1 = 1
    SPEN2 = 1
   
    TX1IP = 1                                                                     ; TX Usart Int is high priority
    TX2IP = 1                                                                     ; TX Usart Int is high priority
    TX1GenDataSent = True                                                         ; Info flags
    TX2DataSent = True
   
    TRISC.6 = 0                                                                   ' Set the TX ports as output so the data can come out
    TRISB.6 = 0


;-------------------------------------------------------------------------------

;*=============================================================*
;   Usart interrupt
;   Hanldes the RX and TX of data
;*=============================================================*


Usart_Int:
    Reset_Bank
    If OERR1 = 1 Then GoTo USART_ERR1                                           ; Check for usart1 overrun
    If OERR2 = 1 Then GoTo USART_ERR2                                           ; Check for usart1 overrun

    HiIntFSRSave = FSR_0                                                        ; Save the FSR Reg

    If RCIF = True Then                                                         ; If this is a RX1 interrupt
        HighIntTemp = RCREG1                                                    ; Make a working copy of the data
        RX1DataBuffer[RX1DataBufferPointer] = HighIntTemp                       ; Load the data into our buffer
        If RX1DataBufferPointer < RX1DataBufferSize Then                        ; make sure we are below our buffer size
            Inc RX1DataBufferPointer                                            ; Move our pointer up
            RX1FrameTimer = RX1FrameTimerReloadVal
        Else                                                                    ; too much data to quick reset needed
            RX1FrameTimer = RX1FrameTimerReloadVal
            RX1DataBufferPointer = 0                                            ; Reset the buffer pointers and timers
        EndIf
    EndIf

    If RC2IF = True Then                                                        ; If this is a RX2 interrupt
        HighIntTemp = RCREG2                                                    ; Make a working copy of the data
        RX2DataBuffer[RX2DataBufferPointer] = HighIntTemp                       ; Load the data into our buffer
        If RX2DataBufferPointer < RX2DataBufferSize Then                        ; make sure we are below our buffer size
            Inc RX2DataBufferPointer                                            ; Move our pointer up
        RX2FrameTimer = RX2FrameTimerReloadVal
        Else                                                                    ; too much data to quick reset needed
            RX2FrameTimer = RX2FrameTimerReloadVal
            RX2DataBufferPointer = 0                                            ; Reset the buffer pointers and timers
        EndIf
    EndIf

    ; Code to send the data from the TX buffer1
    If TX1IE = 1 Then                                                           ; Only do the rest if the TX1 interrupts are enabled, its our way to control the system
        If TX1IF = True Then                                                    ; If this is a TX interrupt
            If TX1PacketType = TX1PType_MainData Then
                If TX1GenDataBufferPointer >= TX1GenBufferCount Then            ; Check if there is more data to send
                    TX1IE = 0                                                   ; Buffer empty so turn of interrupts for now
                    TX1FrameTimer = TX1FrameTimerReloadVal
                Else
                    TXREG1 = TX1GenDataBuffer[TX1GenDataBufferPointer]          ; Send the data
                    Inc TX1GenDataBufferPointer                                 ; Move the pointer to the next byte
                    TX1GenDataSent = False                                      ; Mark there is still data to send
                    TX1FrameTimer = TX1FrameTimerReloadVal
                EndIf
            Else
                If TX1MsgReplyBufferPointer >= TX1MsgReplyPacket Then           ; Check if there is more data to send
                    TX1IE = 0                                                   ; Buffer empty so turn of interrupts for now
                    TX1FrameTimer = TX2FrameTimerReloadVal
                Else
                    TXREG1 = TX1MsgReplyBuffer[TX1MsgReplyBufferPointer]        ; Send the data
                    Inc TX1MsgReplyBufferPointer                                ; Move the pointer to the next byte
                    TX1GenDataSent = False                                      ; Mark there is still data to send
                    TX1FrameTimer = TX1FrameTimerReloadVal
                EndIf
            EndIf
        EndIf
    EndIf

    ; Code to send the data from the TX buffer2
    If TX2IE = 1 Then                                                           ; Only do the rest if the TX1 interrupts are enabled, its our way to control the system
        If TX2IF = True Then                                                    ; If this is a TX interrupt
            If TX2PacketType = TX2PType_MainData Then
                If TX2DataOutBufferPointer >= TX2BufferCount Then               ; Check if there is more data to send
                    TX2IE = 0                                                   ; Buffer empty so turn of interrupts for now
                    TX2FrameTimer = TX2FrameTimerReloadVal
                Else
                    TXREG2 = TX2GenDataBuffer[TX2DataOutBufferPointer]          ; Send the data
                    Inc TX2DataOutBufferPointer                                 ; Move the pointer to the next byte
                    TX2DataSent = False                                         ; Mark there is still data to send
                    TX2FrameTimer = TX2FrameTimerReloadVal
              EndIf
          Else
              If TX2MsgReplyBufferPointer >= TX2MsgReplyPacket Then           ; Check if there is more data to send
                    TX2IE = 0                                                   ; Buffer empty so turn of interrupts for now
                    TX2FrameTimer = TX2FrameTimerReloadVal
              Else
                    TXREG2 = TX2MsgReplyBuffer[TX2MsgReplyBufferPointer]        ; Send the data
                    Inc TX2MsgReplyBufferPointer                                ; Move the pointer to the next byte
                    TX2DataSent = False                                         ; Mark there is still data to send
                    TX2FrameTimer = TX2FrameTimerReloadVal
              EndIf
          EndIf
        EndIf
    EndIf

USART_EXIT:
    FSR_0 = HiIntFSRSave
    USART_EXIT2:
    Retfie Fast

USART_ERR1:                                                                     ; Handle a usart overrun error
    WREG = RCREG1                                                               ; Clear the regs
    CREN1 = 0
    CREN1 = 1
    TX1FrameTimer = 0                                                           ; Clear the regs
    RX1DataBufferPointer = 0
    GoTo Usart_Int                                                              ; Jump back to the start
   
USART_ERR2:                                                                     ; Handle a usart overrun error
    WREG = RCREG2                                                               ; Clear the regs
    CREN2 = 0
    CREN2 = 1
    TX2FrameTimer = 0                                                           ; Clear the regs
    RX2DataBufferPointer = 0                                                    ; Reset the buffer pointer
    GoTo Usart_Int



chris_cb_uk

Thanks Tim, I've picked out some key points in your code that I was lacking understanding of for interrupts. 
Interesting about modbus, I have experience of this from PLC backgrounds in a previous life programming S7 Siemens Ladder.  I think this will be the most robust solution for avoiding clashes, time outs and enabling everything to be clocked in, and out with certainty backwards and fourth.

Teo

Hi Tim,
How can I use interrupts for USART 1 on the 18F26K22?
I used:
PIE1 = %00100000
If PIR1.5 = 1 Then ....
and it doesn't work.
Thanks for the help,
Teo

charliecoutas

Hi Teo

I'm sure Tim won't mind me helping you a little with this. What else have you set up? You need to set some more things up, enable interrupts, baud rate, set the flag RC1IE etc.

Charlie

Teo

Hi Charlie,

    INTCON.6 = 1        ' Enable Peripheral Interrupt
    INTCON.4 = 1        ' Enable PORTB IOC
    INTCON.7 = 1        ' Global interrupt enable
    INTCON2.6 = 0       ' Interrupt on falling edge
    PIE1.5 = 1

Thanks in advance,
Teo

RGV250

#6
Hi Teo,
How about posting whole but (not) working code so we can see everything. From memory you need to clear the interrupt flag in the interrupt or it will only occur once.

Have you looked at the "Buffered_Hserin_Test" in the new samples folder.

Regards,
Bob

Teo

Thank you,
I am looking now.
Have a pleasant evening,
Teo

CPR

Here is what I used to receive bytes on UART1 from a Nextion display. This code is within my interrupt routine.
PIC 18F26K22 @ 64Mhz

'//---------------------    RX UART1

            If RC1IE = 1 Then
            If RC1IF = 1 Then                                   '// There are Byte(s) received from local Nextion on UART1

                If RCSTA1.2 = 1 Then
                        dummy1 = RCREG1                         '// Note: Reading RCREG1 resets RC1IF
                    ElseIf RCSTA1.1 = 1 Then
                        RCSTA1.4 = 0
                        RCSTA1.4 = 1
                    Else
                        dummy1 = RCREG1
                        inComing1[inPointer1] = dummy1
                        nextFlag = 1                            '// Byte(s) have arrived/ing from Nextion to PIC
                       
                        Inc inPointer1
                    If  inPointer1 > SS Then
                        inPointer1 = 0
                    EndIf
                EndIf

            EndIf
            EndIf


Make sure you've set PMD0.6 to "0" (to power on the module) That was a "gotcha" that had me for a while...

'// UART1
        Symbol UART1MD  = PMD0.6
        UART1MD         = 0                '// "0" Power to module is enabled

To write a byte(s) to UART1 I used -
                                  '// UART1 WRITE ONE BYTE
Proc writeUart1(toSend1 As Byte)
   
        TXREG1 = toSend1
        While TRMT1 = 0
            Nop
        Wend

EndProc

Hope that helps

Teo

Hi,
Thank you all for the help.
I had made a wrong setting. Now it's OK.
Have a nice Sunday,
Teo

Teo

Hi,
I don't understand why this is happening .

   Main:   
     Setup()     
     Do       
        If x = 1 Then
           If Date_Rec = $1B  Then
              Comanda()             
           EndIf
        EndIf
     Loop
   
    ISR_HANDLER:
       Context Save   
       If PIR1.5 = 1 Then
          x=1
          Date_Rec = RC1REG         
       EndIf   
       Context Restore

'---------------------------------------------------------------------------------------------   
   Proc Comanda()
      If x=1 Then
         If Date_Rec = $4B Then
            'HRSOut "K"
            HRSOut2 "R"
            x=0
         EndIf
      EndIf
   EndProc

If I have
HRSOut "K"
HRSOut2 "R"
both USARTs will work.
If I only have
HRSOut2 "R"
it does not work.
Does anyone have any idea and how I can solve the problem?
Thanks in advance,
Teo
 

charliecoutas

Are you sure that you have the values right Teo? When you check what has been received, you only accept $1B (Escape in ASACII):

     Do       
        If x = 1 Then
           If Date_Rec = $1B  Then
              Comanda()             
           EndIf
        EndIf
     Loop

Charlie

Mapo

Hi Teo,
are you sure you have set the 2 UART ports correctly?

Teo

Hi,
It seems like there is some interference between the USART1 and USART2 settings.
Thanks in advance,
Teo

trastikata

Hello Teo,

now when you sent me both codes I understood what you meant. The quirk  is that the compiler will set-up the UART only if it sees a valid Positron command related to the UART module.

Using declares like Baud rate and pins (Declare Hserial_Baud , Declare HSerin_Pin, HSerout_Pin ...) for the UART module does not set the UART.

The UART module will be set-up only if the compiler sees an UART command.

So in your second example you read the UART inbound register but this happens using direct register assignment "Date_Rec = RC1REG", so the UART1 does not get set-up.

Thus, to force the compiler to set the UART modules, just place one line HRSOut "1" : HRSOut2 "2" somewhere outside of the main program where it will never be executed but will force the compiler to make the necessary UART settings.

Best regards.

top204

The PIC18F26K22 device is one of my favourite devices, because it has just the right internals to make it very useful, even though it is around 16 years old now!

So I created a serial receive buffer for it a few years ago, and over time, I have improved upon it, and added the code for two USARTs.

The code listing for the serial receive interrupt buffer is below, and the SFRs are for the PIC18Fx6K22 devices, but the code itself will work on any 18F device if the SFRs are changed to suit the device, and the 18F device has enough RAM for the buffer sizes chosen etc...

$ifndef _RX_Buffered_Dual_Serial_
$define _RX_Buffered_Dual_Serial_
'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Interrupt-driven serial buffer for USART1 and USART2 receive using a hardware high priority interrupt.
' The subroutines replace the compiler's Hserin1/Hrsin1 and Hserin2/Hrsin2 commands library subroutines.
'
' The SFRs in this code listing are for PIC18Fx6K22 devices.
' However the code itself will work with any 18F devices, if the SFRs are changed to suit the device being used.
'
' Written for the Positron8 compiler by Les Johnson.
' https://sites.google.com/view/rosetta-tech/positron-compilers-experimenters-notebook.
'
    #Disable HRSIn1, HRSIn1To, HRSIn_RCREG_Read             ' Disable the library subroutines for Hrsin1 with and without timeouts
    #Disable HRSIn2, HRSIn2To, HRSIn2_RCREG_Read            ' Disable the library subroutines for Hrsin2 with and without timeouts
'
' Create the Access RAM compiler system variables and aliases for the Buffered commands
'
    Dim GEN  As Byte System                                 ' \
    Dim GENH As Byte System                                 ' / Buffered HRsinx Timeout value storage
    Dim PP0  As Byte System                                 ' Holds the return byte from HRsinx
'
' Create variables for the interrupt buffered USART1 and USART2 serial
'    
    Dim USARTx_bRXByte       As Byte Access                 ' Holds the byte received from USART1 or USART2
    Dim USARTx_wFSR0Save     As Word Heap                   ' Used to save/restore SFRs FSR0L\H
    Dim USARTx_TimeoutInt    As GEN
    Dim USARTx_TimeoutIntH   As GENH
    Dim USARTx_wTimeoutValue As USARTx_TimeoutInt.Word      ' Alias the timeout value to GEN\H
    Dim USARTx_wInsideLoop   As Word Access                 ' Timeout inside loop variable
    Dim USARTx_wOutsideLoop  As Word Access                 ' Timeout outside loop variable
'
' Create variables for the interrupt buffered USART1 serial
'  
    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
'
' Create the USART1 serial buffer in high RAM
'
$define _cUSART1_BufferSize 128                             ' The amount of RAM reserved is the buffer size (Max 255)
    Dim USART1_bRingBuffer[_cUSART1_BufferSize] As Byte Heap ' Array for holding received characters
'
' Create variables for the interrupt buffered USART2 serial
'
    Dim USART2_bIndexIn       As Byte Access                ' Pointer to the next empty location in the buffer
    Dim USART2_bIndexOut      As Byte Access                ' Pointer to the location of the oldest character in the buffer
'
' Create the USART2 serial buffer in high RAM
'
$define _cUSART2_BufferSize 128                             ' The amount of RAM reserved is the buffer size (Max 255)
    Dim USART2_bRingBuffer[_cUSART2_BufferSize] As Byte Heap ' Array for holding received characters
'
' Create the System variables and aliases for the Buffered commands
'
    Dim USARTx_wFSR0 As FSR0L.Word                          ' Create a 16-bit SFR of FSR0L\H
    Dim USARTx_wFSR1 As FSR1L.Word                          ' Create a 16-bit SFR of FSR1L\H

$ifndef True
    $define True 1
$endif
$ifndef False
    $define False 0
$endif

'------------------------------------------------------------------------------
' Meta-macros for general interrupt controls on a PIC18F26K22 device
'
$define IntGlobal_Enable()  INTCONbits_GIE = 1              ' Enable global interrupts
$define IntGlobal_Disable() INTCONbits_GIE = 0              ' Disable global interrupts
$define IntPeriph_Enable()  INTCONbits_GIEL = 1             ' Enable peripheral interrupts
$define IntPeriph_Disable() INTCONbits_GIEL = 0             ' Disable peripheral interrupts

'------------------------------------------------------------------------------
' Meta-macros for USART1 controls on a PIC18F26K22 device
'
$define USART1_RX_Flag() PIR1bits_TXIF                      ' The bit that indicates a byte has been received
$define USART1_TX_Flag() PIR1bits_TXIF                      ' The bit that indicates a byte is being transmitted
$define USART1_Int_Enable()  PIE1bits_RCIE = 1              ' Enable interrupt on USART1 receive
$define USART1_Int_Disable() PIE1bits_RCIE = 0              ' Disable interrupt on USART1 receive
$define USART1_EnableWake()  BAUD1CONbits_WUE = 1           ' Enable wake from sleep with reception on USART1
$define USART1_DisableWake() BAUD1CONbits_WUE = 0           ' Disable waking from sleep via USART1
$define USART1_TX_Disable() TX1STAbits_TXEN = 0             ' Disable USART1 TX
$define USART1_TX_Enable()  TX1STAbits_TXEN = 1             ' Enable USART1 TX
$define USART1_RX_Disable() RC1STAbits_SPEN = 0             ' Disable USART1 RX
$define USART1_RX_Enable()  RC1STAbits_SPEN = 1             ' Enable USART1 RX
'
' Disable USART1
'
$define USART1_Disable() '
    TX1STAbits_TXEN = 0  '
    RC1STAbits_SPEN = 0
'
' Enable USART1
'
$define USART1_Enable() '
    TX1STAbits_TXEN = 1 '
    RC1STAbits_SPEN = 1

'------------------------------------------------------------------------------
' Meta-macros for USART2 controls on a PIC18F26K22 device
'
$define USART2_RX_Flag() PIR3bits_RC2IF                     ' The bit that indicates a byte has been received
$define USART2_TX_Flag() PIR3bits_TX2IF                     ' The bit that indicates a byte is being transmitted
$define USART2_Int_Enable()  PIE3bits_RC2IE = 1             ' Enable interrupt on USART1 receive
$define USART2_Int_Disable() PIE3bits_RC2IE = 0             ' Disable interrupt on USART1 receive
$define USART2_EnableWake()  BAUD2CONbits_WUE = 1           ' Enable wake from sleep with reception on USART2
$define USART2_DisableWake() BAUD2CONbits_WUE = 0           ' Disable waking from sleep via USART2
$define USART2_TX_Disable() TX2STAbits_TXEN = 0             ' Disable USART2 TX
$define USART2_TX_Enable()  TX2STAbits_TXEN = 1             ' Enable USART2 TX
$define USART2_RX_Disable() RC2STAbits_SPEN = 0             ' Disable USART2 RX
$define USART2_RX_Enable()  RC2STAbits_SPEN = 1             ' Enable USART2 RX
'
' Disable USART2
'
$define USART2_Disable() '
    TX2STAbits_TXEN = 0  '
    RC2STAbits_SPEN = 0
'
' Enable USART2
'
$define USART2_Enable() '
    TX2STAbits_TXEN = 1 '
    RC2STAbits_SPEN = 1

'------------------------------------------------------------------------------
    GoTo _USARTS_Main_                                      ' Jump over the replacement library subroutines

'------------------------------------------------------------------------------
' Wait for a byte from the USART1 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     : Uses FSR0L\H as buffer pointers
'
__HRsin1_With_TimeOut__:
    USARTx_wOutsideLoop = USARTx_wTimeoutValue              ' Save the timeout value so it doesn't get overwritten
    USARTx_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     USARTx_wInsideLoop,f                          ' |
    Addwfc    USARTx_wInsideLoopH,f                         ' | Decrement the inside and outside loops
    Addwfc    USARTx_wOutsideLoop,f                         ' |
    Addwfc    USARTx_wOutsideLoopH,f                        ' /
    Btfss     STATUSbits_C
    Ret                                                     ' Return with the Carry flag clear to indicate timed out
    Infsnz    USARTx_wInsideLoop,w
    Incfsz    USARTx_wInsideLoopH,w
    GoTo _USART1_OutsideLoop
    USARTx_wInsideLoop = ((59 * Xtal) / 4)                  ' Set the inside loop counter based upon the Xtal frequency
    GoTo _USART1_InsideLoop

'------------------------------------------------------------------------------
' Wait for a byte from the USART1 interrupt driven circular buffer without timeout
' Input     : None
' Output    : WREG holds the value received from USART1
' Notes     : Uses FSR0L\H as buffer pointers
'
__HRsin1__:
    While USART1_bIndexIn = USART1_bIndexOut: Wend          ' Wait for a byte to appear in the serial buffer                                     
'
' 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
'
USART1_GetByte:
    Inc USART1_bIndexOut                                    ' Increment the 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
    USARTx_wFSR0Save = USARTx_wFSR0                         ' Save FSR0L\H registers
    USARTx_wFSR0 = AddressOf(USART1_bRingBuffer)            ' Point FSR0L\H to USART1_bRingBuffer
    USARTx_wFSR0 = USARTx_wFSR0 + USART1_bIndexOut          ' Add the buffer position to FSR0L\H
    PP0 = INDF0                                             ' Read buffer location (USART1_bIndexOut) into PP0
    USARTx_wFSR0 = USARTx_wFSR0Save                         ' Restore FSR0\H registers
    WREG = PP0                                              ' Place PP0 into WREG
    STATUSbits_C = 1                                        ' Set the Carry flag to indicate a byte received
    Return

'------------------------------------------------------------------------------
' Wait for a byte from the USART2 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     : Uses FSR0L\H as buffer pointers
'
__HRsin2_With_TimeOut__:
    USARTx_wOutsideLoop = USARTx_wTimeoutValue              ' Save the timeout value so it doesn't get overwritten
    USARTx_wInsideLoop = 0                                  ' Reset the inside loop counter
_USART2_OutsideLoop:
    DelayCS 2                                               ' Delay for 2 cycles within the outside loop
_USART2_InsideLoop:
    DelayCS 1                                               ' Delay for 1 cycle within the inside loop
    WREG = USART2_bIndexIn                                  ' \
    Subwf     USART2_bIndexOut,w                            ' / Is there anything in the serial buffer?
    Bnz       USART2_GetByte                                ' Yes. So fetch it
    WREG = 255                                              ' \
    Addwf     USARTx_wInsideLoop,f                          ' |
    Addwfc    USARTx_wInsideLoopH,f                         ' | Decrement the inside and outside loops
    Addwfc    USARTx_wOutsideLoop,f                         ' |
    Addwfc    USARTx_wOutsideLoopH,f                        ' /
    Btfss     STATUSbits_C
    Ret                                                     ' Return with the Carry flag clear to indicate timed out
    Infsnz    USARTx_wInsideLoop,w
    Incfsz    USARTx_wInsideLoopH,w
    GoTo _USART2_OutsideLoop
    USARTx_wInsideLoop = ((59 * Xtal) / 4)                  ' Set the inside loop counter based upon the Xtal frequency
    GoTo _USART2_InsideLoop

'------------------------------------------------------------------------------
' Wait for a byte from the USART2 interrupt driven circular buffer without timeout
' Input     : None
' Output    : WREG holds the value received from USART2
' Notes     : Uses FSR0L\H as buffer pointers
'
__HRsin2__:
    While USART2_bIndexIn = USART2_bIndexOut: Wend          ' Wait for a byte to appear in the serial buffer
'
' Fall through to USART2_GetByte
'------------------------------------------------------------------------------
' Read a byte from the USART2 interrupt driven circular buffer
' Input     : None
' Output    : PP0 and WREG hold the value received
' Notes     : Uses FSR0L\H as buffer pointers
'
USART2_GetByte:
    Inc USART2_bIndexOut                                    ' Increment USART2_bIndexOut pointer (0 to 255)
    If USART2_bIndexOut >= _cUSART2_BufferSize Then         ' End of buffer reached?
        USART2_bIndexOut = 0                                ' Yes. So USART2_bIndexOut = 0
    EndIf
    USARTx_wFSR0Save = USARTx_wFSR0                         ' Save FSR0L\H registers
    USARTx_wFSR0 = AddressOf(USART2_bRingBuffer)            ' Point FSR0L\H to USART2_bRingBuffer
    USARTx_wFSR0 = USARTx_wFSR0 + USART2_bIndexOut          ' Add the buffer position to FSR0L\H
    PP0 = INDF0                                             ' Read buffer location (USART2_bIndexOut) into PP0
    USARTx_wFSR0 = USARTx_wFSR0Save                         ' Restore FSR0\H registers
    WREG = PP0                                              ' Place PP0 into WREG
    STATUSbits_C = 1                                        ' Set the Carry flag to indicate a byte received
    Return

'--------------------------------------------------------------------------------
' Initialise the USART1 interrupt
' Input     : None
' Output    : None
' Notes     : Enables interrupt on USART1 receive
'           : Enables global and peripheral interrupts
'
Proc USART1_InitInterrupt()
    USART1_bIndexIn = 0                                     ' Clear the buffer internal pointer
    USART1_bIndexOut = 0                                    ' Clear the buffer external pointer
    USART1_Int_Enable()                                     ' Enable interrupt on USART1 receive
EndProc

'--------------------------------------------------------------------------------
' Initialise the USART2 interrupt
' Input     : None
' Output    : None
' Notes     : Enables interrupt on USART2 receive
'           : Enables global and peripheral interrupts
'
Proc USART2_InitInterrupt()
    USART2_bIndexIn = 0                                     ' Clear the buffer internal pointer
    USART2_bIndexOut = 0                                    ' Clear the buffer external pointer
    USART2_Int_Enable()                                     ' Enable interrupt on USART2 receive
EndProc

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

'--------------------------------------------------------------------------------
' Disable the USART2 interrupt
' Input     : None
' Output    : None
' Notes     : Disables interrupt on USART2 receive
'
Proc USART2_DisableInterrupt()
    USART2_Int_Disable()                                    ' Disable interrupt on USART2 receive
    USART2_bIndexIn = 0                                     ' Clear the buffer internal pointer
    USART2_bIndexOut = 0                                    ' Clear the buffer external pointer
EndProc

'--------------------------------------------------------------------------------
' Clear the Serial Buffer for USART1
' Input     : None
' Output    : None
' Notes     : Also resets the index pointers to the serial buffer
'
Proc USART1_ClearSerialBuffer()
    'USART1_Int_Disable()                                    ' Disable interrupt on USART1 receive
    Clear USART1_bRingBuffer                                ' Clear the USART1 serial buffer array
    USART1_bIndexIn = 0                                     ' Clear the USART1 buffer internal pointer
    USART1_bIndexOut = 0                                    ' Clear the USART1 buffer external pointer
    'USART1_Int_Enable()                                     ' Re-Enable interrupt on USART1 receive
EndProc

'--------------------------------------------------------------------------------
' Clear the Serial Buffer for USART2
' Input     : None
' Output    : None
' Notes     : Also resets the index pointers to the serial buffer
'
Proc USART2_ClearSerialBuffer()
    'USART2_Int_Disable()                                    ' Disable interrupt on USART2 receive
    Clear USART2_bRingBuffer                                ' Clear the USART2 serial buffer array
    USART2_bIndexIn = 0                                     ' Clear the USART2 buffer internal pointer
    USART2_bIndexOut = 0                                    ' Clear the USART2 buffer external pointer
    'USART2_Int_Enable()                                     ' Re-Enable interrupt on USART2 receive
EndProc

'--------------------------------------------------------------------------------
' Enable USART1
' Input     : None
' Output    : None
' Notes     : Also alters the PPS
'
Proc USART1_Open()
    PinInput RX1_Pin                                        ' Set the RX1 pin as an input
    PinOutput TX1_Pin                                       ' Set the TX1 pin as an output
    USART1_RX_Flag() = 0                                    ' Clear the RX1 flag
    USART1_ClearSerialBuffer()                              ' Clear USART1 serial buffer array
    USART1_InitInterrupt()                                  ' Enable a USART1 interrupt
EndProc

'--------------------------------------------------------------------------------
' Enable USART2
' Input     : None
' Output    : None
' Notes     : Also alters the PPS
'
Proc USART2_Open()
    PinInput RX2_Pin                                        ' Set the RX2 pin as an input
    PinOutput TX2_Pin                                       ' Set the TX2 pin as an output
    USART2_RX_Flag() = 0                                    ' Clear the RX2 flag
    USART2_ClearSerialBuffer()                              ' Clear USART2 serial buffer array
    USART2_InitInterrupt()                                  ' Enable a USART2 interrupt
EndProc

'--------------------------------------------------------------------------------
' Disable USART1
' Input     : None
' Output    : None
' Notes     : None
'
Proc USART1_Close()
    USART1_DisableInterrupt()                               ' Disable USART1 interrupt
    USART1_Disable()                                        ' Disable USART1
    USART1_RX_Flag() = 0                                    ' Clear the RX1 flag
    USART1_ClearSerialBuffer()                              ' Clear USART1 serial buffer
EndProc

'--------------------------------------------------------------------------------
' Disable USART2
' Input     : None
' Output    : None
' Notes     : None
'
Proc USART2_Close()
    USART2_DisableInterrupt()                               ' Disable USART2 interrupt
    USART2_Disable()                                        ' Disable USART2
    USART2_RX_Flag() = 0                                    ' Clear the RX2 flag
    USART2_ClearSerialBuffer()                              ' Clear USART2 serial buffer
EndProc

'------------------------------------------------------------------------------
' Check if there is a byte received in the USART1 serial buffer
' Input     : None
' Output    : Returns true if a byte is in the USART1 buffer, else returns false if not
' Notes     : None
'
Proc USART1_ByteReceived(), Bit
    Result = False                                          ' Default to no byte in the buffer
    If USART1_bIndexIn <> USART1_bIndexOut Then             ' Is there a byte in the USART1 serial buffer?
        Result = True                                       ' Yes. So return a true result
    EndIf
EndProc

'------------------------------------------------------------------------------
' Check if there is a byte received in the USART2 serial buffer
' Input     : None
' Output    : Returns true if a byte is in the USART2 buffer, else returns false if not
' Notes     : None
'
Proc USART2_ByteReceived(), Bit
    Result = False                                          ' Default to no byte in the buffer
    If USART2_bIndexIn <> USART2_bIndexOut Then             ' Is there a byte in the USART2 serial buffer?
        Result = True                                       ' Yes. So return a true result
    EndIf
EndProc

'--------------------------------------------------------------------------------
_USARTS_Main_:

$endif      ' _RX_Buffered_Dual_Serial_



Name the file as "Buffered_Dual_Serial_18F26K22.inc".

Below is a code listing for a demo to show the serial receive buffer code working. It will receive data from both USARTs, and re-transmit it via the USART that received it. It has just been tested on a real PIC18F26K22 device, sitting on an Amicus8 board from Easy Driver, marketed by John.

The code works perfectly, and there is no interference between USART1 and USART2, so what is received by one is not received by the other, and the re-transmitted data is just the same as the data received by each USART. One important note, is that the USART2 does not work in the Proteus simulator with a PIC18F26K22 device, so "never, ever" trust it 100%, and remember, it is just an expensive toy!! It transmits, but with the wrong speeds on USART2. However, on a real device it works 100%

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Interrupt-driven serial buffer demonstration for USART1 and USART2 receive using a hardware High Priority Interrupt.
'
' Written by Les Johnson for the Positron8 BASIC Compiler.
' https://sites.google.com/view/rosetta-tech/positron-compilers-experimenters-notebook.
'
    Device = 18F26K22                                                   ' Tell the compiler what device to compile for
    Declare Xtal = 64                                                   ' Tell the compiler what frequency the device is operating at (in MHz)
    Declare Auto_Heap_Arrays = On                                       ' Make all arrays "Heap" types, so they always get placed after standard variables
    Declare Auto_Heap_Strings = On                                      ' Make all Strings "Heap" types, so they always get placed after standard variables
    Declare Auto_Variable_Bank_Cross = On                               ' Make sure all multi-byte variables remain within a single RAM bank

    On_Hardware_Interrupt GoTo ISR_Handler                              ' Point to the interrupt handler routine
'
' Setup USART1
' Note. Comment out the $define RX1_Pin if USART1 is not required for the serial receive buffer
'
$define TX1_Pin PORTC.6                                                 ' Define the USART1 TX pin
$define RX1_Pin PORTC.7                                                 ' Define the USART1 RX pin to enable the USART1 interrupt and procedures

    Declare HSerout1_Pin  = TX1_Pin                                     ' Tell the compiler what pin for USART1 TX
    Declare HSerin1_Pin   = RX1_Pin                                     ' Tell the compiler what pin for USART1 RX
    Declare Hserial1_Baud = 9600                                        ' Tell the compiler what Baud rate to set for USART1
'
' Setup USART2
' Note. Comment out the $define RX2_Pin if USART2 is not required for the serial receive buffer
'
$define TX2_Pin PORTB.6                                                 ' Define the USART2 TX pin
$define RX2_Pin PORTB.7                                                 ' Define the USART2 RX pin to enable the USART2 interrupt and procedures

    Declare HSerout2_Pin  = TX2_Pin                                     ' Tell the compiler what pin for USART2 TX
    Declare HSerin2_Pin   = RX2_Pin                                     ' Tell the compiler what pin for USART2 RX
    Declare Hserial2_Baud = 9600                                        ' Tell the compiler what Baud rate to set for USART2

    Include "Buffered_Dual_Serial_18F26K22.inc"                         ' Load the interrupt serial buffer routines
'
' Create some global variables for the demo program
'
    Dim ByteIn1 As Byte                                                 ' Holds the data received from USART1
    Dim ByteIn2 As Byte                                                 ' Holds the data received from USART2

'--------------------------------------------------------------------------------
' The main program starts here
' Receives data from USART1 and USART2 and re-transmits it
'
Main:
    Setup()                                                             ' Setup the program and peripherals

    HRSOut1Ln "Type in data for USART1 to receive"
    HRSOut2Ln "Type in data for USART2 to receive"
    Do                                                                  ' Create a loop
        If USART1_ByteReceived() = True Then                            ' Is there a byte received by USART1?
            ByteIn1 = HRSIn1                                            ' Yes. So fetch it from the buffer
            HRSOut1 ByteIn1                                             ' Re-transmit it via USART1
        EndIf

        If USART2_ByteReceived() = True Then                            ' Is there a byte received by USART2?
            ByteIn2 = HRSIn2                                            ' Yes. So fetch it from the buffer
            HRSOut2 ByteIn2                                             ' Re-transmit it via USART2
        EndIf
        DelayMS 255                                                     ' Create a silly large delay between serial data, to demonstrate the buffers working
    Loop                                                                ' Do it forever

'--------------------------------------------------------------------------------
' Setup the program and peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    Osc_64MHz()                                                         ' Set the internal oscillator to 64MHz

    USART1_Open()                                                       ' Setup and open USART1
    USART2_Open()                                                       ' Setup and open USART2

    IntPeriph_Enable()                                                  ' Enable peripheral interrupts
    IntGlobal_Enable()                                                  ' Enable global interrupts
EndProc

'--------------------------------------------------------------------
' Set the PIC18F26K22 device to 64MHz with the internal oscillator
' Input     : None
' Output    : None
' Notes     : Waits for the oscillator to become stable
'
Proc Osc_64MHz()
    OSCCON  = $70
    OSCCON2 = $04
    OSCTUNE = $40
    Repeat : Until OSCCON2bits_PLLRDY = 1                               ' Wait for the PLL to stabilise
EndProc

'--------------------------------------------------------------------------------
' Interrupt handler
' Input     : None
' Output    : Loads array USART1_bRingBuffer with data received by USART1
'           : Loads array USART2_bRingBuffer with data received by USART2
'           : USART1_bIndexIn holds the position within the USART1 buffer
'           : USART2_bIndexIn holds the position within the USART2 buffer
' Notes     : USART1 and USART2 SFRs are for PIC18Fx6K22 devices
'
ISR_Handler:
    Context Save, FSR1L, FSR1H                                          ' Save the device's SFRs and any compiler system variables
    Clrwdt                                                              ' Clear the watchdog timer (just in case it is enabled)
'
' USART1 serial RX buffer
'
$ifdef RX1_Pin                                                      ' Has the RX1_Pin been $defined at the beginning of the program listing?
    If USART1_RX_Flag() = True Then                                     ' Yes. So was it a USART1 byte receive that triggered the interrupt?
        WREG = RC1STA & %00000110                                       ' Yes. So mask out unwanted bits and check for errors
        If STATUSbits_Z = 0 Then                                        ' Are there any bits set in RC1STA?
            WREG = RC1REG                                               ' \ Yes. So empty the 2 byte USART1 buffer
            WREG = RC1REG                                               ' /
            RC1STAbits_CREN = 0                                         ' \ Clear receiver status
            RC1STAbits_CREN = 1                                         ' /
        Else                                                            ' Otherwise... No error so...
            USARTx_bRXByte = RC1REG                                     ' Place the byte received into a variable
            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
            USARTx_wFSR1 = AddressOf(USART1_bRingBuffer)                ' Point FSR1L\H to USART1_bRingBuffer
            USARTx_wFSR1 = USARTx_wFSR1 + USART1_bIndexIn               ' Add the buffer position to FSR1L\H
            INDF1 = USARTx_bRXByte                                      ' Place the received byte into the buffer
        EndIf
    EndIf
$endif      ' RX1_Pin
'
' USART2 serial RX buffer
'
$ifdef RX2_Pin                                                      ' Has the RX2_Pin been $defined At the beginning of the program listing?
    If USART2_RX_Flag() = True Then                                     ' Yes. So was it a USART2 byte receive that triggered the interrupt?
        WREG = RC2STA & %00000110                                       ' Yes. So mask out unwanted bits and check for errors
        If STATUSbits_Z = 0 Then                                        ' Are there any bits set in RC2STA?
            WREG = RC2REG                                               ' \ Yes. So empty the 2 byte USART2 buffer
            WREG = RC2REG                                               ' /
            RC2STAbits_CREN = 0                                         ' \ Clear receiver status
            RC2STAbits_CREN = 1                                         ' /
        Else                                                            ' Otherwise... No error so...
            USARTx_bRXByte = RC2REG                                     ' Place the byte received into a variable
            Inc USART2_bIndexIn                                         ' Move up the buffer
            If USART2_bIndexIn >= _cUSART2_BufferSize Then              ' End of buffer reached?
                USART2_bIndexIn = 0                                     ' Yes. So reset USART2_bIndexIn
            EndIf
            USARTx_wFSR1 = AddressOf(USART2_bRingBuffer)                ' Point FSR1L\H to USART2_bRingBuffer
            USARTx_wFSR1 = USARTx_wFSR1 + USART2_bIndexIn               ' Add the buffer position to FSR1L\H
            INDF1 = USARTx_bRXByte                                      ' Place the received byte into the buffer
        EndIf
    EndIf
$endif      ' RX2_Pin
    Context Restore                                                     ' Restore the device's SFRs and any compiler system variables, then exit the interrupt

'--------------------------------------------------------------------------------
' Setup the configuration fuses for a PIC18F26K22 to use the internal oscillator.
' OSC pins are general purpose I/O.
'
Config_Start
    FOSC     = INTIO67                                                  ' Internal oscillator block. Port function on RA6 and RA7
    PRICLKEN = Off                                                      ' Primary clock disabled
    MCLRE    = EXTMCLR                                                  ' MCLR pin enabled, RE3 input pin disabled
    WDTEN    = Off                                                      ' Watchdog Timer disabled
    Debug    = Off                                                      ' Background debugger disabled. RB6 and RB7 configured as general purpose I/O pins
    PLLCFG   = Off                                                      ' Oscillator used directly
    XINST    = Off                                                      ' Extended Instruction Set Disabled
    FCMEN    = Off                                                      ' Fail-Safe Clock Monitor disabled
    IESO     = Off                                                      ' Oscillator Switchover mode disabled
    PWRTEN   = On                                                       ' Power up timer enabled
    BOREN    = Off                                                      ' Brown-out Reset disabled
    BORV     = 190                                                      ' VBOR set to 1.9 V nominal
    WDTPS    = 128                                                      ' Watchdog ratio is 1:128
    HFOFST   = Off                                                      ' The Access Clock is not held off until the HF-INTOSC is stable
    PBADEN   = Off                                                      ' PORTB<4:0> pins are configured as digital on reset
    CCP2MX   = PORTC1                                                   ' CCP2 input/output is multiplexed with RC1
    CCP3MX   = PORTB5                                                   ' P3A/CCP3 input/output is multiplexed with RB5
    T3CMX    = PORTC0                                                   ' T3CKI is on RC0
    P2BMX    = PORTB5                                                   ' P2B is on RB5
    STVREN   = On                                                       ' Stack full/underflow will cause a reset
    LVP      = Off                                                      ' Single-Supply ICSP disabled
    Cp0      = Off                                                      ' Block 0 (000800-001FFF) not code-protected
    CP1      = Off                                                      ' Block 1 (002000-003FFF) not code-protected
    CPB      = Off                                                      ' Boot block (000000-0007FF) not code-protected
    CPD      = Off                                                      ' Data EEPROM not code-protected
    WRT0     = Off                                                      ' Block 0 (000800-001FFF) not write-protected
    WRT1     = Off                                                      ' Block 1 (002000-003FFF) not write-protected
    WRTB     = Off                                                      ' Boot block (000000-0007FF) not write-protected
    WRTC     = On                                                       ' Configuration registers (300000-3000FF) write-protected
    WRTD     = Off                                                      ' Data EEPROM not write-protected
    EBTR0    = Off                                                      ' Block 0 (000800-001FFF) not protected from table reads executed in other blocks
    EBTR1    = Off                                                      ' Block 1 (002000-003FFF) not protected from table reads executed in other blocks
    EBTRB    = Off                                                      ' Boot block (000000-0007FF) not protected from table reads executed in other blocks
Config_End

I have attached the demo and include files shown above, to this thread, and it is named: "18F26K22_Buffered_Dual_Serial.zip"

Teo

Hi friends
Thank you very much to both of you
Teo