News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Buying of PIC

Started by joesaliba, Sep 22, 2024, 05:09 PM

Previous topic - Next topic

joesaliba

I am trying to get hold of a couple of PIC18F06Q40.

Does anyone know a suitable place in Europe to buy from with reasonable shipping prices? Mouser and Farnell has the most ridiculous shipping prices, and Microchip Direct are adding a UK VAT, which I am not ready to pay, as items are not being delivered to UK but to Malta.

Regards

Joe 

Mapo


Gamboa

Joesaliba,

Regards,
GamboaDistributors.png
Long live for you

joesaliba

Quote from: Mapo on Sep 22, 2024, 08:05 PMTry TME.eu



Thank you Mapo, I ordered from them.

Ordered the PIC18F05Q41 in stock, should be sufficient for my needs.

Thank you
Kind regards

Joe

joesaliba


top204

#5
They are good prices, and very good devices. Because they are new devices, the prices are still very low, and they are a pleasure to work with. The querks come into play with some SFRs and peripherals because they have been changed for mysterious reasons, but they operate nicely.

On Ebay, the greedy b#st*rds are asking £8 or £9 for a single PIC Q device, and other PIC devices!

When did the world become so full of greedy b#st*rds? There has always been greed, but it seems to have become the normal practice now, to rip others off! And more mysteriously, it is accepted by the people with more money than sense, which falls through to the people who simply cannot afford it because of them, so they cannot get the enjoyment of something they love!... Capitalism! The scourge of the human species, where nothing else matters except money, and was supposed to be eradicated in the 21st century (or so I was taught when I was a boy at school, and on the television sci-fi programs back then)!.

