News:

;) This forum is the property of Proton software developers

Main Menu

USART Interrupt 18F47K40

Started by Dave-S, Dec 12, 2022, 07:40 PM

Previous topic - Next topic

Dave-S

Trying to set up USART Interrupt on a 18F47K40.
I want to receive a Modbus request ie: 01 03 00 02 00 02 65 CB
I have some problems, the interrupt works but does not then return to the main code.
It returns a string of 49's which I think is the first zero.
Code attached:
'****************************************************************
'*  Name    : Pylon Battery Monitor-1.BAS                       *
'*  Author  : [select VIEW...EDITOR OPTIONS]                    *
'*  Notice  : Copyright (c) 2022 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 2022-12-11                                        *
'*  Version : 1.0                                               *
'*  Notes   :                                                   *
'*          :                                                   *
'****************************************************************
;-------------------------------------------------------------------------------
;**** Added by Fuse Configurator ****
; Use the Fuse Configurator plug-in to change these settings

Device = 18F47K40

Config_Start
  FEXTOSC = OFF ;Oscillator not enabled
  RSTOSC = HFINTOSC_64MHZ ;HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
  CLKOUTEN = OFF ;CLKOUT function is disabled
  CSWEN = On ;Writing to NOSC and NDIV is allowed
  FCMEN = On ;Fail-Safe Clock Monitor enabled
  MCLRE = EXTMCLR ;If LVP = 0, MCLR pin is MCLR; If LVP = 1, RE3 pin function is MCLR
  PWRTE = OFF ;Power up timer disabled
  LPBOREN = OFF ;ULPBOR disabled
  BOREN = SBORDIS ;Brown-out Reset enabled , SBOREN bit is ignored
  BORV = VBOR_2P45 ;Brown-out Reset Voltage (VBOR) set to 2.45V
  ZCD = OFF ;ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
  PPS1WAY = Off ;PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle
  STVREN = On ;Stack full/underflow will cause Reset
  Debug = OFF ;Background debugger disabled
  XINST = OFF ;Extended Instruction Set and Indexed Addressing Mode disabled
  WDTCPS = WDTCPS_31 ;Divider ratio 1:65536; software control of WDTPS
  WDTE = off ;WDT enabled regardless of sleep
  WDTCWS = WDTCWS_7 ;window always open (100%); software control; keyed access not required
  WDTCCS = SC ;Software Control
  WRT0 = OFF ;Block 0 (000800-003FFFh) not write-protected
  WRT1 = OFF ;Block 1 (004000-007FFFh) not write-protected
  WRT2 = OFF ;Block 2 (008000-00BFFFh) not write-protected
  WRT3 = OFF ;Block 3 (00C000-00FFFFh) not write-protected
  WRT4 = OFF ;Block 4 (010000-013FFFh) not write-protected
  WRT5 = OFF ;Block 5 (014000-017FFFh) not write-protected
  WRT6 = OFF ;Block 6 (018000-01BFFFh) not write-protected
  WRT7 = OFF ;Block 7 (01C000-01FFFFh) not write-protected
  WRTC = OFF ;Configuration registers (300000-30000Bh) not write-protected
  WRTB = OFF ;Boot Block (000000-0007FFh) not write-protected
  WRTD = OFF ;Data EEPROM not write-protected
  SCANE = On ;Scanner module is available for use, SCANMD bit can control the module
  LVP = On ;Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored
  Cp = OFF ;UserNVM code protection disabled
  CPD = OFF ;DataNVM code protection disabled
  EBTR0 = OFF ;Block 0 (000800-003FFFh) not protected from table reads executed in other blocks
  EBTR1 = OFF ;Block 1 (004000-007FFFh) not protected from table reads executed in other blocks
  EBTR2 = OFF ;Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks
  EBTR3 = OFF ;Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks
  EBTR4 = OFF ;Block 4 (010000-013FFFh) not protected from table reads executed in other blocks
  EBTR5 = OFF ;Block 5 (014000-017FFFh) not protected from table reads executed in other blocks
  EBTR6 = OFF ;Block 6 (018000-01BFFFh) not protected from table reads executed in other blocks
  EBTR7 = OFF ;Block 7 (01C000-01FFFFh) not protected from table reads executed in other blocks
  EBTRB = OFF ;Boot Block (000000-0007FFh) not protected from table reads executed in other blocks
Config_End
;**** End of Fuse Configurator Settings ****
;-------------------------------------------------------------------------------
Declare Xtal = 64
   
    Declare Float_Display_Type = Fast      ' Enable the faster, and more accurate, floating point display library routine
' Setup USART1
    Declare Hserial_Baud = 9600          ' Set the Baud rate for USART1
    Declare HSerout_Pin = PORTC.6         ' Setup the pin used for RX on the USART1
    Declare Hserial_Clear = 1                                         
    ANSELC.7 = 0   'disable   digital
    ANSELC.6 = 0   'disable   digital
 
    INTCONbits_GIE = 0    ' Disable global interrupts
    INTCONbits_GIE = 1    ' Enable global interrupts
    INTCONbits_PEIE = 0    ' Disable peripheral interrupts
    INTCONbits_PEIE = 1     ' Enable peripheral interrupts
   
    RX1PPS = $17                    ' RC7->EUSART1:RX1   
    RC6PPS = $09                    ' RC6->EUSART1:TX1
    IOCCF = %00000000      ; Interrupt-on-Change PORTC flags.
    IOCCP = %10000000      ; Interrupt-on-Change PORTC Positive Edge Enable bits.
    IOCCN = %10000000      ; Interrupt-on-Change PORTC Negative Edge Enable bits.
 
    INTCON.7 = 1                    ;Enable Global Interrupts
    INTCON.6 = 1                    ;Enable Peripheral Interrupts
 
    OSCILLATOR_Initialize()
   
    Dim RCBuffer As Byte = 0
    Dim RC1BuffSize As 10
    Dim RC1RingBuffer[RC1BuffSize] As Byte
    Dim RInterruptTemp As Byte
    Dim Mytest As Byte  = 0
    Dim Mytest1 As Byte = 0
    On_Hardware_Interrupt    GoTo USART_INTERRUPT
 
    PIE0bits_IOCIE = 1      ' Enable IOC Interrupts
 
Main:
    Do   
        SerOut PORTD.1, 84, ["Led on", 13]
        High PORTB.5
        DelayMS 800
        SerOut PORTD.1, 84, ["Led off", 13]
        Low PORTB.5
        DelayMS 800
    Loop   
End
 ';*******************************************************************************
; INTERRUPT SERVICE ROUTINES START HERE.
;*******************************************************************************
; IOC interrupt handler checks which interrupt flag has been set for PORTC.
;  Each flag bit corresponds to an input.
;*******************************************************************************
USART_INTERRUPT:
   SerOut PORTD.1, 84, ["Interrupt start"]
    Context Save
    If  PIE0bits_IOCIE = 1 Then         ' Only do the rest if the RX1 interrupts are enabled.
     
     PIE0bits_IOCIE = 0      ' Disable IOC Interrupts
     
        If PIR0bits_IOCIF = 1 Then     ' Was it a USART1 byte receive that triggered the interrupt?
           RC1RingBuffer[RCBuffer] = RC1REG                     
           HSerOut [Dec RC1RingBuffer[RCBuffer], 13]
              Inc RCBuffer                                                 
        EndIf
    EndIf
   IOCCF.7  = 0      'Clear PORTC.7 IOC Flag
  PIE0bits_IOCIE = 1      ' Enable IOC Interrupts
  Context Restore
 
  '***********************************************************************************************   
Proc OSCILLATOR_Initialize()
    OSCCON1 = $60       ' NOSC HFINTOSC; NDIV 1
    OSCCON3 = $00       ' CSWHOLD may proceed, SOSCPWR Low power
    ; MFOEN disabled; LFOEN disabled; ADOEN disabled; SOSCEN disabled; EXTOEN disabled; HFOEN disabled;
    OSCEN = $00
    OSCFRQ = $08        ' HFFRQ 64_MHz
    OSCTUNE = $00       ' TUN 0
    EndProc       
 


John Lawton

You don't appear to be clearing the interrupt flag PIR0bits_IOCIF in the interrupt code.

tumbleweed

Quote from: Dave-STrying to set up USART Interrupt on a 18F47K40.
Then why are you messing around with the IOC interrupt?

The USART1 receive has it's own interrupt, RC1IF (PIE3/PIR3 on the K40).
Also, it's a good idea to get everything setup before you enable the interrupts.

JonW

#3
Like tumbleweed says, use the dedicated RX interrupt and avoid call to any routines within the interrupt to keep it as small and efficient as possible.  Consider using toggled pin states to indicate a successful call or position in the interrupt routine as these only take a few cycles..  You are also trying to receive serial data and send data out in the same int routine and run the risk of getting other interrupts generated,  framing or buffer full causing issues.

This is not finished as  (am still working on it),  It  needs to check for more UART errors but works well etc but I use a EOL flag like "%" to check the routine is working and end the message, this avoids the need for timers or counters to terminate the message and thus can easily test out long fast bursts of serial data..
This is on a 26k42 but I suspect its a similar UART.


'------------------------------------------------------------------------------------------------
'                                    UART DEFINES
'------------------------------------------------------------------------------------------------
   Symbol RX_BUFFERSIZE         =   16                      ' NUMBER OF BYTES IN UART ARRAY
   SYMBOL EOM                   =   "%"
   Symbol RX_INTENABLE          =   PIE3.3
   Symbol RX_INTFLAG            =   PIR3.3
   Symbol GLOBALINT             =   INTCON0.7
   Symbol RX_ENABLE             =   U1CON0.4
   Symbol RX_BUFFEREMPTY        =   U1FIFO.1                ' IF 0 BUFFER IS NOT EMPTY, TO CLEAR READ U1FIFO, SET BIT1 AND USE MOVWF U1FIFO
   Symbol RX_BUFFERFULL         =   U1FIFO.0
   Symbol RX_FRAMEERROR         =   U1ERRIR.3               ' 1 = UNREAD BYTE AT THE TOP OF THE BUFFER HAS FRAMING ERROR. 0 = NO ERROR
   Symbol RX_FIFOOVERFLOWED     =   U1ERRIR.1               ' 1 = FIFO HAS OVERFLOWED. 0 = FIFO NOT OVERLOWED
   Symbol RX_REG                =   U1RXB                   ' RX RECEIVE REGISTER


