Log in

View Full Version : 18F2580 with strange behaviour when using Hserin and RX interrupt



PaulMaker
- 15th February 2026, 16:48
Hi guys,

I'm facing a weird behaviour with my 18F2580 using Hserin and RX interrupts and I was hoping someone could help.


I'm trying to run a code that when an incoming 2 characters is received, it triggers the interrupt and reads the message.
Once it reads the message, it goes back the the main routine.

The issue is that, once it is turned on, it does not show the correct characters being sent.
However, the interrupt trigger is being done and once it reads the message, goes back to the main routine.

But if I send a long message, from that point on, it will show the correct characters being sent but no longer goes back to the main routine!

Not sure why it does not show the correct message in the first place and also, can't understand why it fails to jump from the interrupt routine back to the main routine!

The message is being sent via bluetooth with a BT module connected directly to the MCU.
The TX from the MCU is disabled because i only need to receive and not transmit.

I filmed this behaviour which can be seen in the link below.

This is the code:




'************************************************* ***************
'* Name : IC_3_COMTEST2.PBP *
'* Author : *
'* Notice : Copyright (c) 2024 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 19/12/2024 *
'* Version : 1.0 *
'* Notes : 18F2580 MCU *
'* : *
'************************************************* ***************
'
;----[18F2580 Hardware Configuration]-------------------------------------------
#IF __PROCESSOR__ = "18F2580"
#DEFINE MCU_FOUND 1
#CONFIG
CONFIG OSC = IRCIO67 ; Internal oscillator block, port function on RA6 and RA7
CONFIG FCMEN = ON ; Fail-Safe Clock Monitor ENABLED
CONFIG IESO = OFF ; Oscillator Switchover mode disabled
CONFIG PWRT = OFF ; PWRT disabled
CONFIG BOREN = OFF ; Brown-out Reset disabled in hardware and software
CONFIG BORV = 3 ; VBOR set to 2.1V
CONFIG WDT = ON ; WDT ENABLED (control is placed on the SWDTEN bit)
CONFIG WDTPS = 512 ; 1:512
CONFIG PBADEN = OFF ; PORTB<4:0> pins are configured as digital I/O on Reset
CONFIG LPT1OSC = OFF ; Timer1 configured for higher power operation
CONFIG MCLRE = OFF ; RE3 input pin enabled; MCLR disabled
CONFIG STVREN = OFF ; Stack full/underflow will NOT cause Reset
CONFIG LVP = OFF ; Single-Supply ICSP disabled
CONFIG BBSIZ = 1024 ; 1K words (2K bytes) boot block
CONFIG XINST = OFF ; Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
CONFIG DEBUG = OFF ; Background debugger disabled, RB6 and RB7 configured as general purpose I/O pins
CONFIG CP0 = OFF ; Block 0 (000800-001FFFh) not code-protected
CONFIG CP1 = OFF ; Block 1 (002000-003FFFh) not code-protected
CONFIG CP2 = OFF ; Block 2 (004000-005FFFh) not code-protected
CONFIG CP3 = OFF ; Block 3 (006000-007FFFh) not code-protected
CONFIG CPB = OFF ; Boot block (000000-0007FFh) not code-protected
CONFIG CPD = OFF ; Data EEPROM not code-protected
CONFIG WRT0 = OFF ; Block 0 (000800-001FFFh) not write-protected
CONFIG WRT1 = OFF ; Block 1 (002000-003FFFh) not write-protected
CONFIG WRT2 = OFF ; Block 2 (004000-005FFFh) not write-protected
CONFIG WRT3 = OFF ; Block 3 (006000-007FFFh) not write-protected
CONFIG WRTC = OFF ; Configuration registers (300000-3000FFh) not write-protected
CONFIG WRTB = OFF ; Boot block (000000-0007FFh) not write-protected
CONFIG WRTD = OFF ; Data EEPROM not write-protected
CONFIG EBTR0 = OFF ; Block 0 (000800-001FFFh) not protected from table reads executed in other blocks
CONFIG EBTR1 = OFF ; Block 1 (002000-003FFFh) not protected from table reads executed in other blocks
CONFIG EBTR2 = OFF ; Block 2 (004000-005FFFh) not protected from table reads executed in other blocks
CONFIG EBTR3 = OFF ; Block 3 (006000-007FFFh) not protected from table reads executed in other blocks
CONFIG EBTRB = OFF ; Boot block (000000-0007FFh) not protected from table reads executed in other blocks
#ENDCONFIG


#ENDIF


