I'm writing a program for a programmable thermostat via radio that can interface to my home automation system.
I use a PIC16F1847 with a 32 MHz internal clock.
I found problems using the interrupt on the serial port.
I use both the i2c bus and the serial port and I had to re-program the pins for this function.
Not using the interrupt the reading and writing do not give any problem.
Instead, using the interrupt, it seems that the program just crashes on this interrupt routine and no longer goes out.
I wrote a small piece of code to perform functional tests.
The LED inserted in the interrupt routine flashes when a character is received, but the control does not return to the main.
Probably I'm wrong in something ...
I enclose the test program
' $formattagcb
'
' Test program for read interrupt on the serial port.
#option explicit
#Chip 16F1847, 32
#Config OSC = INT, MCLR_OFF ', PLLEN_ON
#Include <DS3231.H>
ConfigPins
'
' ---------------------------------------------------------------
' Preparazione degli interrupts
' ---------------------------------------------------------------
' ---> Timer1 non più usato NOT USED NOW
' On Interrupt Timer1Overflow Call INT_Tmr1Overflowed
' -
' ---> Arrivo dati sulla porta seriale
On Interrupt UsartRX1Ready Call INT_Serial
' -
' ---> Interrupt on portB.0. One second pulse
' INTEDG= Interrupt Edge Select bit
' 1 = Interrupt on rising edge of INT pin
' 0 = Interrupt on falling edge of INT pin
INTEDG = 1
INTCON.3 = 1 ' IOCE(3) not defined. Abilita Interrupt
' Enable portb.0 as the source of the interrupt.
' See the datasheet for more information.
IOCBP.IOCBP0 = 1
' On Interrupt PORTBChange Call INT_UnSecondo
#Define USART_BAUD_RATE 2400
#Define USART_TX_BLOCKING
' #Define USART_DELAY 5 ms
' #Define USART_BLOCKING
' Define I2C settings SOFTWARE
' #Define I2CMODE Master
' #Define I2C_BAUD_RATE 400
' #Define I2C_DATA PORTB.1
' #Define I2C_CLOCK PORTB.4
' #Define I2C_DISABLE_INTERRUPTS On
' OK values ??for the DS3231.
' If missing values, the reading stops responding.
' #Define I2C_BIT_DELAY 20 us ' width of Data Bit On SDA
' #Define I2C_CLOCK_DELAY 10 us ' width of clock pulse On SCL
' #Define I2C_END_DELAY 10 us ' interval between clock pulses
' Define I2C settings
#Define HI2C_BAUD_RATE 400
#Define HI2C_DATA PORTB.1
#Define HI2C_CLOCK PORTB.4
' I2C pins need to be input for SSP module when used on Microchip PIC device
Dir HI2C_DATA In
Dir HI2C_CLOCK In
' MASTER MODE
HI2CMode Master
' LCD I2C
#Define LCD_IO 10 ' This is required!
#Define LCD_I2C_ADDRESS_1 0x4e ' Default = 0x4e
#Define LCD_SPEED FAST ' Defaults is FAST
#Define LCD_BACKLIGHT_ON_STATE 1 ' type 10 LCD
#Define LCD_BACKLIGHT_OFF_STATE 0 ' type 10 LCD
' Altri pins
#Define PIN_TASTIERA PORTA.0 ' AN0 Tastiera 6 tasti
#Define P_TEMP_ARIA AN6 ' PORTB.7 ' AN6 Sensore lettura temperatura Aria
#Define P_TEMP_ACQUA AN5 ' PORTB.6 ' AN5 Sensore lettura temperatura Acqua
#Define P_RELE LATB.3 ' Relè On/Off fancoil
#Define LED_TASTIERA LATA.2 ' Led sulla tastiera
#Define BUZZER PORTA.4 ' BUZZER attivo
#Define SOUNDOUT BUZZER
' Relè di utilizzo vario comandati via radio
#Define RL1 LATA.1 ' Primo relè general purpose
#Define RL2 LATA.6 ' Secondo relè general purpose
#Define HC12_SET_PIN LATA.7 ' Pin per il settaggio dell'HC12
Dim Tmp As Byte
Dim Cnt As Byte
Dim Ora As Byte
Dim Minuti As Byte
Dim Secondi As Byte
Dim MOra As Byte
Dim MMinuti As Byte
Dim bLedOn As Bit
Dim bSerial As Bit
Dim bOneSecond As Bit
' ===============================================================
' Direzione out delle porte relative al led e ai relè.
' Non serve ma necessario perchè altrimenti il
' compilatora da un errore.
' ---------------------------------------------------------------
Dir PORTA.1 Out ' RL1
Dir PORTA.2 Out ' LED
Dir PORTA.4 Out ' BUZZER
Dir PORTA.6 Out ' RL2
Dir PORTA.7 Out ' HC_12 Set pin
Dir PORTA.3 In ' VRef
Dir PORTB.0 In ' 1Hz dal DS3231
Dir PORTB.6 In ' T. Acqua
Dir PORTB.7 In ' T. Aria
' ---------------------------------------------------------------
' Imposta gli ingressi
Dir PIN_TASTIERA In
Dir P_TEMP_ARIA In
Dir P_TEMP_ACQUA In
' Pin porta seriale
Dir PORTB.5 Out
Dir PORTB.2 In
main:
IntOn
Do ForEver
If bSerial Then
bSerial = FALSE
HSerSend Tmp
Else
IncCnt
End If
Loop
Sub IncCnt
Cnt ++
HSerPrint "Cnt="
HSerPrint Cnt
HSerSend 13
HSerSend 10
Wait 200 ms
End Sub
Sub INT_Serial
If PIR1.RCIF Then
Tmp = HSerReceive
If LED_TASTIERA Then
LED_TASTIERA = FALSE
Else
LED_TASTIERA = TRUE
End If
bSerial = TRUE
PIR1.RCIF = 0
End If
End Sub
' ===============================================================
' Serial port and I2C port configuration
' Uscite così configurate:
' RB1 --> SDA1
' RB2 --> RX usart
' RB4 --> SCL1
' RB5 --> TX usart
' ---------------------------------------------------------------
Sub ConfigPins
APFCON0.SDO1SEL = 1 ' 0 = SDO1 Function is On RB2 , 1 = SDO1 Function is On RA6
APFCON0.SS1SEL = 1 ' 1 = SS1 Function is On RA5
APFCON0.RXDTSEL = 1 ' 1 = RX/DT Function is On RB2
APFCON1.TXCKSEL = 1 ' RB5 As TX UART
BAUDCON.WUE = 1 ' Wake-up Enable Bit 0 = Receiver is operating normally
CPSCON0 = 0 ' CAPACTIVE SENSE Module Off
End Sub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I am looking why The serial interrupt don't return from the receive sub, but i haven't found it yet.
One problem is :
PIR1.RCIF = 0
" The RCIF interrupt flag bit is read-only, it cannot be set or cleared
by software." off of the Data Sheet. Please remove the "PIR1.RCIF = 0".
On Interrupt UsartRX1Ready Call INT_Serial
looks right. "UsartRX1Ready" is defined in the PIC16F1847.dat file and the compiler must set the RCIE to enable it and check the RCIF to trip the interrupt.
Do you really need the
If PIR1.RCIF Then
if you already were sent here to get a byte from the RCREG ?
And actually the HSerReceive does one more checking of the RCIF even though it is disguissed as USARTHasData. So please remove the " If PIR1.RCIF Then... End If"
If USARTHasData Then
SerData = RCREG
End if
Could you try changing
Tmp = HSerReceive
to
Tmp = HSerReceive1
?
Every now and again we have trouble with compiler not remembering the default is Comport =1.
I don't have a 16F1847 to try this on .
I'll see if anything else pops into mind.
BR
Mike
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks for the advices
Tomorrow, when I return home, I will try to make the changes recommended by you.
The code I entered is only part of a more complex program that also uses an RTC and a display connected in I2C mode.
The routinte INT_UnSecondo (here not used) serves to have a clock every second and this impulse is given by the DS3231
This part of the program inserted in the forum, however, works and the above mentioned problems occur.
Sub INT_Serial_OK
Tmp = HSerReceive
HSerSend Tmp
End Sub
This routine works perfectly, but never goes out and the control does not return me to the 'main'.
The information arriving from the serial port, not cyclically, must be processed in order to decide which operations to perform, therefore, if the control does not return to the 'main', commands received can not be performed.
Thanks again.
Giacomo
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
@mmote:
No way !
I made the changes you suggested but practically nothing has changed.
I'm starting to think it's a problem due to RX redirection from RB1 to RB2 so I can use the I2C hardware module.
Does anyone have any ideas?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
ok,no idea what the prog does but
"I wrote a small piece of code to perform functional tests.
The LED inserted in the interrupt routine flashes when a character is received, but the control does not return to the main.
Probably I'm wrong in something ..."
Does not return to the main...where's it go then?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
IntOn
Do ForEver
If bSerial Then
bSerial = FALSE
HSerSend Tmp
Else
IncCnt
End If
Loop
So if the control returns to the main and the 'bSerial' flag is set in the interrupt routine, the 'Tmp' value must be transmitted from the serial to the terminal. This does not happen.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The sub 'IncCnt' only serves to have a visual indication that the main loop is running.
It seems that the interrupt routine takes over even before the interrupt condition occurs.
I tried to insert an 'HSerPrint "HELLO!"' Statement before the loop and this instruction is not executed.
Actually I can not understand anything.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I had probs with 2 interrupts so turned 1 off and then on after something like pulsin. Could be like interrupt at wrong time..dunno. I fake stuff when de bugging ie simulate event.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This is the problem I encountered and I can not answer.
When the data is received from the serial port, the interrupt routine is called up correctly.
If I read the data inside the routine it ends correctly, but if I set the flag for a following reading outside of the routine it does not end and remains locked.
Unless you read the serial port the Interrupt flag is still set, so when you leave the Interrupt Routine it immediately retriggers the interrupt, and the outward appearance is that the program has hung, when it is actually just stuck in a loop.
Cheers
Chris
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
In fact I thought about it too, but PIR1.RCIF is read only, so it is not possible to reset it ...
I solved by reading only the first character from the interrupt routine and then following the reading elsewhere by checking in a loop PIR1.RCIF and, if set, reading with HSerReceive.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Great Cow Basic PIC16F1847 UART code examples are hard to find but the above thread proved closest. The code below is adapted from that above and echoes characters back to the terminal.
We did not find RCIF needed checking in the main loop, as suggested immediately above, as the interrupt seems to work as intended. Improvements are most welcome ;-)
Compiler version used was Great Cow BASIC (0.98.<<>> 2021-<<>>-24 (Linux 64 bit) : Build 1005).
Use on command line: $ gcbasic /A:GCASM PIC16F1847uartJackJames.gcb
The PIC was programmed using a PICkit3 and MPLAB IPE v6.00
' Test program for read interrupt on the serial port using UART on PIC16F1847.'Adapted from https://sourceforge.net/p/gcbasic/discussion/579126/thread/88f6e6de/'to include suggestions.'Type in a character, it is incremented and echoed back to the terminal. e.g. a returns b etc'The LED toggles on every character input. 'The LCD is not doing much but kept as in the original, it may be useful if nothing appears on the terminal.'DS41453B http://ww1.microchip.com/downloads/en/devicedoc/41453b.pdf PIC16F1847 manual' Note: UART output here is to a MAX483 hence SCKP is set for TX and a transistor inverts received'serial from the MAX483. Both inverts likely not needed if a MAX232 was used instead.'The MAX483 is connected via twisted pair to a RS-485/USB convertor then into a PC terminal e.g. CuteCom#option explicit#Chip 16F1847, 8 'MHz#Config OSC = INT, MCLR_OFF'#Include <DS3231.H> 'Cannotfind/opt/GCBASIC/include//DS3231.H'#Include "/opt/GCBASIC/include/ds3231.h" 'ThisworkedbutnotneededConfigPins' ---------------------------------------------------------------' Preparazione degli interrupts' ---------------------------------------------------------------' ---> Arrivo dati sulla porta serialeOnInterruptUsartRX1ReadyCallINT_Serial#Define USART_BAUD_RATE 9600 'was 2400#Define USART_TX_BLOCKING;LCDI2C#Define LCD_IO 10 ' This is required!#Define LCD_I2C_ADDRESS_1 0x4e ' Default = 0x4e#Define LCD_BACKLIGHT_ON_STATE 1 ' type 10 LCD#Define LCD_BACKLIGHT_OFF_STATE 0 ' type 10 LCD;-----DefineHardwaresettingsimported' Define I2C settings - CHANGE PORTS#define I2C_MODE Master#define I2C_DATA PORTB.1 'SDA#define I2C_CLOCK PORTB.4 'SCL#define I2C_DISABLE_INTERRUPTS ON'Optionally, you can reduce the I2C timings.#define I2C_BIT_DELAY 0 us#define I2C_CLOCK_DELAY 1 us#define I2C_END_DELAY 0 us#Define LED_TASTIERA LATA.0 ' was LATA.2 Led sulla tastiera, was on PortA.2'http://ww1.microchip.com/downloads/en/devicedoc/41453b.pdf DS41453B-page 300 SCKP=1'Asynchronous mode, Transmit inverted data to the TX/CK pin DimTmpAsByteDimCntAsByteDimbSerialAsBitDirPORTA.0Out' LED LED_TASTIERA was PORTA.2'Dir PORTB.5 Out 'TX(notneededhere,seeSPEN)DirPORTB.2In'RX'DS41453B-page 291 TX and DS41453B-page 296 RX (NB GCB attends to the six below)'TXSTA.SYNC = 0 'Asyncmode'RCSTA.SPEN = 1 'EnabletheserialportandautomaticallyconfigurestheTX/CKI/Opinasanoutput'TXSTA.TXEN = 1 'Transmitenable'PIE1.RCIE = 1 'ForRXinterrupt'INTCON.GIE = 1 'ForRXinterrupt'INTCON.PEIE = 1 'ForRXinterrupt;Belowif1enablesMAX483#Define MAX483ENABL PORTb.3DirMAX483ENABLOutmain:CLSLCDBacklightONPrint"Hi LCD"MAX483ENABL=1;EnableMAX483TXHSerPrint"Hello PIC16F1847 UART"HSerSend13HSerSend10MAX483ENABL=0;DisableMAX483TXonstartupbSerial=FALSE;initialiseIntOnDoForEverIfRCSTA.OERR=1then'Receive Overrun ErrorRCSTA.SPEN=0'DS41453B-page 295EndIfIfbSerialThenbSerial=FALSEMAX483ENABL=1;EnableMAX483TXHSerSendTmp+1'Send a from PC get b echoed back etcMAX483ENABL=0;DisableMAX483TXEndIf'Wait 200 ms 'slowsoutputdownasIncCntdidLoopSubINT_SerialTmp=HSerReceive1'mmotte adviceLED_TASTIERA=!LED_TASTIERA'Toggle LED statebSerial=TRUE'Tell main a character came in EndSub' =============================================' Serial port and I2C port configuration' Uscite così configurate:' RB1 --> SDA1' RB2 --> RX usart' RB4 --> SCL1' RB5 --> TX usart' ----------------------------------------------SubConfigPinsAPFCON0.RXDTSEL=1' 1 = RX/DT Function is On RB2APFCON1.TXCKSEL=1' RB5 As TX UARTBAUDCON.WUE=1' Wake-up Enable Bit 0 = Receiver is operating normally see DS41453B-page 300CPSCON0=0' CAPACTIVE SENSE Module OffEndSub
Last edit: Jon Nelson 2022-06-18
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Nice program - thank you for posting. I will publish as a demo - all credit to you.
Feedback.
#CONFIG OSC = INT, MCLR_OFF not needed as the compiler has these as the defaults. See PICINFO for the config defaults for all chips. ConfigPins the registers are not required, As Great Cow BASIC uses a unique identifier for every register / register.bit therefore the register suffix is not required.
I'm writing a program for a programmable thermostat via radio that can interface to my home automation system.
I use a PIC16F1847 with a 32 MHz internal clock.
I found problems using the interrupt on the serial port.
I use both the i2c bus and the serial port and I had to re-program the pins for this function.
Not using the interrupt the reading and writing do not give any problem.
Instead, using the interrupt, it seems that the program just crashes on this interrupt routine and no longer goes out.
I wrote a small piece of code to perform functional tests.
The LED inserted in the interrupt routine flashes when a character is received, but the control does not return to the main.
Probably I'm wrong in something ...
I enclose the test program
where's On Interrupt PORTBChange Call INT_UnSecondo if that's the prob? I cannot see the interrupt sub.
I am looking why The serial interrupt don't return from the receive sub, but i haven't found it yet.
One problem is :
" The RCIF interrupt flag bit is read-only, it cannot be set or cleared
by software." off of the Data Sheet. Please remove the "PIR1.RCIF = 0".
looks right. "UsartRX1Ready" is defined in the PIC16F1847.dat file and the compiler must set the RCIE to enable it and check the RCIF to trip the interrupt.
Do you really need the
if you already were sent here to get a byte from the RCREG ?
And actually the HSerReceive does one more checking of the RCIF even though it is disguissed as USARTHasData. So please remove the " If PIR1.RCIF Then... End If"
Could you try changing
Tmp = HSerReceive
to
Tmp = HSerReceive1
?
Every now and again we have trouble with compiler not remembering the default is Comport =1.
I don't have a 16F1847 to try this on .
I'll see if anything else pops into mind.
BR
Mike
Thanks for the advices
Tomorrow, when I return home, I will try to make the changes recommended by you.
The code I entered is only part of a more complex program that also uses an RTC and a display connected in I2C mode.
The routinte INT_UnSecondo (here not used) serves to have a clock every second and this impulse is given by the DS3231
This part of the program inserted in the forum, however, works and the above mentioned problems occur.
Sub INT_Serial_OK
Tmp = HSerReceive
HSerSend Tmp
End Sub
This routine works perfectly, but never goes out and the control does not return me to the 'main'.
The information arriving from the serial port, not cyclically, must be processed in order to decide which operations to perform, therefore, if the control does not return to the 'main', commands received can not be performed.
Thanks again.
Giacomo
@mmote:
No way !
I made the changes you suggested but practically nothing has changed.
I'm starting to think it's a problem due to RX redirection from RB1 to RB2 so I can use the I2C hardware module.
Does anyone have any ideas?
ok,no idea what the prog does but
"I wrote a small piece of code to perform functional tests.
The LED inserted in the interrupt routine flashes when a character is received, but the control does not return to the main.
Probably I'm wrong in something ..."
Does not return to the main...where's it go then?
Here is the main:
So if the control returns to the main and the 'bSerial' flag is set in the interrupt routine, the 'Tmp' value must be transmitted from the serial to the terminal. This does not happen.
Do interrupts,seems 2 cause probs?
Is an interrupt re happening?
sorry,just a thought. and re mappable 16fxx is new to me
The sub 'IncCnt' only serves to have a visual indication that the main loop is running.
It seems that the interrupt routine takes over even before the interrupt condition occurs.
I tried to insert an 'HSerPrint "HELLO!"' Statement before the loop and this instruction is not executed.
Actually I can not understand anything.
I had probs with 2 interrupts so turned 1 off and then on after something like pulsin. Could be like interrupt at wrong time..dunno. I fake stuff when de bugging ie simulate event.
This weekend I have some free time and I think I'll play a bit.
I also checked the assembler source but it seems all right.
This is the problem I encountered and I can not answer.
When the data is received from the serial port, the interrupt routine is called up correctly.
If I read the data inside the routine it ends correctly, but if I set the flag for a following reading outside of the routine it does not end and remains locked.
Unless you read the serial port the Interrupt flag is still set, so when you leave the Interrupt Routine it immediately retriggers the interrupt, and the outward appearance is that the program has hung, when it is actually just stuck in a loop.
Cheers
Chris
In fact I thought about it too, but PIR1.RCIF is read only, so it is not possible to reset it ...
I solved by reading only the first character from the interrupt routine and then following the reading elsewhere by checking in a loop PIR1.RCIF and, if set, reading with HSerReceive.
Great Cow Basic PIC16F1847 UART code examples are hard to find but the above thread proved closest. The code below is adapted from that above and echoes characters back to the terminal.
We did not find RCIF needed checking in the main loop, as suggested immediately above, as the interrupt seems to work as intended. Improvements are most welcome ;-)
Compiler version used was Great Cow BASIC (0.98.<<>> 2021-<<>>-24 (Linux 64 bit) : Build 1005).
Use on command line: $ gcbasic /A:GCASM PIC16F1847uartJackJames.gcb
The PIC was programmed using a PICkit3 and MPLAB IPE v6.00
Last edit: Jon Nelson 2022-06-18
Nice program - thank you for posting. I will publish as a demo - all credit to you.
Feedback.
#CONFIG OSC = INT, MCLR_OFF
not needed as the compiler has these as the defaults. See PICINFO for the config defaults for all chips.ConfigPins
the registers are not required, As Great Cow BASIC uses a unique identifier for every register / register.bit therefore the register suffix is not required.See you demo here. https://github.com/GreatCowBASIC/Demonstration_Sources/blob/main/Interrupt_and_Timer_Solutions/Interrupt_Serial_examples/PIC16F1847_UART.gcb You can login into GitHub and edit online if you want to update/change.
Thank you,
Last edit: Anobium 2022-06-20