'SERIAL INTERRUPT VARS
    Dim EOM_FLAG             As Bit                     ' SET WHEN END OF SERIAL STRING RECEIVED %
    Dim RX_BUFFER[RX_BUFFERSIZE]       As Byte          ' USED IN INTERRUPT
    Dim RX_PNTR              As Byte
    Dim RXBYTE               As Byte
 

' SETUP INTERRUPTS
        RX_INTENABLE = 1
        RX_PNTR = 0             ; RESET THE POINTER
        globalint = 1
        EOM_FLAG = 0            ; RESET END OF MESSAGE



ISR_Handler:
    Context Save FSR1L, FSR1H                           ' Save any compiler system variables and any SFRs used before we perform the interrupt code
'
' Check the USART1 RX interrupt
     If RX_INTFLAG = 1 Then
        IF RX_PNTR = RX_BUFFERSIZE THEN GOTO RX_FULL                                          ' INCREMEMENT POINTER
        RXBYTE =   RX_REG                   ' LOAD BYTE INTO ARRAY
        RX_BUFFER[RX_PNTR] = RXBYTE
        INC RX_PNTR
        IF  RXBYTE = EOM then
             DEC RX_PNTR
             EOM_FLAG = 1                               ' WE HAVE A MESSAGE THE BUFFER
            GOTO EXIT_INT
        EndIf
     EndIf

RX_FULL: ' add more code for buffer full and uart errors later
     RX_BUFFEREMPTY = 0

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


Dave-S

Thanks for the replies.
I tried the code JONW supplied but get Compiler errors,
INTCONO
RX_REG
RX_BUFFEREMPTY
Not found

Altered my original code to use "dedicated RX interrupt", the interrupt occurs once but no data is returned
to the RC1RingBuffer.

  Declare Hserial_Baud = 9600          ' Set the Baud rate for USART1
    ANSELC.7 = 0   'disable   digital
    ANSELC.6 = 0   'disable   digital
 
    RX1PPS = $17                    ' RC7->EUSART1:RX1   
    RC6PPS = $09                    ' RC6->EUSART1:TX1
   
    RC1STA = %10010000
   
    INTCONbits_GIE = 0    ' Disable global interrupts
    INTCONbits_GIE = 1    ' Enable global interrupts
    INTCONbits_PEIE = 0    ' Disable peripheral interrupts
    INTCONbits_PEIE = 1     ' Enable peripheral interrupts
    PIE3bits_RC1IE = 1     ' Enable RC interrupt
    IPR3bits_RC1IP = 1
   
    OSCILLATOR_Initialize()
   
    Dim RCBuffer As Byte = 0
    Dim RC1BuffSize As 10
    Dim RC1RingBuffer[RC1BuffSize] As Byte
    Dim RInterruptTemp As Byte
    Dim Mytest As Byte  = 0
    Dim Mytest1 As Byte = 0
    Clear RC1RingBuffer
    On_Hardware_Interrupt    GoTo USART_INTERRUPT
 
Main:
    Do   
        SerOut PORTD.1, 84, ["B = ", Dec RC1RingBuffer[0], 13]
        SerOut PORTD.1, 84, ["B = ", Dec RC1RingBuffer[1], 13]
        SerOut PORTD.1, 84, ["B = ", Dec RC1RingBuffer[2], 13]
        SerOut PORTD.1, 84, ["B = ", Dec RC1RingBuffer[3], 13]
        SerOut PORTD.1, 84, ["Led on", 13]
        High PORTB.5
        DelayMS 800
        SerOut PORTD.1, 84, ["Led off", 13]
        Low PORTB.5
        DelayMS 800
    Loop   
End
 ';*******************************************************************************
; INTERRUPT SERVICE ROUTINES START HERE.
;*******************************************************************************
USART_INTERRUPT:
    Context Save
    If  PIE3bits_RC1IE = 1 Then         ' Only do the rest if the RX1 interrupts are enabled.
     If RC1STA.1 = 1 Then   RC1STA.4 = 0
     PIE3bits_RC1IE = 0      ' Disable Interrupt
        RC1STA.4 = 0
        RC1STA.4 = 1
        If PIR3bits_RC1IF = 1 Then     ' Was it a USART1 byte receive that triggered the interrupt?
           RC1RingBuffer[RCBuffer] = RC1REG                     
           Inc RCBuffer                                                 
        EndIf
    EndIf
    PIR3bits_RC1IF = 0    ' CLEAR FLAG
    PIE3bits_RC1IE = 1      ' Enable Interrupt
  Context Restore
 
  '***********************************************************************************************   
Proc OSCILLATOR_Initialize()
    OSCCON1 = $60       ' NOSC HFINTOSC; NDIV 1
    OSCCON3 = $00       ' CSWHOLD may proceed, SOSCPWR Low power
    ; MFOEN disabled; LFOEN disabled; ADOEN disabled; SOSCEN disabled; EXTOEN disabled; HFOEN disabled;
    OSCEN = $00
    OSCFRQ = $08        ' HFFRQ 64_MHz
    OSCTUNE = $00       ' TUN 0
    EndProc       
 

Thanks for the help
David


JonW

Its for a 26k42 so will need to be modified to suit the processor you are working on. It was meant to show the structure of how to use the ISR

JonW

#6
Here is a bit of code that compiles for your device, I tried to run it on ISIS however the HRSOUT keeps sending "." and I do not have a 27k40 on hand to test. 

device = 18F27K40
Declare Xtal = 64                                   ' Tell the compiler that the device will be running at 64MHz
Declare Hserial1_Baud = 115200                      ' Set the Baud rate for USART1
Declare HRSOUT_Pin  = PORTC.6                       ' Set the pin used for USART1 TX
Declare HRSIN_Pin   = PORTC.7                       ' Set the pin used for USART1 RX
Declare Hserial_RCSTA = %10010000                   ' Enable serial port and continuous receive
'Declare Hserial_TXSTA = %00100100                   ' Enable transmit and asynchronous mode
Declare Hserial_Clear = On                          ' Enable Error clearing on received characters      ' Clear the buffer before receiving

declare all_digital = true
Declare Create_Coff On
declare watchdog = off

On_Hardware_Interrupt GoTo ISR_Handler              ' Point to the interrupt handler routine

SYMBOL EOM = "%"                    ' END OF MESSAGE TERMINATOR
SYMBOL RXIF =  PIR3.5               ' INTERRUPT FLAG
SYMBOL RXINT_ENABLE = PIE3.5        ' INTERRUPT ENABLE
SYMBOL RX_BUFFERSIZE = 20
SYMBOL ENABLE_GLOBAL_INT = INTCON.7

DIM RXBUFFER[RX_BUFFERSIZE]     AS BYTE
DIM RXPNTR                      AS BYTE
DIM RXBYTE                      AS BYTE
DIM EOM_FLAG                    AS BIT

SETUP_PIC:
        INTCON = B'00100000'   '  Alter to suit priority
        ANSELA = 0
        ANSELB = 0
        ANSELC = 0
        CM1CON0 = 0
        T3CON =     %00000000
        TRISA =     %00000000   ; ALL OUTPUT
        TRISB =     %00000000   ; SEE PORT MAP
        TRISC =     %10000000   ; SERIAL PORT
        WPUA =      %00000000   ; NO PULLUPS
        WPUB =      %00000000   ; NO PULLUPS
        WPUC =      %00000000   ; NO PULLUPS

'ENABLE UART INT
        RXINT_ENABLE = 1
        ENABLE_GLOBAL_INT = 1
        EOM_FLAG = 0

MAINLOOP:

        IF EOM_FLAG = 1 then
           HRSOUT "MESSAGE IN BUFFER",13,10
           HRSOUT "BYTES IN BUFFER = ", DEC RXPNTR,13,10
           RXPNTR = 0
           EOM_FLAG = 0
        EndIf
        hrsout "."
        delayms 300
        GOTO MAINLOOP





ISR_Handler:
    Context Save FSR1L, FSR1H                           ' Save any compiler system variables and any SFRs used before we perform the interrupt code
'
' Check the USART1 RX interrupt
     If RXIF = 1 Then
        RXBYTE =   RC1REG                   ' LOAD BYTE INTO ARRAY
        IF RXPNTR = RX_BUFFERSIZE THEN GOTO RX_FULL                                          ' INCREMEMENT POINTER
        RXBUFFER[RXPNTR] = RXBYTE
        INC RXPNTR
        IF  RXBYTE = EOM then
             DEC RXPNTR
             EOM_FLAG = 1                               ' WE HAVE BYTE IN THE BUFFER
             RXIF = 0
             GOTO EXIT_INT
        EndIf
     EndIf

RX_FULL: ' add more code for buffer full later on
    RXPNTR = 0

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

'-------------------------------------------------------------------------------
'**** Added by Fuse Configurator ****
' Use the Fuses Tab to change these settings