;----[Verify Configs have been specified for Selected Processor]----------------
; Note: Only include this routine once, after all #CONFIG blocks
#IFNDEF MCU_FOUND
#ERROR "No CONFIGs found for [" + __PROCESSOR__ +"]"
#ENDIF


'************************************************* ****************************


OSCCON =%01110010 '8MHz INTOSC
OSCTUNE=%01000000 '


DEFINE OSC 8


'************************************************* ****************************


INCLUDE "ALLDIGITAL.pbp"
DEFINE SHOWDIGITAL 1


'************************************************* ****************************


Define HSER_BAUD 9600
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
'DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_SPBRG 12 '
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
'DEFINE HSER_CLEAR = On




RXBYTE VAR BYTE
RXFLAG VAR BIT
RX1 VAR BYTE
RX2 VAR BYTE
RX3 VAR BYTE
RX4 VAR BYTE
RX5 VAR BYTE
RX6 VAR BYTE




CT VAR BYTE
CT2 VAR BYTE


INTFLAG VAR BYTE
MOODCHANGE VAR WORD


'PIE1.5 = 1 ' RCIE
INTCON = %11000000 ' GIE + PEIE


'************************************************* ****************************


PORTA=%00000000
PORTB=%00000000
PORTC=%00000000


TRISA=%00000000
TRISB=%00000000
TRISC=%10000000 'RC7 - RX pin as input


'************************************************* ****************************
'PORTS & PINS


A0 VAR PORTA.0 '
A1 VAR PORTA.1 '
A2 VAR PORTA.2 '
A3 VAR PORTA.3 '
A4 VAR PORTA.4 '
A5 VAR PORTA.5 '
A6 VAR PORTA.6 '
LED1 VAR PORTA.7 '


B0 VAR PORTB.0 '
B1 VAR PORTB.1 '
B2 VAR PORTB.2 '
B3 VAR PORTB.3 '
LED2 VAR PORTB.4 '
B5 VAR PORTB.5 '
B6 VAR PORTB.6 '
B7 VAR PORTB.7 '


C0 VAR PORTC.0 '
C1 VAR PORTC.1 '
C2 VAR PORTC.2 '
C3 VAR PORTC.3 '
C4 VAR PORTC.4 '
C5 VAR PORTC.5 '
IC_TX VAR PORTC.6 'TX HARDWARE PIN / Not Used as TX
IC_RX VAR PORTC.7 'RX HARDWARE PIN


INCLUDE "modedefs.bas"


'[DISPLAY SETTINGS]************************************************** ***************************


char var byte
x var byte
y var byte
BUFF VAR BYTE[16]


;use this define for hw i2c
'#define hwi2c 1


;set and uncomment these to use softi2c
SCL var PortA.6 ' I2C Clock
SDA var PortC.0 ' I2C Data


;set these to match display
ssdheight con 3 ; 7 = 8 PAGES 64*128 , 3 = 4 pages 32*128
ssdwidth con 127 ; 128 PIXELS WIDE
sdd1306_addr con $78
Include "ssd1306_I2C.INC" ' bring it in
include "font7x5_18.bas"


'[INTERRUPT SETTINGS]************************************************** ***************************




INCLUDE "DT_INTS-18.bas"
INCLUDE "ReEnterPBP-18.bas"


ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _RxISR, PBP, yes
ENDM
INT_CREATE
INT_ENABLE RX_INT ;enables external (INT) interrupts
ENDASM


'************************************************* ****************************


'wsave var byte $20 system ;location for W if in bank0
'wsave var byte $70 system ;location for W if in bank0
'..... If any of these next three lines cause an error ...Comment them out to fix the problem...
'............which variables are needed, depends on the chip you are using.......
wsave1 var byte $A0 system ;location for W if in bank0
wsave2 var byte $120 system ;location for W if in bank0
wsave3 var byte $1A0 system ;location for W if in bank0

'[INIT]************************************************** ***************************


INIT:


clear


PORTB=%00000000


BIG_TEXT = 0


PAUSE 1000


high led1
high led2
pause 500
low led1
low led2


PAUSE 500


gosub glcd_init
GLCD_CLR
ARRAYWRITE BUFF,["INIT OK",0]
GLCDSTR 0,0,BUFF


PAUSE 500


goto main


'[MAIN ROUTINE]************************************************** ***************************


main:


gosub glcd_init
GLCD_CLR
ARRAYWRITE BUFF,["WAITING",0]
GLCDSTR 0,0,BUFF


toggle LED1