I, sometimes, wish I had the capitalistic mentality, but I was not brought up like that, so I have ended up being ripped off multiple times in my working career by others who do have it. :-(

Enjoy using it Joe, the PIC18F05Q41 is a really nice device and I have worked with it and some other new Q devices (thanks to trastikata) for a project of my own, and they are a pleasure to use.

joesaliba

Exactly same thoughts re greedy.

They are on order from TME. Sure will come with a lot of questions to get these little things going.

Best regards

Joe

top204

#7
Here is a code listing template for a PIC18F05Q41 device operating at 64MHz using its internal oscillator, for when you receive your device. I have used it on a previous project, so I know it is working. It should also so work on the larger 18FxxQ41 devices:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A code listing template for a PIC18F05Q41 device using the internal oscillator at 64MHz.
' Written by Les Johnson for the Positron8 compiler.
'
    Device = 18F05Q41                                       ' Tell the compiler what device to compile for
    Declare Xtal = 64                                       ' Tell the compiler what frequency the device is operating at (in MHz)
'
' Setup USART1
'
    Declare Hserial1_Baud = 9600
    Declare HRSOut1_Pin = PORTC.4
    Declare HRSIn1_Pin = PORTC.5
'
' Setup USART2
'
    Declare Hserial2_Baud = 9600
    Declare HRSOut2_Pin = PORTC.1
    Declare HRSIn2_Pin = PORTC.2
'
' Create global variables and constants here
'

'-------------------------------------------------------------------------------------------------
' The main program starts here
'
Main:
    Setup()                                                 ' Setup the program and any peripherals

    Do

    Loop

'-------------------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()

EndProc
'
' More user procedures here, or placed before the Setup procedure...
'
'-------------------------------------------------------------------------------------------------
' Setup the config fuses for internal oscillator at 64MHz, with OSC pins as I\O
' For a PIC18F05Q41 device
'
Config_Start
    FEXTOSC = Off                           ' External Oscillator not enabled
    RSTOSC = HFINTOSC_64MHZ                 ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1

    CLKOUTEN = Off                          ' CLKOUT function is disabled
    PR1WAY = Off                            ' PRLOCKED bit can be set and cleared repeatedly
    CSWEN = On                              ' Writing to NOSC and NDIV is allowed
    FCMEN = On                              ' Fail-Safe Clock Monitor enabled
    FCMENP = On                             ' Fail-Safe Clock Monitor enabled. Timer will flag FSCMP bit and OSFIF interrupt on EXTOSC failure.
    FCMENS = On                             ' Fail-Safe Clock Monitor enabled. Timer will flag FSCMP bit and OSFIF interrupt on SOSC failure.

    MCLRE = EXTMCLR                         ' MCLR pin is used as MCLR
    PWRTS = PWRT_OFF                        ' PWRT is disabled
    MVECEN = Off                            ' Interrupt controller does not use vector table
    IVT1WAY = On                            ' IVTLOCKED bit can be cleared and set only once
    LPBOREN = On                            ' Low-Power BOR enabled
    BOREN = On                              ' Brown-out Reset enabled according to SBOREN

    BORV = VBOR_1P9                         ' Brown-out Reset Voltage (VBOR) set to 1.9V
    ZCD = Off                               ' ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                           ' PPSLOCKED bit can be set and cleared repeatedly
    STVREN = On                             ' Stack full/underflow will cause Reset
    LVP = Off                               ' HV on MCLR/VPP must be used for programming
    XINST = Off                             ' Extended instruction set disabled

    WDTCPS = WDTCPS_17                      ' Watchdog Timer Period Divider ratio 1:4194304
    WDTE = Off                              ' Watchdog Timer disabled

    WDTCWS = WDTCWS_7                       ' Watchdog Timer window always open (100%). Software control. Keyed access not required
    WDTCCS = SC                             ' Watchdog Timer input clock Software Control

    BBSIZE = BBSIZE_512                     ' Boot Block size is 512 words
    BBEN = Off                              ' Boot block disabled
    SAFEN = Off                             ' SAF disabled
    Debug = Off                             ' Background Debugger disabled

    WRTB = Off                              ' Boot Block not Write protected
    WRTC = Off                              ' Configuration registers not Write protected
    WRTD = Off                              ' Data EEPROM not Write protected
    WRTSAF = Off                            ' SAF not Write Protected
    WRTAPP = Off                            ' Application Block not write protected

    CP = Off                                ' PFM and Data EEPROM code protection disabled
Config_End

joesaliba

Thank you Les, very kind of you.

Kind regards

Joe

Mapo

Thank you Les, a lot of time saved

Mapo

top204

Below is the code listing for a demo using an interrupt driven serial buffer library for USART1, USART2 and USART3 on a PIC18F05Q41 device. For such a small device (14-pins), it is amazing it has three USARTs, and lots of other good peripherals:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate receiving data from USART1, USART2, and USART3 using interrupt serial buffers on a PIC18F05Q41 device.
' Written by Les Johnson for the Positron8 compiler
'
    Device = 18F05Q41                               ' Tell the compiler what device to compile for
    Declare Xtal = 64                               ' Tell the compiler what frequency the device is operating at (in MHz)
    On_Hardware_Interrupt GoTo ISR_Handler          ' Point to the interrupt handler routine
'
' Setup USART1
'
    Declare HRSOut1_Pin   = PORTC.4
    Declare HRSIn1_Pin    = PORTC.1
    Declare Hserial_Baud  = 9600
'
' Setup USART2
'
    Declare HRSOut2_Pin   = PORTC.2
    Declare HRSIn2_Pin    = PORTC.3
    Declare Hserial2_Baud = 9600
'
' Setup USART3
'
    Declare HRSOut3_Pin   = PORTA.0
    Declare HRSIn3_Pin    = PORTA.1
    Declare Hserial3_Baud = 9600

$define cUSART1_BufferSize 64                       ' Set the amount of RAM reserved for the USART1 buffer (Max 255)
$define cUSART2_BufferSize 64                       ' Set the amount of RAM reserved for the USART2 buffer (Max 255)
$define cUSART3_BufferSize 64                       ' Set the amount of RAM reserved for the USART3 buffer (Max 255)

    Include "Buffered_Serial_Q41.inc"               ' Load the serial buffer code into the program
'
' Create global variable here
'
    Dim Bytein1 As Byte                             ' Holds the data received from USART1
    Dim Bytein2 As Byte                             ' Holds the data received from USART2
    Dim Bytein3 As Byte                             ' Holds the data received from USART3
   
'-----------------------------------------------------------------------------------------------------------------------------
' The main program starts here
' Receive data from USARTs 1, 2 and 3, and re-transmit what was received
'
Main:
    Setup()                                         ' Setup the program and any peripherals

    Do                                              ' Create a loop
Cont:
        If Global_tByteInBuffer1 = 1 Then           ' Has a byte been received via USART1?
            Global_tByteInBuffer1  = 0              ' Yes. So clear its received flag
            HSerIn1 5000, TimedOut1, [Bytein1]      ' Read the byte of data from USART1 serial buffer
            HRSOut1Ln "USART1: ", Bytein1           ' Transmit the data byte received via USART1
        EndIf

        If Global_tByteInBuffer2 = 1 Then           ' Has a byte been received via USART2?
            Global_tByteInBuffer2  = 0              ' Yes. So clear its received flag
            HSerIn2 5000, TimedOut2, [Bytein2]      ' Read the byte of data from USART2 serial buffer
            HRSOut2Ln "USART2: ", Bytein2           ' Transmit the data byte received via USART2
        EndIf

        If Global_tByteInBuffer3 = 1 Then           ' Has a byte been received via USART3?
            Global_tByteInBuffer3  = 0              ' Yes. So clear itsreceived flag
            HSerIn3 5000, TimedOut3, [Bytein3]      ' Read the byte of data from USART3 serial buffer
            HRSOut3Ln "USART3: ", Bytein3           ' Transmit the data byte received via USART3
        EndIf
    Loop                                            ' Loop forever
'
' Jump here if USART1 timeout out
'
TimedOut1:
    HRSOut1Ln "\rUSART1 Timed Out"
    GoTo Cont                                       ' Jump back into the loop
'
' Jump here if USART2 timeout out
'   
TimedOut2:
    HRSOut2Ln "\rUSART2 Timed Out"
    GoTo Cont                                       ' Jump back into the loop
'
' Jump here if USART3 timeout out
'   
TimedOut3:
    HRSOut3Ln "\rUSART3 Timed Out"
    GoTo Cont                                       ' Jump back into the loop
       
'-----------------------------------------------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    USART1_ClearSerialBuffer()                                          ' Clear USART1 serial buffer
    USART2_ClearSerialBuffer()                                          ' Clear USART2 serial buffer
    USART3_ClearSerialBuffer()                                          ' Clear USART3 serial buffer

    USART1_InitInterrupt()                                              ' Initialise the USART1 interrupt (and set a flag to indicate it is required in code)
    USART2_InitInterrupt()                                              ' Initialise the USART2 interrupt (and Set a flag To indicate it is required in Code)
    USART3_InitInterrupt()                                              ' Initialise the USART3 interrupt (and Set a flag To indicate it is required in Code)

    DelayMS 50                                                          ' A small delay to allow things to settle
    IntPeriph_Enable()                                                  ' Enable peripheral interrupts
    IntGlobal_Enable()                                                  ' Enable global interrupts
EndProc

'-----------------------------------------------------------------------------------------------------------------------------
' Interrupt handler routine
' Input     : None
' Output    : Global_tByteInBuffer1 is true if a byte was received via USART1 (must be reset in the main program)
'           : Global_tByteInBuffer2 is true if a byte was received via USART2 (must be reset in the main program)
'           : Global_tByteInBuffer3 is true if a byte was received via USART3 (must be reset in the main program)
' Notes     : Interrupts on USART1 and USART2 and USART3 receive
'
ISR_Handler:
    Context Save FSR1L, FSR1H                                           ' Save any compiler system variables and any SFRs used before we perform the interrupt code
    Clrwdt                                                              ' Clear the watchdog timer (just in case it is enabled)

#ifSym _USART1_Int_Req_                                                 ' Is a USART1 interrupt handler required?
'
' Check the USART1 receive interrupt
'
    If USART1_RX_Flag() = True Then                                     ' Was it a USART1 byte receive that triggered the interrupt?
        WREG = U1ERRIR & %00001110                                      ' Yes. So mask out unwanted bits and check for errors
        If STATUSbits_Z = 0 Then                                        ' Are there any bits set in U1ERRIR?
            WREG = U1RXB                                                ' \ Yes. So empty the 2 byte USART1 buffer
            WREG = U1RXB                                                ' /
            USART1_RX_Disable()                                         ' Disable USART1's RX to clear flags
            USART1_RX_Flag() = 0                                        ' Clear USART1's RX flag
            USART1_RX_Enable()                                          ' Re-Enable USART1's RX
            Global_tByteInBuffer1 = False                               ' Indicate that there is not a byte received in USART1's buffer
        Else                                                            ' Otherwise... No error so...
            USARTx_bRXByte = U1RXB                                      ' Place the byte received into USARTx_bRXByte
            Inc USART1_bIndexIn                                         ' Yes. So move up the buffer and allow all byte values through
            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 the address of USART1_bRingBuffer
            USARTx_wFSR1 = USARTx_wFSR1 + USART1_bIndexIn               ' Add the buffer position to FSR1L\H
            INDF1 = USARTx_bRXByte                                      ' Place the received character into the buffer
            Global_tByteInBuffer1 = True                                ' Indicate that there is a byte received in USART1's buffer
            USART1_RX_Flag() = 0                                        ' Clear the USART1 received flag (just in case)
        EndIf
    EndIf
#endIfSym       ' _USART1_Int_Req_

#ifSym _USART2_Int_Req_                                                 ' Is a USART2 interrupt handler required?
'
' Check the USART2 receive interrupt
'
    If USART2_RX_Flag() = True Then                                     ' Was it a USART2 byte receive that triggered the interrupt?
        WREG = U2ERRIR & %00001110                                      ' Yes. So mask out unwanted bits and check for errors
        If STATUSbits_Z = 0 Then                                        ' Are there any bits set in U2ERRIR?
            WREG = U2RXB                                                ' \ Yes. So empty the 2 byte USART2 buffer
            WREG = U2RXB                                                ' /
            USART2_RX_Disable()                                         ' Disable USART2's RX to clear flags
            USART2_RX_Flag() = 0                                        ' Clear the USART2 RX flag
            USART2_RX_Enable()                                          ' Re-Enable USART2's RX
            Global_tByteInBuffer2 = False                               ' Indicate that there is not a byte in the USART2 buffer
        Else                                                            ' Otherwise... No error so...
            USARTx_bRXByte = U2RXB                                      ' Place the byte received into USARTx_bRXByte
            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 the address of USART2_bRingBuffer
            USARTx_wFSR1 = USARTx_wFSR1 + USART2_bIndexIn               ' Add the USART2 buffer position to FSR1L\H
            INDF1 = USARTx_bRXByte                                      ' Place the received character into the USART2 buffer
            Global_tByteInBuffer2 = True                                ' Indicate that there is a  byte received in the USART2 buffer
            USART2_RX_Flag() = 0                                        ' Clear the USART2 received flag (just in case)
        EndIf
    EndIf
#endIfSym       ' _USART2_Int_Req_

#ifSym _USART3_Int_Req_                                                 ' Is a USART3 interrupt handler required?
'
' Check the USART3 receive interrupt
'
    If USART3_RX_Flag() = True Then                                     ' Was it a USART3 byte receive that triggered the interrupt?
        WREG = U3ERRIR & %00001110                                      ' Yes. So mask out unwanted bits and check for errors
        If STATUSbits_Z = 0 Then                                        ' Are there any bits set in U3ERRIR?
            WREG = U3RXB                                                ' \ Yes. So empty the 3 byte USART3 buffer
            WREG = U3RXB                                                ' /
            USART3_RX_Disable()                                         ' Disable USART3's RX to clear flags
            USART3_RX_Flag() = 0                                        ' Clear the USART3 RX flag
            USART3_RX_Enable()                                          ' Re-Enable USART3's RX
            Global_tByteInBuffer3 = False                               ' Indicate that there is not a byte in the USART3 buffer
        Else                                                            ' Otherwise... No error so...
            USARTx_bRXByte = U3RXB                                      ' Place the byte received into USARTx_bRXByte
            Inc USART3_bIndexIn                                         ' Move up the buffer
            If USART3_bIndexIn >= cUSART3_BufferSize Then               ' End of buffer reached?
                USART3_bIndexIn = 0                                     ' Yes. So reset USART3_bIndexIn
            EndIf
            USARTx_wFSR1 = AddressOf(USART3_bRingBuffer)                ' Point FSR1L\H to the address of USART3_bRingBuffer
            USARTx_wFSR1 = USARTx_wFSR1 + USART3_bIndexIn               ' Add the USART3 buffer position to FSR1L\H
            INDF1 = USARTx_bRXByte                                      ' Place the received character into the USART3 buffer
            Global_tByteInBuffer3 = True                                ' Indicate that there is a  byte received in the USART3 buffer
            USART3_RX_Flag() = 0                                        ' Clear the USART3 received flag (just in case)
        EndIf
    EndIf
#endIfSym       ' _USART3_Int_Req_

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

'-------------------------------------------------------------------------------------------------
' Setup the config fuses for internal oscillator at 64MHz, with OSC pins as I/O
' For a PIC18F05Q41 device
'
Config_Start
    FEXTOSC = Off                           ' External Oscillator not enabled
    RSTOSC = HFINTOSC_64MHZ                 ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1

    CLKOUTEN = Off                          ' CLKOUT function is disabled
    PR1WAY = Off                            ' PRLOCKED bit can be set and cleared repeatedly
    CSWEN = On                              ' Writing to NOSC and NDIV is allowed
    FCMEN = On                              ' Fail-Safe Clock Monitor enabled
    FCMENP = On                             ' Fail-Safe Clock Monitor enabled; timer will flag FSCMP bit and OSFIF interrupt on EXTOSC failure.
    FCMENS = On                             ' Fail-Safe Clock Monitor enabled; timer will flag FSCMP bit and OSFIF interrupt on SOSC failure.

    MCLRE = EXTMCLR                         ' MCLR pin is MCLR
    PWRTS = PWRT_OFF                        ' PWRT is disabled
    MVECEN = Off                            ' Interrupt controller does not use vector table to prioritze interrupts
    IVT1WAY = On                            ' IVTLOCKED bit can be cleared and set only once
    LPBOREN = On                            ' Low-Power BOR enabled
    BOREN = On                              ' Brown-out Reset enabled according to SBOREN

    BORV = VBOR_1P9                         ' Brown-out Reset Voltage (VBOR) set to 1.9V
    ZCD = Off                               ' ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                           ' PPSLOCKED bit can be set and cleared repeatedly
    STVREN = On                             ' Stack full/underflow will cause Reset
    LVP = Off                               ' HV on MCLR/VPP must be used for programming
    XINST = Off                             ' Extended instruction set disabled

    WDTCPS = WDTCPS_17                      ' WDT Period Divider ratio 1:4194304
    WDTE = Off                              ' WDT disabled

    WDTCWS = WDTCWS_7                       ' WDT window always open (100%). Software control. Keyed access not required
    WDTCCS = SC                             ' WDT input clock Software Control

    BBSIZE = BBSIZE_512                     ' Boot Block size is 512 words
    BBEN = Off                              ' Boot block disabled
    SAFEN = Off                             ' SAF disabled
    Debug = Off                             ' Background Debugger disabled

    WRTB = Off                              ' Boot Block not Write protected
    WRTC = Off                              ' Configuration registers not Write protected
    WRTD = Off                              ' Data EEPROM not Write protected
    WRTSAF = Off                            ' SAF not Write Protected
    WRTAPP = Off                            ' Application Block not write protected

    Cp = Off                                ' PFM and Data EEPROM code protection disabled
Config_End

And below is the library's code listing:

$ifndef _Buffered_Serial_Q41_
$define _Buffered_Serial_Q41_
'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Interrupt-driven serial buffers for USART1 and USART2 and USART3 receive using a hardware high priority interrupt.
' These routines replace the compiler's Hserin1/Hrsin1 and HSerIn2/HRSIn2 and HSerIn3/HRSIn3 commands library subroutines
'
' Written by Les Johnson for the Positron8 compiler for a PIC18F05Q41 device.
'
    #Disable HRSIn, HRSInTo, 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
    #Disable HRSIn3, HRSIn3To, HRSIn3_RCREG_Read            ' Disable the library subroutines for Hrsin3 with and without timeouts

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

'------------------------------------------------------------------------------------------------
' Enable global interrupts
'
$ifndef IntGlobal_Enable
    $define IntGlobal_Enable() Repeat: INTCON0bits_GIE = 1: Until INTCON0bits_GIE = 1
$endif

'------------------------------------------------------------------------------------------------
' Disable global interrupts
'
$ifndef IntGlobal_Disable
    $define IntGlobal_Disable() Repeat: INTCON0bits_GIE = 0: Until INTCON0bits_GIE = 0
$endif

'------------------------------------------------------------------------------------------------
' Enable peripheral interrupts
'
$ifndef IntPeriph_Enable
    $define IntPeriph_Enable() Repeat: INTCON0bits_GIEL = 1: Until INTCON0bits_GIEL = 1
$endif

'------------------------------------------------------------------------------------------------
' Disable peripheral interrupts
'
$ifndef IntPeriph_Disable
    $define IntPeriph_Disable() Repeat: INTCON0bits_GIEL = 0: Until INTCON0bits_GIEL = 0
$endif

'------------------------------------------------------------------------------
' USART1 Meta-Macros
'------------------------------------------------------------------------------
$define USART1_IntRX_Enable() PIE4bits_U1RXIE = 1                   ' Enable interrupt on USART1 receive
$define USART1_IntRX_Disable() PIE4bits_U1RXIE = 0                  ' Disable interrupt on USART1 receive

'------------------------------------------------------------------------------
' 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() PIR4bits_U1RXIF                            ' The bit that indicates a byte has been received in USART1
$define USART1_TX_Flag() PIR4bits_U1TXIF                            ' The bit that indicates a byte is being transmitted from USART1
$define USART1_Flag() PIR4bits_U1IF                                 ' The bit that indicates an activation of USART1

'------------------------------------------------------------------------------
' Enable wake interrupt on USART1
'
$define USART1_WakeInt_Enable() '
    U1UIRbits_WUIF = 0          '
    PIE4bits_U1IE = 1           '
    U1CON1bits_WUE = 1

'------------------------------------------------------------------------------
' Disable wake interrupt on USART1
'
$define USART1_WakeInt_Disable() '
    U1UIRbits_WUIF = 0           '
    PIE4bits_U1IE = 0            '
    U1CON1bits_WUE = 0

'------------------------------------------------------------------------------
' USART2 Meta-Macros
'------------------------------------------------------------------------------
$define USART2_IntRX_Enable() PIE8bits_U2RXIE = 1                   ' Enable interrupt on USART2 receive
$define USART2_IntRX_Disable() PIE8bits_U2RXIE = 0                  ' Disable interrupt on USART2 receive

'------------------------------------------------------------------------------
' Disable USART2
'
$define USART2_Disable() '
    U2CON0bits_TXEN = 0  '
    U2CON0bits_RXEN = 0

'------------------------------------------------------------------------------
' Enable USART2
'
$define USART2_Enable() '
    U2CON0bits_TXEN = 1 '
    U2CON0bits_RXEN = 1

'------------------------------------------------------------------------------
$define USART2_TX_Disable() U2CON0bits_TXEN = 0                     ' Disable USART2 TX
$define USART2_TX_Enable()  U2CON0bits_TXEN = 1                     ' Enable USART2 TX

'------------------------------------------------------------------------------
$define USART2_RX_Disable() U2CON0bits_RXEN = 0                     ' Disable USART2 RX
$define USART2_RX_Enable()  U2CON0bits_RXEN = 1                     ' Enable USART2 RX

'------------------------------------------------------------------------------
$define USART2_RX_Flag() PIR8bits_U2RXIF                            ' The bit that indicates a byte has been received on USART2
$define USART2_TX_Flag() PIR8bits_U2TXIF                            ' The bit that indicates a byte is being transmitted from USART2
$define USART2_Flag() PIR8bits_U2IF                                 ' The bit that indicates an activation of USART2

'------------------------------------------------------------------------------
' Enable wake interrupt on USART2
'
$define USART2_WakeInt_Enable() '
    U2UIRbits_WUIF = 0          '
    PIE8bits_U2IE = 1           '
    U2CON1bits_WUE = 1

'------------------------------------------------------------------------------
' Disable wake interrupt on USART2
'
$define USART2_WakeInt_Disable() '
    U2UIRbits_WUIF = 0           '
    PIE8bits_U2IE = 0            '
    U2CON1bits_WUE = 0

'------------------------------------------------------------------------------
' USART3 Meta-Macros
'------------------------------------------------------------------------------
$define USART3_IntRX_Enable() PIE9bits_U3RXIE = 1                   ' Enable interrupt on USART3 receive
$define USART3_IntRX_Disable() PIE9bits_U3RXIE = 0                  ' Disable interrupt on USART3 receive

'------------------------------------------------------------------------------
' Disable USART3
'
$define USART3_Disable() '
    U3CON0bits_TXEN = 0  '
    U3CON0bits_RXEN = 0

'------------------------------------------------------------------------------
' Enable USART3
'
$define USART3_Enable() '
    U3CON0bits_TXEN = 1 '
    U3CON0bits_RXEN = 1

'------------------------------------------------------------------------------
$define USART3_TX_Disable() U3CON0bits_TXEN = 0                     ' Disable USART3 TX
$define USART3_TX_Enable()  U3CON0bits_TXEN = 1                     ' Enable USART3 TX

'------------------------------------------------------------------------------
$define USART3_RX_Disable() U3CON0bits_RXEN = 0                     ' Disable USART3 RX
$define USART3_RX_Enable()  U3CON0bits_RXEN = 1                     ' Enable USART3 RX

'------------------------------------------------------------------------------
$define USART3_RX_Flag() PIR9bits_U3RXIF                            ' The bit that indicates a byte has been received on USART3
$define USART3_TX_Flag() PIR9bits_U3TXIF                            ' The bit that indicates a byte is being transmitted from USART3
$define USART3_Flag() PIR9bits_U3IF                                 ' The bit that indicates an activation of USART3

'------------------------------------------------------------------------------
' Enable wake interrupt on USART3
'
$define USART3_WakeInt_Enable() '
    U3UIRbits_WUIF = 0          '
    PIE9bits_U3IE = 1           '
    U3CON1bits_WUE = 1

'------------------------------------------------------------------------------
' Disable wake interrupt on USART3
'
$define USART3_WakeInt_Disable() '
    U3UIRbits_WUIF = 0           '
    PIE9bits_U3IE = 0            '
    U3CON1bits_WUE = 0

'------------------------------------------------------------------------------
' Create some Compiler system variables
'
    Dim BPF     As Byte System                                      ' A compiler system variable used by the serial Modifier routines
    Dim GEN     As Byte System                                      ' \
    Dim GENH    As Byte System                                      ' / Buffered Hrsinx 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 Hrsinx Timeout inside loop counter
'
' Create variables and alias' for the USART1 and USART2 and USART3 interrupt buffered routines
'
    Dim Global_tByteInBuffer1 As Bit = False                        ' Indicates that there is a byte in USART1's RX buffer
    Dim Global_tByteInBuffer2 As Bit = False                        ' Indicates that there is a byte in USART2's RX buffer
    Dim Global_tByteInBuffer3 As Bit = False                        ' Indicates that there is a byte in USART3's RX buffer
    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_wFSR0Save      As Word Heap                          ' Holds a copy of FSR0L\H
    Dim USARTx_InsideLoopInt  As PP1
    Dim USARTx_InsideLoopIntH As PP1H
    Dim USARTx_wInsideLoop    As USARTx_InsideLoopInt.Word          ' Alias the inside loop to PP1\H
    Dim USARTx_wOutsideLoop   As PRODL.Word                         ' Alias the outside loop to PRODL\H registers
    Dim USARTx_bRXByte        As Byte Access                        ' Holds the byte received from a USART in the interrupt handler

$ifndef cUSART1_BufferSize                                          ' Has a buffer size been set for USART1?
    $define cUSART1_BufferSize 63                                   ' No. So set the default amount of RAM reserved for the USART1 buffer (Max 255)
$endif
$ifndef cUSART2_BufferSize                                          ' Has a buffer size been set for USART2?
    $define cUSART2_BufferSize 63                                   ' No. So set the default amount of RAM reserved for the USART2 buffer (Max 255)
$endif
$ifndef cUSART3_BufferSize                                          ' Has a buffer size been set for USART3?
    $define cUSART3_BufferSize 63                                   ' No. So set the default amount of RAM reserved for the USART3 buffer (Max 255)
$endif
    Dim USARTx_wFSR0  As FSR0L.Word                                 ' Create a 16-bit SFR of FSR0L and FSR0H
    Dim USARTx_wFSR1  As FSR1L.Word                                 ' Create a 16-bit SFR of FSR1L and FSR1H

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

#ifSym _USART1_Int_Req_
'------------------------------------------------------------------------------
' Wait for a byte from the interrupt driven circular USART1 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 PRODL\H as temporary variable storage (USARTx_wOutsideLoop)
'           : Uses FSR0L\H as buffer the pointer
'
__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 interrupt driven circular USART1 buffer without timeout
' Input     : None
' Output    : WREG holds the value received
' Notes     : Uses FSR0L\H as buffer pointers
'
__HRsin1__:
    While USART1_bIndexIn = USART1_bIndexOut                        ' \
        Clrwdt                                                      ' | Wait for a byte to appear in the serial buffer
    Wend                                                            ' /
'
' Fall through to USART1_GetByte
'------------------------------------------------------------------------------
' Read a byte from the interrupt driven circular USART1 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
    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
    WREG = INDF0                                                    ' Read buffer location (USART1_bIndexOut) into WREG
    PP0 = WREG                                                      ' Also place it into PP0
    USARTx_wFSR0 = USARTx_wFSR0Save                                 ' Restore FSR0\H registers
    STATUSbits_C = 1                                                ' Set the Carry flag to indicate a byte received
EndSub

'--------------------------------------------------------------------------------
' Replace the library Hrsout1 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 USART1 TX buffer to be ready
'    U1TXB = PP0                                                     ' Send the byte
'    WREG = PP0                                                      ' Restore the contents of WREG
'EndSub                                                              ' Exit the subroutine
#endIfSym       ' _USART1_Int_Req_

#ifSym _USART2_Int_Req_
'------------------------------------------------------------------------------
' Wait for a byte from the interrupt driven circular USART2 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 PRODL\H as temporary variable storage (USARTx_wOutsideLoop)
'           : Uses FSR0L\H as buffer the pointer
'
__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
' Notes     : Uses FSR0L\H as buffer pointers
'
__HRsin2__:
    While USART2_bIndexIn = USART2_bIndexOut                        ' \
        Clrwdt                                                      ' | Wait for a byte to appear in the serial buffer
    Wend                                                            ' /
'
' Fall through to USART2_GetByte
'------------------------------------------------------------------------------
' Read a byte from the interrupt driven circular USART2 buffer
' Input     : None
' Output    : PP0 and WREG hold the value received
' Notes     : Uses FSR0L\H as buffer pointers
'
Sub 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 clear USART2_bIndexOut.
    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
    WREG = INDF0                                                    ' Read buffer location (USART2_bIndexOut) into WREG
    PP0 = WREG                                                      ' Also place it into PP0
    USARTx_wFSR0 = USARTx_wFSR0Save                                 ' Restore FSR0\H registers
    STATUSbits_C = 1                                                ' Set the Carry flag to indicate a byte received
EndSub

'--------------------------------------------------------------------------------
' Replace the library Hrsout2 library routine with this routine
' Input     : WREG holds the byte to transmit
' Output    : WREG still holds the byte transmitted
' Notes     : None
'
'Sub __HRsout2__()
'    PP0 = WREG                                                      ' Save the byte to transmit
'    Repeat: Until USART2_TX_Flag() = 1                              ' Wait for the TX2 buffer to be ready
'    U2TXB = PP0                                                     ' Send the byte
'    WREG = PP0                                                      ' Restore the contents of WREG
'EndSub                                                              ' Exit the subroutine

#endIfSym       ' _USART2_Int_Req_

#ifSym _USART3_Int_Req_
'------------------------------------------------------------------------------
' Wait for a byte from the interrupt driven circular USART3 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 PRODL\H as temporary variable storage (USARTx_wOutsideLoop)
'           : Uses FSR0L\H as buffer the pointer
'
__HRsin3_With_TimeOut__:
    USARTx_wOutsideLoop = USARTx_wTimeoutValue                      ' Save the timeout value so it doesn't get overwritten
    USARTx_wInsideLoop = 0                                          ' Reset the inside loop counter
_USART3_OutsideLoop:
    DelayCS 2                                                       ' Delay for 2 cycles within the outside loop
_USART3_InsideLoop:
    DelayCS 1                                                       ' Delay for 1 cycle within the inside loop
    WREG = USART3_bIndexIn                                          ' \
    Subwf     USART3_bIndexOut,w                                    ' / Is there anything in the serial buffer?
    Bnz       USART3_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      _USART3_OutsideLoop
    USARTx_wInsideLoop = ((59 * Xtal) / 4)                          ' Set the inside loop counter based upon the Xtal frequency
    GoTo _USART3_InsideLoop

'------------------------------------------------------------------------------
' Wait for a byte from the USART3 interrupt driven circular buffer without timeout
' Input     : None
' Output    : WREG holds the value received
' Notes     : Uses FSR0L\H as buffer pointers
'
__HRsin3__:
    While USART3_bIndexIn = USART3_bIndexOut                        ' \
        Clrwdt                                                      ' | Wait for a byte to appear in the serial buffer
    Wend                                                            ' /
'
' Fall through to USART3_GetByte
'------------------------------------------------------------------------------
' Read a byte from the interrupt driven circular USART3 buffer
' Input     : None
' Output    : PP0 and WREG hold the value received
' Notes     : Uses FSR0L\H as buffer pointers
'
Sub USART3_GetByte()
    Inc USART3_bIndexOut                                            ' Increment USART3_bIndexOut pointer (0 to 255)
    If USART3_bIndexOut >= cUSART3_BufferSize Then                  ' End of buffer reached ?
        USART3_bIndexOut = 0                                        ' Yes. So clear USART3_bIndexOut.
    EndIf
    USARTx_wFSR0Save = USARTx_wFSR0                                 ' Save FSR0L\H registers
    USARTx_wFSR0 = AddressOf(USART3_bRingBuffer)                    ' Point FSR0L\H to USART3_bRingBuffer
    USARTx_wFSR0 = USARTx_wFSR0 + USART3_bIndexOut                  ' Add the buffer position to FSR0L\H
    WREG = INDF0                                                    ' Read buffer location (USART3_bIndexOut) into WREG
    PP0 = WREG                                                      ' Also place it into PP0
    USARTx_wFSR0 = USARTx_wFSR0Save                                 ' Restore FSR0\H registers
    STATUSbits_C = 1                                                ' Set the Carry flag to indicate a byte received
EndSub

'--------------------------------------------------------------------------------
' Replace the library Hrsout3 library routine with this routine
' Input     : WREG holds the byte to transmit
' Output    : WREG still holds the byte transmitted
' Notes     : None
'
'Sub __HRsout3__()
'    PP0 = WREG                                                      ' Save the byte to transmit
'    Repeat: Until USART3_TX_Flag() = 1                              ' Wait for the TX3 buffer to be ready
'    U3TXB = PP0                                                     ' Send the byte
'    WREG = PP0                                                      ' Restore the contents of WREG
'EndSub                                                              ' Exit the subroutine

#endIfSym       ' _USART3_Int_Req_

'--------------------------------------------------------------------------------
' Initialise the USART1 interrupt
' Input     : None
' Output    : None
' Notes     : Enables interrupt on USART1 receive
'
Proc USART1_InitInterrupt()
#Sym _USART1_Int_Req_
'
' Create variables for the USART1 interrupt buffered serial
'
Global Dim USART1_bIndexIn  As Byte Access Shared                   ' Pointer to the next empty location in the USART1 buffer
Global Dim USART1_bIndexOut As Byte Access Shared                   ' Pointer to the location of the oldest byte in the USART1 buffer
'
' Create the USART1 serial buffer in high RAM
'
Global Dim USART1_bRingBuffer[cUSART1_BufferSize] As Byte Heap Shared   ' Array for holding USART1 received characters (in high RAM because it is used indirectly, so needs no RAM bank switching mnemonics)

    Global_tByteInBuffer1 = False                                   ' Clear the byte in buffer flag for USART1
    USART1_bIndexIn = 0                                             ' Clear the USART1 buffer internal pointer
    USART1_bIndexOut = 0                                            ' Clear the USART1 buffer external pointer
    USART1_IntRX_Enable()                                           ' Enable interrupt on USART1 receive
EndProc

'--------------------------------------------------------------------------------
' Initialise the USART2 interrupt
' Input     : None
' Output    : None
' Notes     : Enables interrupt on USART2 receive
'
Proc USART2_InitInterrupt()
#Sym _USART2_Int_Req_
'
' Create variables for the USART2 interrupt buffered serial
'
Global Dim USART2_bIndexIn  As Byte Access Shared                   ' Pointer to the next empty location in the USART2 buffer
Global Dim USART2_bIndexOut As Byte Access Shared                   ' Pointer to the location of the oldest byte in the USART2 buffer
'
' Create the USART2 serial buffer in high RAM
'
Global Dim USART2_bRingBuffer[cUSART2_BufferSize] As Byte Heap Shared   ' Array for holding USART2 received characters (in high RAM because it is used indirectly, so needs no RAM bank switching mnemonics)

    Global_tByteInBuffer2 = False
    USART2_bIndexIn = 0                                             ' Clear the USART2 buffer internal pointer
    USART2_bIndexOut = 0                                            ' Clear the USART2 buffer external pointer
    USART2_IntRX_Enable()                                           ' Enable interrupt on USART2 receive
EndProc

'--------------------------------------------------------------------------------
' Initialise the USART3 interrupt
' Input     : None
' Output    : None
' Notes     : Enables interrupt on USART3 receive
'
Proc USART3_InitInterrupt()
#Sym _USART3_Int_Req_
'
' Create variables for the USART3 interrupt buffered serial
'
Global Dim USART3_bIndexIn  As Byte Access Shared                   ' Pointer to the next empty location in the USART3 buffer
Global Dim USART3_bIndexOut As Byte Access Shared                   ' Pointer to the location of the oldest byte in the USART3 buffer
'
' Create the USART3 serial buffer in high RAM
'
Global Dim USART3_bRingBuffer[cUSART3_BufferSize] As Byte Heap Shared   ' Array for holding USART3 received characters (in high RAM because it is used indirectly, so needs no RAM bank switching mnemonics)

    Global_tByteInBuffer3 = False
    USART3_bIndexIn = 0                                             ' Clear the USART3 buffer internal pointer
    USART3_bIndexOut = 0                                            ' Clear the USART3 buffer external pointer
    USART3_IntRX_Enable()                                           ' Enable interrupt on USART3 receive
EndProc

'--------------------------------------------------------------------------------
' Disable the USART1 interrupt
' Input     : None
' Output    : None
' Notes     : Disables interrupt on USART1 receive
'
Proc USART1_DisableInterrupt()
#Sym _USART1_Int_Req_
'
' Create variables for the USART1 interrupt buffered serial
'
Global Dim USART1_bIndexIn  As Byte Access Shared                   ' Pointer to the next empty location in the USART1 buffer
Global Dim USART1_bIndexOut As Byte Access Shared                   ' Pointer to the location of the oldest byte in the USART1 buffer
'
' Create the USART1 serial buffer in high RAM
'
Global Dim USART1_bRingBuffer[cUSART1_BufferSize] As Byte Heap Shared   ' Array for holding USART1 received characters (in high RAM because it is used indirectly, so needs no RAM bank switching mnemonics)

    Global_tByteInBuffer1 = False
    USART1_bIndexIn = 0                                             ' Clear the USART1 buffer internal pointer
    USART1_bIndexOut = 0                                            ' Clear the USART1 buffer external pointer
    USART1_IntRX_Disable()                                          ' Disable interrupt on USART1 receive
EndProc

'--------------------------------------------------------------------------------
' Disable the USART2 interrupt
' Input     : None
' Output    : None
' Notes     : Disables interrupt on USART2 receive
'
Proc USART2_DisableInterrupt()
#Sym _USART2_Int_Req_
'
' Create variables for the USART2 interrupt buffered serial
'
Global Dim USART2_bIndexIn  As Byte Access Shared                   ' Pointer to the next empty location in the USART2 buffer
Global Dim USART2_bIndexOut As Byte Access Shared                   ' Pointer to the location of the oldest byte in the USART2 buffer
'
' Create the USART2 serial buffer in high RAM
'
Global Dim USART2_bRingBuffer[cUSART2_BufferSize] As Byte Heap Shared   ' Array for holding USART2 received characters (in high RAM because it is used indirectly, so needs no RAM bank switching mnemonics)

    Global_tByteInBuffer2 = False                                   ' Clear the byte in buffer flag for USART2
    USART2_bIndexIn = 0                                             ' Clear the USART2 buffer internal pointer
    USART2_bIndexOut = 0                                            ' Clear the USART2 buffer external pointer
    USART2_IntRX_Disable()                                          ' Disable interrupt on USART2 receive
EndProc

'--------------------------------------------------------------------------------
' Disable the USART3 interrupt
' Input     : None
' Output    : None
' Notes     : Disables interrupt on USART3 receive
'
Proc USART3_DisableInterrupt()
#Sym _USART3_Int_Req_
'
' Create variables for the USART3 interrupt buffered serial
'
Global Dim USART3_bIndexIn  As Byte Access Shared                   ' Pointer to the next empty location in the USART3 buffer
Global Dim USART3_bIndexOut As Byte Access Shared                   ' Pointer to the location of the oldest byte in the USART3 buffer
'
' Create the USART3 serial buffer in high RAM
'
Global Dim USART3_bRingBuffer[cUSART3_BufferSize] As Byte Heap Shared   ' Array for holding USART3 received characters (in high RAM because it is used indirectly, so needs no RAM bank switching mnemonics)

    Global_tByteInBuffer3 = False                                   ' Clear the byte in buffer flag for USART3
    USART3_bIndexIn = 0                                             ' Clear the USART3 buffer internal pointer
    USART3_bIndexOut = 0                                            ' Clear the USART3 buffer external pointer
    USART3_IntRX_Disable()                                          ' Disable interrupt on USART3 receive
EndProc

'--------------------------------------------------------------------------------
' Clear the USART1 Serial Buffer
' Input     : None
' Output    : None
' Notes     : Also resets the index pointers to the serial buffer
'
Proc USART1_ClearSerialBuffer()
#Sym _USART1_Int_Req_
'
' Create variables for the USART1 interrupt buffered serial
'
Global Dim USART1_bIndexIn  As Byte Access Shared                   ' Pointer to the next empty location in the USART1 buffer
Global Dim USART1_bIndexOut As Byte Access Shared                   ' Pointer to the location of the oldest byte in the USART1 buffer
'
' Create the USART1 serial buffer in high RAM
'
Global Dim USART1_bRingBuffer[cUSART1_BufferSize] As Byte Heap Shared   ' Array for holding USART1 received characters (in high RAM because it is used indirectly, so needs no RAM bank switching mnemonics)

    Clrwdt
    WREG = U1RXB                                                    ' \ Empty USART1's 2-byte serial buffer
    WREG = U1RXB                                                    ' /
    USART1_RX_Flag() = 0                                            ' Clear the USART1 byte received flag
    Clear USART1_bRingBuffer                                        ' Clear the USART1 serial buffer
    USART1_bIndexIn = 0                                             ' Clear the USART1 buffer internal pointer
    USART1_bIndexOut = 0                                            ' Clear the USART1 buffer external pointer
    Global_tByteInBuffer1 = False                                   ' Reset the byte in USART1 RX1 buffer flag
EndProc

'--------------------------------------------------------------------------------
' Clear the USART2 Serial Buffer
' Input     : None
' Output    : None
' Notes     : Also resets the index pointers to the serial buffer
'
Proc USART2_ClearSerialBuffer()
#Sym _USART2_Int_Req_
'
' Create variables for the USART2 interrupt buffered serial
'
Global Dim USART2_bIndexIn  As Byte Access Shared                   ' Pointer to the next empty location in the USART2 buffer
Global Dim USART2_bIndexOut As Byte Access Shared                   ' Pointer to the location of the oldest byte in the USART2 buffer
'
' Create the USART2 serial buffer in high RAM
'
Global Dim USART2_bRingBuffer[cUSART2_BufferSize] As Byte Heap Shared   ' Array for holding USART2 received characters (in high RAM because it is used indirectly, so needs no RAM bank switching mnemonics)

    Clrwdt
    WREG = U2RXB                                                    ' \ Empty the USART's 2-byte serial buffer
    WREG = U2RXB                                                    ' /
    USART2_RX_Flag() = 0                                            ' Clear the USART2 byte received flag
    Clear USART2_bRingBuffer                                        ' Clear the USART2 serial buffer
    USART2_bIndexIn = 0                                             ' Clear the USART2 buffer internal pointer
    USART2_bIndexOut = 0                                            ' Clear the USART2 buffer external pointer
    Global_tByteInBuffer2 = False                                   ' Reset the byte in USART2 buffer flag
EndProc

'--------------------------------------------------------------------------------
' Clear the USART3 Serial Buffer
' Input     : None
' Output    : None
' Notes     : Also resets the index pointers to the serial buffer
'
Proc USART3_ClearSerialBuffer()
#Sym _USART3_Int_Req_
'
' Create variables for the USART3 interrupt buffered serial
'
Global Dim USART3_bIndexIn  As Byte Access Shared                   ' Pointer to the next empty location in the USART3 buffer
Global Dim USART3_bIndexOut As Byte Access Shared                   ' Pointer to the location of the oldest byte in the USART3 buffer
'
' Create the USART3 serial buffer in high RAM
'
Global Dim USART3_bRingBuffer[cUSART3_BufferSize] As Byte Heap Shared   ' Array for holding USART3 received characters (in high RAM because it is used indirectly, so needs no RAM bank switching mnemonics)

    Clrwdt
    WREG = U3RXB                                                    ' \ Empty the USART's 3-byte serial buffer
    WREG = U3RXB                                                    ' /
    USART3_RX_Flag() = 0                                            ' Clear the USART3 byte received flag
    Clear USART3_bRingBuffer                                        ' Clear the USART3 serial buffer
    USART3_bIndexIn = 0                                             ' Clear the USART3 buffer internal pointer
    USART3_bIndexOut = 0                                            ' Clear the USART3 buffer external pointer
    Global_tByteInBuffer3 = False                                   ' Reset the byte in USART3 buffer flag
EndProc

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

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

'--------------------------------------------------------------------------------
' Disable USART3
' Input     : None
' Output    : None
' Notes     : Also disables the USART3 RX interrupt
'
Proc USART3_Close()
    USART3_DisableInterrupt()                                       ' Disable USART3 interrupt
    USART3_RX_Flag() = 0                                            ' Clear the USART3 RX flag
    USART3_ClearSerialBuffer()                                      ' Clear USART3 serial buffer
EndProc

'--------------------------------------------------------------------------------
' Any start up code for the buffered USARTs goes here
'
_USARTx_Main:

$endif      ' _Buffered_Serial_Q41_

Name the library file as: "Buffered_Serial_Q41.inc".

In the demo, if one or more of the USARTs is not required, remove the USART1_InitInterrupt(), USART2_InitInterrupt(), or USART3_InitInterrupt() procedure calls, and no code will be produced for them, so they will not waste time, RAM, or flash memory space.

The library file and demo are attached to this post, below.