Config_Start
  FEXTOSC = OFF               ;HS (crystal oscillator) above 8 MHz; PFM set to high powe
  RSTOSC = HFINTOSC_64MHZ    ;HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:
  CLKOUTEN = OFF             ;CLKOUT function is disable
  CSWEN = ON                 ;Writing to NOSC and NDIV is allowe
  FCMEN = ON                 ;Fail-Safe Clock Monitor enable
  MCLRE = INTMCLR            ;If LVP = 0, MCLR pin function is port defined function; If LVP =1, RE3 pin fuction is MCL
  PWRTE = OFF                ;Power up timer disable
  LPBOREN = OFF              ;ULPBOR disable
  BOREN = SBORDIS            ;Brown-out Reset enabled , SBOREN bit is ignore
  BORV = VBOR_2P45           ;Brown-out Reset Voltage (VBOR) set to 2.45
  ZCD = OFF                  ;ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCO
  PPS1WAY = ON               ;PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycl
  STVREN = ON                ;Stack full/underflow will cause Rese
  DEBUG = OFF                ;Background debugger disable
  XINST = OFF                ;Extended Instruction Set and Indexed Addressing Mode disable
  WDTCPS = WDTCPS_31         ;Divider ratio 1:65536; software control of WDTP
  WDTE = OFF                 ;WDT Disable
  WDTCWS = WDTCWS_7          ;window always open (100%); software control; keyed access not require
  WDTCCS = SC                ;Software Contro
  WRT0 = OFF                 ;Block 0 (000800-003FFFh) not write-protecte
  WRT1 = OFF                 ;Block 1 (004000-007FFFh) not write-protecte
  WRT2 = OFF                 ;Block 2 (008000-00BFFFh) not write-protecte
  WRT3 = OFF                 ;Block 3 (00C000-00FFFFh) not write-protecte
  WRT4 = OFF                 ;Block 4 (010000-013FFFh) not write-protecte
  WRT5 = OFF                 ;Block 5 (014000-017FFFh) not write-protecte
  WRT6 = OFF                 ;Block 6 (018000-01BFFFh) not write-protecte
  WRT7 = OFF                 ;Block 7 (01C000-01FFFFh) not write-protecte
  WRTC = OFF                 ;Configuration registers (300000-30000Bh) not write-protecte
  WRTB = OFF                 ;Boot Block (000000-0007FFh) not write-protecte
  WRTD = OFF                 ;Data EEPROM not write-protecte
  SCANE = ON                 ;Scanner module is available for use, SCANMD bit can control the modul
  LVP = OFF                   ;Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignore
  CP = OFF                   ;UserNVM code protection disable
  CPD = OFF                  ;DataNVM code protection disable
  EBTR0 = OFF                ;Block 0 (000800-003FFFh) not protected from table reads executed in other block
  EBTR1 = OFF                ;Block 1 (004000-007FFFh) not protected from table reads executed in other block
  EBTR2 = OFF                ;Block 2 (008000-00BFFFh) not protected from table reads executed in other block
  EBTR3 = OFF                ;Block 3 (00C000-00FFFFh) not protected from table reads executed in other block
  EBTR4 = OFF                ;Block 4 (010000-013FFFh) not protected from table reads executed in other block
  EBTR5 = OFF                ;Block 5 (014000-017FFFh) not protected from table reads executed in other block
  EBTR6 = OFF                ;Block 6 (018000-01BFFFh) not protected from table reads executed in other block
  EBTR7 = OFF                ;Block 7 (01C000-01FFFFh) not protected from table reads executed in other block
  EBTRB = OFF                ;Boot Block (000000-0007FFh) not protected from table reads executed in other block
Config_End

'**** End of Fuse Configurator Settings ****
'--------

tumbleweed

There are a couple of things that need fixing there.

Symbol ENABLE_GLOBAL_INT = INTCON.1I assume you mean the GIE bit, which is bit 7, not bit 1

SETUP_PIC:
        INTCON = B'00000000'   ; DISABLE INT
If you clear IPEN (bit 5) then it will operate in mid-range compatibility mode where you have GIE and PEIE for peripherals. With IPEN=1 you have GIE and GIEL (high and low priorities)

' Check the USART1 RX interrupt
     If RXIF = 1 Then
        If RXPNTR = RX_BUFFERSIZE Then GoTo RX_FULL   ' INCREMEMENT POINTER
        RXBYTE =   RC1REG                   ' LOAD BYTE INTO ARRAY
If the RX buffer fills then this code will bypass reading RC1REG. If you don't read it then the RCIF interrupt bit will remain set and you'll generate an infinite loop reentering the ISR.





JonW

OOPS, I did it really quickly this morning and i should have checked it apologies guys.  Fixed the errors  ;)

top204

I have just created an include file that implements both RX and TX interrupt driven buffers on the PIC18FxxK40 devices, and it has been tested on a real PIC18F26K40 device. I gave up with Proteus trying to simulate the latest devices it has implemented, because they do not appear to work. Not even a flashing LED works in them properly.

Below is the code listing for the include file, and it should be named: "Int_TX_RX_18FxxK40.inc":
$ifndef _BUFFER_USART1_INC_
$define _BUFFER_USART1_INC_
'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Interrupt driven buffered USART1 RX and TX
' Implements replacements for the compiler's HRsOut, HSerout, HRsin and HSerin commands
' Note. The interrupt handler routine must be placed in the main program listing
'
' The code is for PIC18FxxK40 devices.
' Written for the Positron8 compiler by Les Johnson.
'
$if _device <> _18F27K40 And _device <> _18F47K40 And _device <> _18F26K40 And _device <> _18F46K40
    $error "The TX/RX buffer library is for PIC18F26K40, PIC18F27K40, PIC18F46K40, and PIC18F47K40 devices only"
$else
    #Disable HRSIn, HRSInTo, HRSIn_RCREG_Read, HRSOut               ' Disable the compiler's library subroutines for HRsin, HRsout, HSerin and HSerout
'
' Create some Compiler system variables
'
    Dim GEN  As Byte System                                         ' \
    Dim GENH As Byte System                                         ' / Buffered Hrsin1 Timeout value storage
    Dim PP0  As Byte System                                         ' \
    Dim PP0H As Byte System                                         ' / Storage for FSR0L\H registers
    Dim PP1  As Byte System                                         ' \
    Dim PP1H As Byte System                                         ' / Buffered Hrsin1 Timeout inside loop counter
'
' Create variables for the interrupt buffered serial
'
    Dim USART1_bTimeoutInt     As GEN
    Dim USART1_bTimeoutIntH    As GENH
    Dim USART1_wTimeoutValue   As USART1_bTimeoutInt.Word           ' Alias the timeout value to GEN\H
    Dim USART1_wFSR0Save       As Word Heap                         ' Alias the FSR0L\H storage to PP0\H
    Dim USART1_bInsideLoopInt  As PP1
    Dim USART1_bInsideLoopIntH As PP1H
    Dim USART1_wInsideLoop     As USART1_bInsideLoopInt.Word        ' Alias the inside loop to PP1\H
    Dim USART1_wOutsideLoop    As PRODL.Word                        ' Alias the outside loop to PRODL\H registers
    Dim USART1_bRxIndexIn      As Byte Access                       ' Pointer to the next empty location in the buffer
    Dim USART1_bRxIndexOut     As Byte Access                       ' Pointer to the location of the oldest character in the buffer
    Dim USART1_bRXByte         As Byte Access                       ' Holds the byte received from USART1
    Dim USART1_tByteInBuffer   As Bit                               ' Holds true if a byte is in the RX buffer
'
' Create the serial buffer in high RAM
'
$define cUSART1_RxBufferSize 128                                    ' The amount of RAM reserved for the receive buffer (Max 255)
    Dim USART1_bRxBuffer[cUSART1_RxBufferSize] As Byte Heap         ' USART1 RX circular buffer (in high RAM because it is used indirectly)
'
' Create the variables for the interrupt driven USART1 Tx routines
' These need to be in Access RAM for non-banked operation
'
    Dim USART1_bTxTemp     As Byte Access
    Dim USART1_bTxIndexIn  As Byte Access                           ' \
    Dim USART1_bTxIndexOut As Byte Access                           ' / USART1 Tx buffer index variables
'
' Create the Tx buffer for USART1
'
    $define cUSART1_TxBufferSize 128                                ' Tx Serial buffer size must be a power of 2. i.e. 2, 4, 8, 16, 32, 64 or 128
$define cUSART1_TxFIFO_Mask $eval (cUSART1_TxBufferSize - 1)        ' Create a mask for resetting or testing the serial buffer
    Dim USART1_bTxBuffer[cUSART1_TxBufferSize] As Byte Heap         ' USART1 TX circular buffer (in high RAM because it is used indirectly)
'
' Alias some SFR's as 16-bit variables
'
    Dim USART1_wFSR0 As FSR0L.Word
    Dim USART1_wFSR1 As FSR1L.Word

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

'------------------------------------------------------------------------------------------------
' USART1 RX SFRs and bits for a PIC18F26K40 device
'
$define USART1_RX_Flag()       PIR3bits_RC1IF                   ' The flag that indicates a byte has been received
$define USART1_RX_ClearFlag()  USART1_RX_Flag() = 0             ' Reset the receive flag
$define USART1_RX_IntFlag()    PIE3bits_RC1IE                   ' The USART1 RX interrupt bit
$define USART1_RX_IntEnable()  USART1_RX_IntFlag() = 1          ' Enable a USART1 RX interrupt
$define USART1_RX_IntDisable() USART1_RX_IntFlag() = 0          ' Disable a USART1 RX interrupt

'------------------------------------------------------------------------------------------------
' USART1 TX SFRs and bits for a PIC18F26K40 device
'
$define USART1_TX_Flag()       PIR3bits_TX1IF                   ' The flag that indicates a byte is being transmitted
$define USART1_TX_ClearFlag()  USART1_TX_Flag() = 0             ' Reset the transmission flag
$define USART1_TX_IntFlag()    PIE3bits_TX1IE                   ' The USART1 TX interrupt bit
$define USART1_TX_IntEnable()  USART1_TX_IntFlag() = 1          ' Enable a USART1 TX interrupt
$define USART1_TX_IntDisable() USART1_TX_IntFlag() = 0          ' Disable a USART1 TX interrupt

'------------------------------------------------------------------------------------------------
$define Global_Int_Enable()  INTCONbits_GIE = 1                 ' Enable global interrupts
$define Global_Int_Disable() INTCONbits_GIE = 0                 ' Disable global interrupts
$define Periph_Int_Enable()  INTCONbits_PEIE = 1                ' Enable peripheral interrupts
$define Periph_Int_Disable() INTCONbits_PEIE = 0                ' Disable peripheral interrupts

'-------------------------------------------------------------------------------------------
    GoTo _USART1_Buffer_Main_                                   ' Jump over the replacement subroutines