pause 1000


gosub calculat


goto main


'[INTERRUPT ROUTINE]************************************************** ***************************


RxISR:




HSERIN [RX1, RX2, RX3, rx4]


'ASCII TO DECIMAL CONVERSION
rx1 = (rx3 - "0") * 10
rx1 = rx1 + (rx4 - "0")


gosub glcd_init
GLCD_CLR
ARRAYWRITE BUFF,["RX1= ", dec RX1,0]
GLCDSTR 0,0,BUFF


PAUSE 1000


@ INT_RETURN


'[CONFIRMATION ROUTINE]************************************************** ***************************


calculat:




if RX1=57 then


gosub glcd_init
GLCD_CLR
ARRAYWRITE BUFF,["GOOD DATA RECEIVED",0]
GLCDSTR 0,0,BUFF


PAUSE 500
high led2
PAUSE 5000
LOW led2


endif




return


'************************************************* ****************************
end



Link for the video showing how it behaves:
https://www.canva.com/design/DAHBZ6VgQfI/pRHYJ7z5Ci2NSus0BYBpFg/edit?utm_content=DAHBZ6VgQfI&utm_campaign=designshare&utm_medium=link2&utm_source=sharebutton

Thanks in advance for any tips on how to get this code working as it is supposed to.

richard
- 16th February 2026, 00:16
I'm trying to run a code that when an incoming 2 characters is received, it triggers the interrupt and reads the message.

yet your rx routine wants 4 chars


HSERIN [RX1, RX2, RX3, rx4]


what is the actual msg you receive [in ascii chrs] is there a start chr how does the msg terminate /n, /CR, /LF?

PaulMaker
- 16th February 2026, 13:11
Hi Richard,

thanks for the help.

According to the information on the display (when set to show the 4 incoming characters), 2 initial characters are being sent as carriage return (10 and 13) from the terminal.
That is why it's capturing 4 but i only use the last 2.

HenrikOlsson
- 16th February 2026, 17:41
Random ramblings and guesses here, take for what it is:


I'm trying to run a code that when an incoming 2 characters is received, it triggers the interrupt and reads the message.
That's not how it works. The ISR triggers when there's a byte is received. You can't configure it to fire after n character (short of setting up DMA and using that perhaps).

Typically, you'd write the interrupt to receive one byte at a time, putting them into a buffer (array) while looking for some sort of qualifier for "end of message" (number of characters, time-out, certain byte sequence, whatever). Once that qualifer is met you set a flag signaling the main rotuine that data is available. LCD updates etc is handled outside of the ISR.

You say that whatever sends the data sends 10,13 first, then two bytes of interest but you're not looking for the 10,13 sequence in order to "sync" and since you have a lot of slow code in the ISR it might get out of sync and therefor get stuck in the ISR since, once the interrupt fires your code expects 4 bytes.

If it gets 3 it'll sit there waiting for the 4th. Then a new burst of 4 bytes comes a long, where the first one counts as the 4th. Then the code moves on to to update the display while remaining three incoming bytes overflows the UART buffer because you're updating the display and/or executing a massive PAUSE in the ISR.

/Henrik.

richard
- 16th February 2026, 22:52
another issue




OSCCON =% 01110010 '8MHz INTOSC OSCTUNE=% 01000000 '




DEFINE OSC 8


will enable the PLL making OSC 32MHz

making the eusart defines incorrect

and

the oled display should only be initialised once
and you dont need to clear the entire screen for every write , just clear the area that needs to be updated
eg GLCD_CLR 0,1,127,8 ; clear a full width text line

PaulMaker
- 17th February 2026, 12:45
Greetings HenrikOlsson and Richard,

thank you so much for your help.

I will make a few changes and run some tests to see if I get it running correctly.

@Richard, regarding the osc settings, yes, you are correct,however, if I change to Define Osc 32 the code will run slower (tested before with pause 1000 and led blink). Weird things happen with this 18F2580 MCU :biggrin:

richard
- 17th February 2026, 22:23
if I change to Define Osc 32 the code will run slower (tested before with pause 1000 and led blink). Weird things happen with this 18F2580 MCU

pll only works with primary clock sources , if you set the int-osc as primary clock then it works as expected


DEFINE OSC 32


OSCCON =% 01110000 '8MHz INTOSC
OSCTUNE=% 01000000 '

PaulMaker
- 22nd February 2026, 13:51
Hi Richard,

you are correct (as always)!
I thought we had to choose internal insteal of primary since it's set to an internal osc.