'-------------------------------------------------------------------------------------------
' Wait for a byte from the interrupt driven circular buffer with timeout
' Input     : GEN\GENH hold the timeout value in approx ms (0 to 65535)
' Output    : PP0 and WREG hold the value received
'           : CARRY Flag (STATUS.0) Clear if timeout out
' Notes     : Uses PRODL\H as temporary variable storage
'           : Uses FSR0L\H as buffer the pointer
'
#ifSym __SYSCOM_HRSIN1_TO_REQ_
__HRsin1_With_TimeOut__:
    USART1_wOutsideLoop = USART1_wTimeoutValue                  ' Save the timeout value so it doesn't get overwritten
    Clear USART1_wInsideLoop                                    ' 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_bRxIndexIn                                    ' \
    Subwf     USART1_bRxIndexOut,w                              ' / Is there anything in the serial buffer?
    Bnz       USART1_GetByte                                    ' Yes. So fetch it
    WREG = 255                                                  ' \
    Addwf     USART1_wInsideLoop,f                              ' |
    Addwfc    USART1_wInsideLoopH,f                             ' | Decrement the inside and outside loops
    Addwfc    USART1_wOutsideLoop,f                             ' |
    Addwfc    USART1_wOutsideLoopH,f                            ' /
    Btfss     STATUSbits_C
    Ret                                                         ' Return with the Carry flag clear to indicate timed out
    Infsnz    USART1_wInsideLoop,w
    Incfsz    USART1_wInsideLoopH,w
    GoTo _USART1_OutsideLoop
    USART1_wInsideLoop = ((59 * Xtal) / 4)                      ' Set the inside loop counter based upon the Xtal frequency
    GoTo _USART1_InsideLoop
#endIfSym   ' __SYSCOM_HRSIN1_TO_REQ_

'-------------------------------------------------------------------------------------------
' Wait for a byte from the interrupt driven circular buffer without timeout
' Input     : None
' Output    : WREG holds the value received
' Notes     : Uses FSR0L\H as buffer pointers
'
#ifSym __SYSCOM_HRSIN1_REQ_
__HRsin1__:
    While USART1_bRxIndexIn = USART1_bRxIndexOut                ' \ Wait for a byte to appear in the serial buffer
    Wend                                                        ' /
#endIfSym   ' __SYSCOM_HRSIN1_REQ_
'
' Fall through to USART1_GetByte
'-------------------------------------------------------------------------------------------
' Read a byte from the interrupt driven circular buffer
' Input     : None
' Output    : PP0 and WREG hold the value received
' Notes     : Uses FSR0L\H as buffer pointers
'
#ifSym __SYSCOM_HRSIN1_HELPERS_REQ_
USART1_GetByte:
    Inc USART1_bRxIndexOut                                      ' Increment USART1_bRxIndexOut pointer (0 to 255)
    If USART1_bRxIndexOut >= cUSART1_RxBufferSize Then          ' End of buffer reached?
        USART1_bRxIndexOut = 0                                  ' Yes. So reset USART1_bRxIndexOut.
    EndIf
    USART1_wFSR0Save = USART1_wFSR0                             ' Save FSR0L\H registers
    USART1_wFSR0 = AddressOf(USART1_bRxBuffer)                  ' Point FSR0L\H to USART1_bRxBuffer
    USART1_wFSR0 = USART1_wFSR0 + USART1_bRxIndexOut            ' Add the buffer position to FSR0L\H
    WREG = INDF0                                                ' Read buffer location (USART1_bRxIndexOut) into WREG
    PP0 = WREG                                                  ' Also place it into PP0
    USART1_wFSR0 = USART1_wFSR0Save                             ' Restore FSR0\H registers
    STATUSbits_C = 1                                            ' Set the Carry flag to indicate a byte received
    Return
#endIfSym   ' __SYSCOM_HRSIN1_HELPERS_REQ_

'-------------------------------------------------------------------------------------------
' Transmit a single byte from the buffer to USART1
' Input     : WREG holds the byte to transmit
' Output    : WREG still holds the byte transmitted
' Notes     : If the buffer is full, wait until an empty slot is present
'           : Replacement for the compiler's HRSOut command
'
#ifSym __SYSCOM_HRSOUT1_REQ_
__HRSOut1__:
    PP0 = WREG                                                  ' Transfer WREG to its working variable
    Repeat                                                      ' \
        USART1_bTxTemp = USART1_bTxIndexIn + 1                  ' |
        USART1_bTxTemp = USART1_bTxTemp & cUSART1_TxFIFO_Mask   ' | Wait until the USART1 TX buffer has an empty slot
    Until USART1_bTxTemp <> USART1_bTxIndexOut                  ' /
    USART1_TX_IntDisable()                                      ' Disable a USART1 TX interrupt
    USART1_bTxBuffer[USART1_bTxIndexIn] = PP0                   ' Place a byte to transmit into the buffer
    Inc USART1_bTxIndexIn                                       ' Increment the In buffer Index
    USART1_bTxIndexIn = USART1_bTxIndexIn & cUSART1_TxFIFO_Mask ' Reset when full
    USART1_TX_IntEnable()                                       ' Enable a USART1 TX Interrupt
    WREG = PP0                                                  ' Restore WREG before leaving
    Return
#endIfSym   ' __SYSCOM_HRSOUT1_REQ_

'-------------------------------------------------------------------------------------------
' Clear the Serial Buffers
' Input     : None
' Output    : None
' Notes     : Also resets the index pointers to the serial buffer
'
Proc USART1_ClearSerialBuffers()
    WREG = RCREG1                                               ' \ Empty the USART's 2-byte serial buffer
    WREG = RCREG1                                               ' /
    USART1_RX_Flag() = False                                    ' Reset the byte received flag
    Clear USART1_bRxBuffer                                      ' Clear the serial RX buffer
    Clear USART1_bTxBuffer                                      ' Clear the serial TX buffer
    USART1_bRxIndexIn = 0                                       ' Reset the buffer internal pointer
    USART1_bRxIndexOut = 0                                      ' Reset the buffer external pointer
    USART1_bTxIndexIn = 0                                       ' \
    USART1_bTxIndexOut = 0                                      ' / Reset the USART1 Tx buffer Indexes
    USART1_tByteInBuffer = False                                ' Reset the byte in buffer flag
EndProc

'-------------------------------------------------------------------------------------------
' Initialise the serial buffers and interrupts
' Input     : None
' Output    : None
' Notes     : None
'
Proc USART1_Buff_Init()
    Global_Int_Disable()                                        ' Disable global interrupts (just in case)
    USART1_TX_IntDisable()                                      ' Disable a USART1 TX interrupt
    WREG = RCREG1                                               ' \ Empty the USART's 2-byte serial buffer
    WREG = RCREG1                                               ' /
    USART1_RX_Flag() = False                                    ' Reset the byte received flag
    Clear USART1_bRxBuffer                                      ' Clear the serial RX buffer
    Clear USART1_bTxBuffer                                      ' Clear the serial TX buffer
    USART1_bRxIndexIn = 0                                       ' Reset the buffer internal pointer
    USART1_bRxIndexOut = 0                                      ' Reset the buffer external pointer
    USART1_bTxIndexIn = 0                                       ' \
    USART1_bTxIndexOut = 0                                      ' / Reset the USART1 Tx buffer Indexes
    USART1_tByteInBuffer = False                                ' Reset the byte in buffer flag
    USART1_RX_IntEnable()                                       ' Enable an interrupt on USART1 receive
    Periph_Int_Enable()                                         ' Enable peripheral interrupts
    Global_Int_Enable()                                         ' Enable global interrupts
EndProc

'-------------------------------------------------------------------------------------------
_USART1_Buffer_Main_:

$endif  ' _device
$endif  ' _BUFFER_USART1_INC_

A demo program for the above include file is listed below:
'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate the USART1 RX and TX Interrupt buffer routines, that replace the compiler's HRsin, HSerin, HRsout and HSerout commands
' Written for the Positron8 compiler by Les Johnson.
'
    Device = 18F26K40                                       ' 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
'
' Setup USART1
'
    Declare HRSOut1_Pin   = PORTC.6
    Declare HRSIn1_Pin    = PORTC.7
    Declare Hserial1_Baud = 9600

    Include "Int_TX_RX_18FxxK40.inc"                        ' Load the USART1 buffer routines into the program
'
' Create a variable for the demo
'
    Dim ByteIn As Byte
  
'-------------------------------------------------------------------------------------------
' The main program starts here
' Transmits text via the interrupt TX buffer
' Then receives characters via the interrupt RX buffer,
' even though there is a large delay between listening
'
Main:
    Setup()                                                 ' Setup the program

    HRSOut1Ln "\rThis message is transmitted via the interrupt TX buffer, so it is very fast.\r",
              "Type in some characters and see them appear on the serial terminal\r",
              "Even though there is a large delay between receiving the individual characters\r",
              "They are received via the interrupt RX buffer"

ListenAgain:   
    Do                                                      ' Create a loop
        HSerIn1 5000, TimedOut, [ByteIn]                    ' Receive a byte from USART1, with a 5 second timeout
        DelayMS 1000                                        ' Place a silly long delay between bytes received, to test the buffer
        HSerOut1 [ByteIn]                                   ' Transmit the character received
    Loop                                                    ' Do it forever
'
' Jump here if a timeout occurs with USART1 receive
'   
TimedOut:
    HRSOut1Ln "Serial Timed Out"
    GoTo ListenAgain                                        ' Jump back to start listening again
   
'-------------------------------------------------------------------------------------------
' Setup the program, variables and peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    Oscillator_64MHz()                                      ' Setup the device to use its internal oscillator at 64MHz
    USART1_Buff_Init()                                      ' Initialise the USART1 buffer interrupt
EndProc

'-------------------------------------------------------------------------------------------
' Interrupt Service Routine handler
' Input     : None
' Output    : USART1_tByteInBuffer is true if a byte has been received
' Notes     : Implements buffered replacement for HRsin and Hrsout and HSerin and HSerout
'
ISR_Handler:
    Context Save FSR1L, FSR1H                                               ' Save any system variables and SFRs used
'
' Service a USART1 RX interrupt
'
    If USART1_RX_Flag() = True Then                                         ' Was it a USART1 byte receive that triggered the interrupt?
        WREG = RCSTA & %00000110                                            ' Yes. So mask out unwanted bits and check for errors
        If STATUSbits_Z = 0 Then                                            ' Are there any bits set in RCSTA?
            WREG = RCREG1                                                   ' \ Yes. So empty the 2 byte USART1 buffer
            WREG = RCREG1                                                   ' /
            RCSTAbits_CREN = 0                                              ' Disable USART1's RX to clear flags
            USART1_RX_Flag() = 0                                            ' Clear the USART1 RX flag
            RCSTAbits_CREN = 1                                              ' Re-Enable USART1's RX
        Else                                                                ' Otherwise... No error so...
            USART1_bRXByte = RCREG1                                         ' Place the byte received into USART1_bRXByte
            Inc USART1_bRxIndexIn                                           ' Move up the buffer
            If USART1_bRxIndexIn >= cUSART1_RxBufferSize Then               ' End of buffer reached?
                USART1_bRxIndexIn = 0                                       ' Yes. So reset USART1_bRxIndexIn
            EndIf
            USART1_wFSR1 = AddressOf(USART1_bRxBuffer)                      ' Point FSR1L\H to the address of USART1_bRxBuffer
            USART1_wFSR1 = USART1_wFSR1 + USART1_bRxIndexIn                 ' Add the buffer position to FSR1L\H
            INDF1 = USART1_bRXByte                                          ' Place the received character into the buffer
            USART1_tByteInBuffer = True                                     ' Indicate that there is an ASCII character in the buffer
        EndIf
    EndIf
'
' Service a USART1 TX interrupt
'
    If USART1_TX_Flag() = True Then                                         ' Was it a USART1 transmit that triggered the interrupt?
        If USART1_TX_IntFlag() = True Then                                  ' Yes. So is a USART1 TX interrupt enabled?
            TXREG1 = USART1_bTxBuffer[USART1_bTxIndexOut]                   ' Yes. So transmit a byte from the USART1 buffer
            Inc USART1_bTxIndexOut                                          ' Increment the out USART1 buffer Index
            USART1_bTxIndexOut = USART1_bTxIndexOut & cUSART1_TxFIFO_Mask   ' Reset when full
            If USART1_bTxIndexOut = USART1_bTxIndexIn Then                  ' Are there any more bytes in the USART1 TX buffer?
                USART1_TX_IntDisable()                                      ' No. So disable USART1 TX interrupts
            EndIf
        EndIf
    EndIf
'
' **** More User interrupt servicing code goes here ****
'
    Context Restore                                                         ' Restore variables then exit the interrupt

'--------------------------------------------------------------------
' Set the microcontroller to internal 64MHz operation with an HFINTOSC_1MHZ fuse
' Input     : None
' Output    : None
' Notes     : None
'
Proc Oscillator_64MHz()
    OSCCON1 = %01100000
    OSCCON3 = %00000000
    OSCEN   = %00000000
    OSCFRQ  = %00001000
    OSCTUNE = %00000000
    Repeat: Until OSCSTATbits_HFOR = 1
EndProc

'------------------------------------------------------------------------------
' Setup the fuses to use the internal oscillator on a PIC18F26K40. With RA6 and RA7 as I/O lines
'
Config_Start
    RSTOSC = HFINTOSC_1MHZ          ' With HFFRQ = 4MHz and CDIV = 4:1
    FEXTOSC = Off                   ' External Oscillator not enabled
    WDTE = Off                      ' WDT disabled
    CLKOUTEN = Off                  ' CLKOUT function is disabled
    CSWEN = On                      ' Writing to NOSC and NDIV is allowed
    FCMEN = Off                     ' Fail-Safe Clock Monitor disabled
    MCLRE = EXTMCLR                 ' If LVP = 0, MCLR pin is MCLR. If LVP = 1, RE3 pin function is MCLR
    PWRTE = On                      ' Power up timer enabled
    LPBOREN = off                   ' ULPBOR disabled
    BOREN = On                      ' Brown-out turned on
    BORV = VBOR_245                 ' Brown-out Reset Voltage (VBOR) set to 2.45V
    ZCD = Off                       ' ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                   ' PPSLOCK bit can be set and cleared repeatedly (subject to the unlock sequence)
    STVREN = Off                    ' Stack full/underflow will not cause Reset
    Debug = Off                     ' Background debugger disabled
    XINST = Off                     ' Extended Instruction Set and Indexed Addressing Mode disabled
    SCANE = Off                     ' Scanner module is Not available for use. SCANMD bit is ignored
    LVP = On                        ' Low Voltage programming enabled
    WDTCPS = WDTCPS_15              ' Watchdog Divider ratio 1:1048576 (32 seconds)
    WDTCWS = WDTCWS_7               ' Window always open (100%). Software control. Keyed access not required
    WDTCCS = LFINTOSC               ' WDT input clock selector->WDT reference clock is the 31.2kHz HFINTOSC output
    WRT0 = Off                      ' Block 0 (000800-001FFF) not write-protected
    WRT1 = Off                      ' Block 1 (002000-003FFF) not write-protected
    WRTC = Off                      ' Configuration registers (300000-30000B) not write-protected
    WRTB = Off                      ' Boot Block (000000-0007FF) write-protected
    WRTD = Off                      ' Data EEPROM not write-protected
    Cp = Off                        ' UserNVM code protection disabled
    CPD = Off                       ' DataNVM code protection disabled
    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

The demo program will operate the PIC18F26K40 device at 64MHz, using its internal oscilaltor, and transmit a block of text to a serial terminal at 9600 Baud using the TX buffer. It will then wait for characters typed into a serial terminal, and display them on it, even though there is a very long delay implemented in the program between listening for the bytes. This proves the serial RX buffer is operating.

I'm back......... :-)




Dave-S

Thanks for the replies.
Great, have finally got it working, Thank you for your help.

I have used JONW revised code and changed as tubleweed suggested
 Symbol ENABLE_GLOBAL_INT = INTCON.1    to   Symbol ENABLE_GLOBAL_INT = INTCON.7
INTCON = B'00000000'    to   INTCON = B'00100000' 

and altered  "Check the USART1 RX interrupt" to
ISR_Handler:
    Context Save FSR1L, FSR1H                           ' Save any compiler system variables and any SFRs used before we perform the interrupt code
'
' Check the USART1 RX interrupt
     If RXIF = 1 Then
        If RXPNTR = RX_BUFFERSIZE Then   ' INCREMEMENT POINTER
             RXBYTE = RC1REG                   ' LOAD BYTE INTO ARRAY
             RXPNTR = 0
             GoTo RX_FULL 
        EndIf
        RXBYTE = RC1REG
        RXBUFFER[RXPNTR] = RXBYTE
        'HRSOut dec RXBUFFER[RXPNTR], " ", dec RXPNTR, 13
          Inc RXPNTR
          'HRSOut "T", Dec RXPNTR, 13
        If  RXBYTE = EOM Then
            Dec RXPNTR
           ' HRSOut "B", Dec RXPNTR, 13
             EOM_FLAG = 1                               ' WE HAVE BYTE IN THE BUFFER
             RXIF = 0
             GoTo EXIT_INT
        EndIf
     EndIf

RX_FULL: ' add more code for buffer full later on
   

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

It was not creating an Interrupt so I changed "ENABLE_GLOBAL_INT = 0" to a "1" and it goes to the
ISR_Handler, then the "RXPNTR" was zero all the time because as it went through "RX_FULL" it got set to zero.

Now working OK many thanks
David




Dave-S

Further testing to use with an input from Modbus I find it only reads 2 Bytes.
If I send from PC "01030002000265CB" via USB/serial to HRSin of 18F47K40 it receives all 18 bytes.
If I send from PC "01030002000265CB" via USB/Modbus to PC Modbus/TTl Module to PC USB/serial it receives all 18 bytes.
But when I send from PC "01030002000265CB" via USB/Modbus to Modbus/TTl Module to HRSin of 18F47K40 it receives only the first 2 bytes, the "RXIF" then goes to zero.

Can someone tell me how the ISR_Handler code works, does it keep returning to "If RXIF = 1 Then" if it = 1
It appears to go through this for the 18 bytes, but when only 2 bytes are received it drops out and then will not accept another interrupt until I reset PIC.

ISR_Handler:
    Context Save FSR1L, FSR1H    ' Save any compiler system variables and any SFRs used before we perform the interrupt code
' Check the USART1 RX interrupt
     If RXIF = 1 Then
          If RXPNTR = RX_BUFFERSIZE Then   ' INCREMEMENT POINTER
               RXBYTE = RC1REG                   ' LOAD BYTE INTO ARRAY
               RXPNTR = 0
               GoTo RX_FULL
          EndIf
              RXBYTE = RC1REG
              RXBUFFER[RXPNTR] = RXBYTE
              Inc RXPNTR
          If  RXBYTE = EOM Then
              Dec RXPNTR
              EOM_FLAG = 1        ' WE HAVE BYTE IN THE BUFFER
              RXIF = 0
              GoTo EXIT_INT
          EndIf
    EndIf

RX_FULL: ' add more code for buffer full later on
   

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

trastikata

#12
.

tumbleweed

The way the USART works is when a byte comes in RCIF gets set and if everything's setup properly you should get an interrupt. In the ISR, when you read the RC1REG that automatically clears RCIF (RCIF is a read-only bit so there's no reason to try and clear it using 'RCIF = 0'). When the next byte comes in the process repeats.

If you don't read the bytes as they come in, if/when the USART hardware FIFO fills after three bytes you get an OERR (RC1STA.1) and the USART will not accept any more bytes until you deal with it.

Post all the code... it's hard to tell what's going on. For example, do you ever initialize RXPNTR at the start of the program?

Dave-S

Thanks for reply tumbleweed and for explaining how Interrupt works.
Attached full code so far.
Code used was what JonW supplied in earlier post.
Something is not right because if I remove the  "HRSOut" instructions in the MainLoop I do not get any Interrupt, so it look as if "HRSOut" is initiating the interrupt.

Thanks for your help David   

'****************************************************************
'*  Name    : Pylon Battery Monitor-9.BAS                       *
'*  Author  : David Summers                                     *
'*  Notice  : Copyright (c) 2022 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 16/12/2022                                        *
'*  Version : 3.0                                               *
'*  Notes   :                                                   *
'*          :                                                   *
'****************************************************************
 Device = 18F47K40
Include "I2CPrintHardCommand.inc"

Declare Xtal = 64                                   ' Tell the compiler that the device will be running at 64MHz
Declare Hserial1_Baud = 9600                     ' Set the Baud rate for USART1
Declare HRSOut_Pin  = PORTC.6                       ' Set the pin used for USART1 TX
Declare HRSIn_Pin   = PORTC.7                       ' Set the pin used for USART1 RX
Declare Hserial_RCSTA = %10010000                   ' Enable serial port and continuous receive
Declare Hserial_Clear = On                          ' Enable Error clearing on received characters      ' Clear the buffer before receiving


Symbol SDA = PORTC.4        'I2C data pin.
Symbol SCL = PORTC.3        'I2C clock pin.
Declare Float_Display_Type = Fast
Declare Slow_Bus On
Declare ACCESS_UPPER_64K = 1

Declare All_Digital = true
Declare Create_Coff On
Declare Watchdog = off

On_Hardware_Interrupt GoTo ISR_Handler              ' Point to the interrupt handler routine

Symbol EOM = "%"                    ' END OF MESSAGE TERMINATOR
Symbol RXIF =  PIR3.5               ' INTERRUPT FLAG
Symbol RXINT_ENABLE = PIE3.5        ' INTERRUPT ENABLE
Symbol RX_BUFFERSIZE = 22
Symbol ENABLE_GLOBAL_INT = INTCON.7

Dim RXBUFFER[RX_BUFFERSIZE]     As Byte
Dim RXPNTR                      As Byte  = 0
Dim RXBYTE                      As Byte
Dim EOM_FLAG                    As Bit

SETUP_PIC:
        INTCON = B'00100000'   '  Alter to suit priority
        ANSELA = 0
        ANSELB = 0
        ANSELC = 0
        CM1CON0 = 0
        T3CON =     %00000000
        TRISA =     %00000000   ; ALL OUTPUT
        TRISB =     %00000000   ; SEE PORT MAP
        TRISC =     %10000000   ; SERIAL PORT
        WPUA =      %00000000   ; NO PULLUPS
        WPUB =      %00000000   ; NO PULLUPS
        WPUC =      %00000000   ; NO PULLUPS

'ENABLE UART INT
        RXINT_ENABLE = 1
        ENABLE_GLOBAL_INT = 1
        EOM_FLAG = 0
        Dim x As Byte
        Dim bDestArray[16] As Byte Heap                         ' Holds the integer values from the ASCII hex characters
        Dim bCharIndex As Byte                                  ' Used to read the source array that holds the hex ASCII characters
        Dim bDestIndex As Byte                                  ' Used to load the destination array
        Dim bHexValue As Byte                                   ' Holds the converted hex ASCII to integer value
        RXPNTR = 0
        RXBYTE = 0
        Clear RXBUFFER


MAINLOOP:
          If EOM_FLAG = 1 Then
               HRSOut "MESSAGE IN BUFFER",13,10
               HRSOut "BYTES IN BUFFER = ", Dec RXPNTR,13,10
           x = 1
           bDestIndex = 0                                          ' Start at the destination array index of 0
           For bCharIndex = 0 To 15 Step 2                          ' Create a loop to read the Hex characters from the source
               bHexValue = ASCII_Hex(RXBUFFER[bCharIndex], RXBUFFER[bCharIndex + 1]) ' Convert the hex characters into an integer value
               bDestArray[bDestIndex] = bHexValue                  ' Load the integer value into the destination array
               Inc bDestIndex                                      ' Move up the element in the integer destination array
          Next       
          Cls
              For bDestIndex = 0 To 7
                   Print At 2, (bDestIndex + x), Hex2 bDestArray[bDestIndex]
                   Inc x
              Next 
         RXPNTR = 0
         EOM_FLAG = 0
        EndIf
        SerOut PORTD.1, 84, ["MainLoop", 13]
        DelayMS 900
        GoTo MAINLOOP

ISR_Handler:
    Context Save FSR1L, FSR1H                           ' Save any compiler system variables and any SFRs used before we perform the interrupt code
' Check the USART1 RX interrupt
     If RXIF = 1 Then
            If RXPNTR = RX_BUFFERSIZE Then   ' INCREMEMENT POINTER
                 RXBYTE = RC1REG             ' LOAD BYTE INTO ARRAY
                 RXPNTR = 0
                 GoTo RX_FULL
            EndIf
              RXBYTE = RC1REG
              RXBUFFER[RXPNTR] = RXBYTE
              Inc RXPNTR
          If  RXBYTE = EOM Then
               Dec RXPNTR
               EOM_FLAG = 1     ' WE HAVE BYTE IN THE BUFFER
               RXIF = 0
               GoTo EXIT_INT
         EndIf
    EndIf

RX_FULL: ' add more code for buffer full later on
   

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

'*************************************************************************************************
 Proc ASCII_Hex(pHexCharH As Byte, pHexCharL As Byte), Byte
    Dim bHexChars[3] As Byte                        ' Used to convert from Hex ASCII to integer
   
    bHexChars[0] = pHexCharH                        ' \
    bHexChars[1] = pHexCharL                        ' / Load the two hex characters into "bHexChars"
    bHexChars[2] = 0                                ' Add a null to the last element of "bHexChars"
    Result = Val(bHexChars, Hex)                    ' Convert the hex characters into an integer value
EndProc

'-------------------------------------------------------------------------------
'**** Added by Fuse Configurator ****
' Use the Fuses Tab to change these settings

Config_Start
  FEXTOSC = OFF               ;HS (crystal oscillator) above 8 MHz; PFM set to high powe
  RSTOSC = HFINTOSC_64MHZ    ;HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:
  CLKOUTEN = OFF             ;CLKOUT function is disable
  CSWEN = On                 ;Writing to NOSC and NDIV is allowe
  FCMEN = On                 ;Fail-Safe Clock Monitor enable
  MCLRE = INTMCLR            ;If LVP = 0, MCLR pin function is port defined function; If LVP =1, RE3 pin fuction is MCL
  PWRTE = OFF                ;Power up timer disable
  LPBOREN = OFF              ;ULPBOR disable
  BOREN = SBORDIS            ;Brown-out Reset enabled , SBOREN bit is ignore
  BORV = VBOR_2P45           ;Brown-out Reset Voltage (VBOR) set to 2.45
  ZCD = OFF                  ;ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCO
  PPS1WAY = On               ;PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycl
  STVREN = On                ;Stack full/underflow will cause Rese
  Debug = OFF                ;Background debugger disable
  XINST = OFF                ;Extended Instruction Set and Indexed Addressing Mode disable
  WDTCPS = WDTCPS_31         ;Divider ratio 1:65536; software control of WDTP
  WDTE = OFF                 ;WDT Disable
  WDTCWS = WDTCWS_7          ;window always open (100%); software control; keyed access not require
  WDTCCS = SC                ;Software Contro
  WRT0 = OFF                 ;Block 0 (000800-003FFFh) not write-protecte
  WRT1 = OFF                 ;Block 1 (004000-007FFFh) not write-protecte
  WRT2 = OFF                 ;Block 2 (008000-00BFFFh) not write-protecte
  WRT3 = OFF                 ;Block 3 (00C000-00FFFFh) not write-protecte
  WRT4 = OFF                 ;Block 4 (010000-013FFFh) not write-protecte
  WRT5 = OFF                 ;Block 5 (014000-017FFFh) not write-protecte
  WRT6 = OFF                 ;Block 6 (018000-01BFFFh) not write-protecte
  WRT7 = OFF                 ;Block 7 (01C000-01FFFFh) not write-protecte
  WRTC = OFF                 ;Configuration registers (300000-30000Bh) not write-protecte
  WRTB = OFF                 ;Boot Block (000000-0007FFh) not write-protecte
  WRTD = OFF                 ;Data EEPROM not write-protecte
  SCANE = On                 ;Scanner module is available for use, SCANMD bit can control the modul
  LVP = OFF                   ;Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignore
  Cp = OFF                   ;UserNVM code protection disable
  CPD = OFF                  ;DataNVM code protection disable
  EBTR0 = OFF                ;Block 0 (000800-003FFFh) not protected from table reads executed in other block
  EBTR1 = OFF                ;Block 1 (004000-007FFFh) not protected from table reads executed in other block
  EBTR2 = OFF                ;Block 2 (008000-00BFFFh) not protected from table reads executed in other block
  EBTR3 = OFF                ;Block 3 (00C000-00FFFFh) not protected from table reads executed in other block
  EBTR4 = OFF                ;Block 4 (010000-013FFFh) not protected from table reads executed in other block
  EBTR5 = OFF                ;Block 5 (014000-017FFFh) not protected from table reads executed in other block
  EBTR6 = OFF                ;Block 6 (018000-01BFFFh) not protected from table reads executed in other block
  EBTR7 = OFF                ;Block 7 (01C000-01FFFFh) not protected from table reads executed in other block
  EBTRB = OFF                ;Boot Block (000000-0007FFh) not protected from table reads executed in other block
Config_End

'**** End of Fuse Configurator Settings ****
'--------

JonW

#15
Dave are you sending the EOM byte "%" at the end of your serial stream?  The EOL flag will only be set if "%" is received as this is to terminate the reading of the RX packet (this is in the ISR)


You can also use timeout and omit the EOM checking by using a counter/timer and a flag to indicate a timeout and this an end of message time termination. On a successful received byte in the ISR you would reset this counter or timer.  If the timer counter times-out then you can process the data in the RXBUFFER.

Try this, (Have removed some code in the mainloop to make it easier to read for now.  DIM have been moved so they are all together and added code to reset the RXPNTR of the RX_BUFF is full.

Remember the processing will only occur when % is received. I would also ensure you are getting simple rx bytes received with the UART settings


'****************************************************************
'*  Name    : Pylon Battery Monitor-9.BAS                       *
'*  Author  : David Summers                                     *
'*  Notice  : Copyright (c) 2022 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 16/12/2022                                        *
'*  Version : 3.0                                               *
'*  Notes   :                                                   *
'*          :                                                   *
'****************************************************************
 Device = 18F47K40


Declare Xtal = 64                                   ' Tell the compiler that the device will be running at 64MHz
Declare Hserial1_Baud = 9600                     ' Set the Baud rate for USART1
Declare HRSOut_Pin  = PORTC.6                       ' Set the pin used for USART1 TX
Declare HRSIn_Pin   = PORTC.7                       ' Set the pin used for USART1 RX
Declare Hserial_RCSTA = %10010000                   ' Enable serial port and continuous receive
Declare Hserial_Clear = On                          ' Enable Error clearing on received characters      ' Clear the buffer before receiving


Symbol SDA = PORTC.4        'I2C data pin.
Symbol SCL = PORTC.3        'I2C clock pin.
Declare Float_Display_Type = Fast
Declare Slow_Bus On
Declare ACCESS_UPPER_64K = 1

Declare All_Digital = true
Declare Create_Coff On
Declare Watchdog = off

On_Hardware_Interrupt GoTo ISR_Handler              ' Point to the interrupt handler routine

Symbol EOM = "%"                    ' END OF MESSAGE TERMINATOR
Symbol RXIF =  PIR3.5               ' INTERRUPT FLAG
Symbol RXINT_ENABLE = PIE3.5        ' INTERRUPT ENABLE
Symbol RX_BUFFERSIZE = 22
Symbol ENABLE_GLOBAL_INT = INTCON.7

Dim RXBUFFER[RX_BUFFERSIZE]     As Byte
Dim RXPNTR                      As Byte  = 0
Dim RXBYTE                      As Byte
Dim EOM_FLAG                    As Bit

Dim x As Byte
Dim bDestArray[16] As Byte Heap                         ' Holds the integer values from the ASCII hex characters
Dim bCharIndex As Byte                                  ' Used to read the source array that holds the hex ASCII characters
Dim bDestIndex As Byte                                  ' Used to load the destination array
Dim bHexValue As Byte                                   ' Holds the converted hex ASCII to integer value


SETUP_PIC:
        INTCON = B'01000000'   '  Alter to suit priority
        ANSELA = 0
        ANSELB = 0
        ANSELC = 0
        CM1CON0 = 0
        T3CON =     %00000000
        TRISA =     %00000000   ; ALL OUTPUT
        TRISB =     %00000000   ; SEE PORT MAP
        TRISC =     %10000000   ; SERIAL PORT
        WPUA =      %00000000   ; NO PULLUPS
        WPUB =      %00000000   ; NO PULLUPS
        WPUC =      %00000000   ; NO PULLUPS

'ENABLE UART INT
        RXINT_ENABLE = 1
        ENABLE_GLOBAL_INT = 1
        EOM_FLAG = 0
        RXPNTR = 0
        RXBYTE = 0
        Clear RXBUFFER


MAINLOOP:
          If EOM_FLAG = 1 Then
               HRSOut "MESSAGE IN BUFFER",13,10
               HRSOut "BYTES IN BUFFER = ", Dec RXPNTR,13,10
               RXPNTR = 0
               EOM_FLAG = 0
          EndIf
          DelayMS 900
          GoTo MAINLOOP




ISR_Handler:
    Context Save FSR1L, FSR1H                           ' Save any compiler system variables and any SFRs used before we perform the interrupt code
' Check the USART1 RX interrupt
     If RXIF = 1 Then
            If RXPNTR = RX_BUFFERSIZE Then   ' INCREMEMENT POINTER
                 RXBYTE = RC1REG             ' LOAD BYTE INTO ARRAY
                 RXPNTR = 0
                 GoTo RX_FULL
            EndIf
              RXBYTE = RC1REG
              RXBUFFER[RXPNTR] = RXBYTE
              Inc RXPNTR
          If  RXBYTE = EOM Then
               Dec RXPNTR
               EOM_FLAG = 1     ' WE HAVE BYTE IN THE BUFFER
               RXIF = 0
               GoTo EXIT_INT
         EndIf
    EndIf

RX_FULL: ' add more code for buffer full later on
    RXPNTR = 0
    EOM_FLAG = 0

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





'*************************************************************************************************
 Proc ASCII_Hex(pHexCharH As Byte, pHexCharL As Byte), Byte
    Dim bHexChars[3] As Byte                        ' Used to convert from Hex ASCII to integer

    bHexChars[0] = pHexCharH                        ' \
    bHexChars[1] = pHexCharL                        ' / Load the two hex characters into "bHexChars"
    bHexChars[2] = 0                                ' Add a null to the last element of "bHexChars"
    Result = Val(bHexChars, Hex)                    ' Convert the hex characters into an integer value
EndProc

'-------------------------------------------------------------------------------
'**** Added by Fuse Configurator ****
' Use the Fuses Tab to change these settings

Config_Start
  FEXTOSC = OFF               ;HS (crystal oscillator) above 8 MHz; PFM set to high powe
  RSTOSC = HFINTOSC_64MHZ    ;HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:
  CLKOUTEN = OFF             ;CLKOUT function is disable
  CSWEN = On                 ;Writing to NOSC and NDIV is allowe
  FCMEN = On                 ;Fail-Safe Clock Monitor enable
  MCLRE = INTMCLR            ;If LVP = 0, MCLR pin function is port defined function; If LVP =1, RE3 pin fuction is MCL
  PWRTE = OFF                ;Power up timer disable
  LPBOREN = OFF              ;ULPBOR disable
  BOREN = SBORDIS            ;Brown-out Reset enabled , SBOREN bit is ignore
  BORV = VBOR_2P45           ;Brown-out Reset Voltage (VBOR) set to 2.45
  ZCD = OFF                  ;ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCO
  PPS1WAY = On               ;PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycl
  STVREN = On                ;Stack full/underflow will cause Rese
  Debug = OFF                ;Background debugger disable
  XINST = OFF                ;Extended Instruction Set and Indexed Addressing Mode disable
  WDTCPS = WDTCPS_31         ;Divider ratio 1:65536; software control of WDTP
  WDTE = OFF                 ;WDT Disable
  WDTCWS = WDTCWS_7          ;window always open (100%); software control; keyed access not require
  WDTCCS = SC                ;Software Contro
  WRT0 = OFF                 ;Block 0 (000800-003FFFh) not write-protecte
  WRT1 = OFF                 ;Block 1 (004000-007FFFh) not write-protecte
  WRT2 = OFF                 ;Block 2 (008000-00BFFFh) not write-protecte
  WRT3 = OFF                 ;Block 3 (00C000-00FFFFh) not write-protecte
  WRT4 = OFF                 ;Block 4 (010000-013FFFh) not write-protecte
  WRT5 = OFF                 ;Block 5 (014000-017FFFh) not write-protecte
  WRT6 = OFF                 ;Block 6 (018000-01BFFFh) not write-protecte
  WRT7 = OFF                 ;Block 7 (01C000-01FFFFh) not write-protecte
  WRTC = OFF                 ;Configuration registers (300000-30000Bh) not write-protecte
  WRTB = OFF                 ;Boot Block (000000-0007FFh) not write-protecte
  WRTD = OFF                 ;Data EEPROM not write-protecte
  SCANE = On                 ;Scanner module is available for use, SCANMD bit can control the modul
  LVP = OFF                   ;Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignore
  Cp = OFF                   ;UserNVM code protection disable
  CPD = OFF                  ;DataNVM code protection disable
  EBTR0 = OFF                ;Block 0 (000800-003FFFh) not protected from table reads executed in other block
  EBTR1 = OFF                ;Block 1 (004000-007FFFh) not protected from table reads executed in other block
  EBTR2 = OFF                ;Block 2 (008000-00BFFFh) not protected from table reads executed in other block
  EBTR3 = OFF                ;Block 3 (00C000-00FFFFh) not protected from table reads executed in other block
  EBTR4 = OFF                ;Block 4 (010000-013FFFh) not protected from table reads executed in other block
  EBTR5 = OFF                ;Block 5 (014000-017FFFh) not protected from table reads executed in other block
  EBTR6 = OFF                ;Block 6 (018000-01BFFFh) not protected from table reads executed in other block
  EBTR7 = OFF                ;Block 7 (01C000-01FFFFh) not protected from table reads executed in other block
  EBTRB = OFF                ;Boot Block (000000-0007FFh) not protected from table reads executed in other block
Config_End

'**** End of Fuse Configurator Settings ****

trastikata

Quote from: Dave-S on Dec 20, 2022, 02:02 PMAttached full code so far.

Hello Dave-s,

looking through your code it seems you have set-up incorrectly the USART interrupts. Please consult the datasheet. I don't know why my previous post has only one dot after the correction I did, there was supposed to be some explanation there. Anywhere here's the important part I pointed out then:

QuoteThe EUSART receiver is enabled for asynchronous operation by configuring the following three control
bits:
• CREN = 1 (enables the receiver circuitry of the EUSART)
• SYNC = 0 (configures the EUSART for asynchronous operation)
• SPEN = 1 (enables the EUSART)

RCxIF interrupts are enabled by setting all of the following bits:
• RCxIE, Interrupt Enable bit of the PIEx register
• PEIE, Peripheral Interrupt Enable bit of the INTCON register
• GIE, Global Interrupt Enable bit of the INTCON register

The RCxIF interrupt flag bit will be set when there is an unread character in the FIFO, regardless of the
state of interrupt enable bits.

From what I see in your code the PEIE is not set.

For the CREN and SPEN bits I can't currently check in the Assembler code if they are automatically set by Positron, but it doesn't hurt to add them in your code.

Dave-S

Thanks For the replies.
Tried what JONW posted but get nothing, yes I am sending EOM %

trastikata Have revised the code as suggested, is this now correct?
Yes I get the "01030002000265CB" sent including EOM % but if I remove the two lines,

HRSOut "MESSAGE IN BUFFER",13,10
HRSOut "BYTES IN BUFFER = ", Dec RXPNTR,13,10

from the MainLoop I get NO Interrupt.

'****************************************************************
'*  Name    : Pylon Battery Monitor-9.BAS                       *
'*  Author  : David Summers                                     *
'*  Notice  : Copyright (c) 2022 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 16/12/2022                                        *
'*  Version : 3.0                                               *
'*  Notes   :                                                   *
'*          :                                                   *
'****************************************************************
 Device = 18F47K40
Include "I2CPrintHardCommand.inc"

Declare Xtal = 64                                   ' Tell the compiler that the device will be running at 64MHz
Declare Hserial1_Baud = 9600                     ' Set the Baud rate for USART1
Declare HRSOut_Pin  = PORTC.6                       ' Set the pin used for USART1 TX
Declare HRSIn_Pin   = PORTC.7                       ' Set the pin used for USART1 RX
Declare Hserial_RCSTA = %10010000                   ' Enable serial port and continuous receive
Declare Hserial_Clear = On                          ' Enable Error clearing on received characters      ' Clear the buffer before receiving


Symbol SDA = PORTC.4        'I2C data pin.
Symbol SCL = PORTC.3        'I2C clock pin.
Declare Float_Display_Type = Fast
Declare Slow_Bus On
Declare ACCESS_UPPER_64K = 1

Declare All_Digital = true
Declare Create_Coff On
Declare Watchdog = off

On_Hardware_Interrupt GoTo ISR_Handler              ' Point to the interrupt handler routine

Symbol EOM = "%"                    ' END OF MESSAGE TERMINATOR
Symbol RXIF =  PIR3.5               ' INTERRUPT FLAG
Symbol RXINT_ENABLE = PIE3.5        ' INTERRUPT ENABLE
Symbol RX_BUFFERSIZE = 22
Symbol ENABLE_GLOBAL_INT = INTCON.7

Dim RXBUFFER[RX_BUFFERSIZE]     As Byte
Dim RXPNTR                      As Byte  = 0
Dim RXBYTE                      As Byte
Dim EOM_FLAG                    As Bit

SETUP_PIC:
        RC1STA.4 = 1    'CREN = 1
        RC1STA.7 = 1    'SPEN = 1
        TX1STA.4 = 0     'SYNC = 0
        INTCON.6 = 1     'PEIE = 1
        INTCON.5 = 1     'IPEN = 1
        ANSELA = 0
        ANSELB = 0
        ANSELC = 0
        CM1CON0 = 0
        T3CON =     %00000000
        TRISA =     %00000000   ; ALL OUTPUT
        TRISB =     %00000000   ; SEE PORT MAP
        TRISC =     %10000000   ; SERIAL PORT
        WPUA =      %00000000   ; NO PULLUPS
        WPUB =      %00000000   ; NO PULLUPS
        WPUC =      %00000000   ; NO PULLUPS

'ENABLE UART INT
        RXINT_ENABLE = 1
        ENABLE_GLOBAL_INT = 1
        EOM_FLAG = 0
        Dim x As Byte
        Dim bDestArray[16] As Byte Heap                         ' Holds the integer values from the ASCII hex characters
        Dim bCharIndex As Byte                                  ' Used to read the source array that holds the hex ASCII characters
        Dim bDestIndex As Byte                                  ' Used to load the destination array
        Dim bHexValue As Byte                                   ' Holds the converted hex ASCII to integer value
        RXPNTR = 0
        RXBYTE = 0
        Clear RXBUFFER


MAINLOOP:
          If EOM_FLAG = 1 Then
               HRSOut "MESSAGE IN BUFFER",13,10
               HRSOut "BYTES IN BUFFER = ", Dec RXPNTR,13,10
           x = 1
           bDestIndex = 0                                          ' Start at the destination array index of 0
           For bCharIndex = 0 To 15 Step 2                          ' Create a loop to read the Hex characters from the source
               bHexValue = ASCII_Hex(RXBUFFER[bCharIndex], RXBUFFER[bCharIndex + 1]) ' Convert the hex characters into an integer value
               bDestArray[bDestIndex] = bHexValue                  ' Load the integer value into the destination array
               Inc bDestIndex                                      ' Move up the element in the integer destination array
          Next       
          Cls
              For bDestIndex = 0 To 7
                    Print $FE, 3 'Backlight on
                    Cls
                    Print At 2, (bDestIndex + x), Hex2 bDestArray[bDestIndex]
                   Inc x
              Next 
         RXPNTR = 0
         EOM_FLAG = 0
        EndIf
        SerOut PORTD.1, 84, ["MainLoop", 13]
        DelayMS 900
        GoTo MAINLOOP

ISR_Handler:
    Context Save FSR1L, FSR1H                           ' Save any compiler system variables and any SFRs used before we perform the interrupt code
' Check the USART1 RX interrupt
     If RXIF = 1 Then
            If RXPNTR = RX_BUFFERSIZE Then   ' INCREMEMENT POINTER
                 RXBYTE = RC1REG             ' LOAD BYTE INTO ARRAY
                 RXPNTR = 0
                 GoTo RX_FULL
            EndIf
              RXBYTE = RC1REG
              RXBUFFER[RXPNTR] = RXBYTE
              Inc RXPNTR
          If  RXBYTE = EOM Then
               Dec RXPNTR
               EOM_FLAG = 1     ' WE HAVE BYTE IN THE BUFFER
               RXIF = 0
               GoTo EXIT_INT
         EndIf
    EndIf

RX_FULL: ' add more code for buffer full later on
   

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

'*************************************************************************************************
 Proc ASCII_Hex(pHexCharH As Byte, pHexCharL As Byte), Byte
    Dim bHexChars[3] As Byte                        ' Used to convert from Hex ASCII to integer
   
    bHexChars[0] = pHexCharH                        ' \
    bHexChars[1] = pHexCharL                        ' / Load the two hex characters into "bHexChars"
    bHexChars[2] = 0                                ' Add a null to the last element of "bHexChars"
    Result = Val(bHexChars, Hex)                    ' Convert the hex characters into an integer value
EndProc

'-------------------------------------------------------------------------------
'**** Added by Fuse Configurator ****
' Use the Fuses Tab to change these settings

Config_Start
  FEXTOSC = OFF               ;HS (crystal oscillator) above 8 MHz; PFM set to high powe
  RSTOSC = HFINTOSC_64MHZ    ;HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:
  CLKOUTEN = OFF             ;CLKOUT function is disable
  CSWEN = On                 ;Writing to NOSC and NDIV is allowe
  FCMEN = On                 ;Fail-Safe Clock Monitor enable
  MCLRE = INTMCLR            ;If LVP = 0, MCLR pin function is port defined function; If LVP =1, RE3 pin fuction is MCL
  PWRTE = OFF                ;Power up timer disable
  LPBOREN = OFF              ;ULPBOR disable
  BOREN = SBORDIS            ;Brown-out Reset enabled , SBOREN bit is ignore
  BORV = VBOR_2P45           ;Brown-out Reset Voltage (VBOR) set to 2.45
  ZCD = OFF                  ;ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCO
  PPS1WAY = On               ;PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycl
  STVREN = On                ;Stack full/underflow will cause Rese
  Debug = OFF                ;Background debugger disable
  XINST = OFF                ;Extended Instruction Set and Indexed Addressing Mode disable
  WDTCPS = WDTCPS_31         ;Divider ratio 1:65536; software control of WDTP
  WDTE = OFF                 ;WDT Disable
  WDTCWS = WDTCWS_7          ;window always open (100%); software control; keyed access not require
  WDTCCS = SC                ;Software Contro
  WRT0 = OFF                 ;Block 0 (000800-003FFFh) not write-protecte
  WRT1 = OFF                 ;Block 1 (004000-007FFFh) not write-protecte
  WRT2 = OFF                 ;Block 2 (008000-00BFFFh) not write-protecte
  WRT3 = OFF                 ;Block 3 (00C000-00FFFFh) not write-protecte
  WRT4 = OFF                 ;Block 4 (010000-013FFFh) not write-protecte
  WRT5 = OFF                 ;Block 5 (014000-017FFFh) not write-protecte
  WRT6 = OFF                 ;Block 6 (018000-01BFFFh) not write-protecte
  WRT7 = OFF                 ;Block 7 (01C000-01FFFFh) not write-protecte
  WRTC = OFF                 ;Configuration registers (300000-30000Bh) not write-protecte
  WRTB = OFF                 ;Boot Block (000000-0007FFh) not write-protecte
  WRTD = OFF                 ;Data EEPROM not write-protecte
  SCANE = On                 ;Scanner module is available for use, SCANMD bit can control the modul
  LVP = OFF                   ;Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignore
  Cp = OFF                   ;UserNVM code protection disable
  CPD = OFF                  ;DataNVM code protection disable
  EBTR0 = OFF                ;Block 0 (000800-003FFFh) not protected from table reads executed in other block
  EBTR1 = OFF                ;Block 1 (004000-007FFFh) not protected from table reads executed in other block
  EBTR2 = OFF                ;Block 2 (008000-00BFFFh) not protected from table reads executed in other block
  EBTR3 = OFF                ;Block 3 (00C000-00FFFFh) not protected from table reads executed in other block
  EBTR4 = OFF                ;Block 4 (010000-013FFFh) not protected from table reads executed in other block
  EBTR5 = OFF                ;Block 5 (014000-017FFFh) not protected from table reads executed in other block
  EBTR6 = OFF                ;Block 6 (018000-01BFFFh) not protected from table reads executed in other block
  EBTR7 = OFF                ;Block 7 (01C000-01FFFFh) not protected from table reads executed in other block
  EBTRB = OFF                ;Boot Block (000000-0007FFh) not protected from table reads executed in other block
Config_End

'**** End of Fuse Configurator Settings ****
'--------     
       
       

trastikata

#18
Quote from: Dave-S on Dec 20, 2022, 04:32 PMtrastikata Have revised the code as suggested, is this now correct?
Yes I get the "01030002000265CB" sent including EOM % but if I remove the two lines,

HRSOut "MESSAGE IN BUFFER",13,10
HRSOut "BYTES IN BUFFER = ", Dec RXPNTR,13,10

from the MainLoop I get NO Interrupt.

I think if no HW USART command has been used in your code, the compiler will not set the baud rate, although you have declared it but I have to check it. In my code whenever I use HW USART I tend to set all related registers myself.

Use the table on page 516 in the datasheet to set-up the baud rate related registers correctly.

Edit:

I just checked the assembler code, if no HW USART command has been used, the PPS registers related to USART are not set, so you will have to set them yourself or simply include a HW USART command in your code somewhere outside the main program code just to enable the PPS routines in Positron.

top204

#19
The post I sent earlier in this thread has the full TX and RX using interrupt buffering for the 18FxxK40 devices, as an include file library.

As trastikata stated, the compiler will not setup the Baud rate or PPS for a USART if its HRSout, HSerout, HRSin, or HSerin commands are not placed in the code listing for a particular USART used. i.e. HRsout, HRsin, HRSout2 or HRSin3 etc... This saves code space and allows a user to add their own setups if they are not using the compiler's built-in commands.

The library include file I posted earlier in the thread replaces the compiler USART commands and buffers both transmitted and received data invisibly to the user. It also has error checking for the RX and clears the buffer and the error flags.