Hi Darrel:
Thanks ... I reloaded the files and now it works...
Ruben de la Pena V.
Hi Darrel:
Thanks ... I reloaded the files and now it works...
Ruben de la Pena V.
1st off wish to thank Darrel for a very useful routine. Now my issue. It seems when in a WHILE loop or a REPEAT..UNTIL look the interrupts are no longer detected. I am using the UART interrupts and they work flawlessly until I call a subroutine which has the WHILE loop and can't get out of it. I have a command protocol where I send a START command via serial which will call the looping program. I stop the loop by sending a STOP command. I minimized the routine to have only the loop and not the code within the loop to simply the trouble shooting. Below the code snippets.
The uart interrupt entry routine reduced to just the command of interest.
SERIALINT:
HSERIN [COMMAND,DEC1 MODE,DEC5 IODATA]
SELECT CASE COMMAND
CASE "N" 'Control scan position and start/stop PIEZO1
MOTORADDR = PIEZO1
SELECT CASE MODE
CASE STARTPOS 'READ START POS DATA 16-BITS
PIEZO1START = IODATA
CASE ENDPOS 'READ END POS DATA 16-BITS
PIEZO1END = IODATA
CASE STARTSCAN 'START SCANNING
SCAN = TRUE
HSEROUT ["START",13,10] '0-65535
CASE STOPSCAN 'STOP SCANNING
SCAN = FALSE
HSEROUT ["STOP",13,10] '0-65535
END SELECT
GOSUB BEGINSCAN
END SELECT
@ INT_RETURN
The subroutine being called below. When I send the start command it enters the routine fine but sending another command to stop it never enters the interrupt handler.
debugging lines to transmit START or STOP in the handler. START is sent to the terminal but STOP doesn't which shows it doesn't recognize another interrupt. Without the WHILE
loop, works fine. I commented the main code to make it as simple as possible
BEGINSCAN: 'START SCANNING PIEZO1
IF (PIEZO1END - PIEZO1START) < 1000 THEN
SCANSTEP = 1
ELSE
SCANSTEP = (PIEZO1END - PIEZO1START)/1000 'LIMIT TO 1000 STEPS
ENDIF
'
WHILE SCAN = TRUE
' SCANINDEX = PIEZO1START
' ARRAYCOUNT = 0
' WHILE SCANINDEX <= PIEZO1END
' PIEZO1POS = SCANINDEX
' GOSUB SETPIEZO
' PDSELECT = pd1 'CONVERT PD1 DATA AND STORE IN ARRAY
' GOSUB READPD
' PD1ARRAY[ARRAYCOUNT] = PD1DATA
' SCANINDEX = SCANINDEX + SCANSTEP
' ARRAYCOUNT = ARRAYCOUNT + 1
' WEND
'GOSUB SENDARRAY 'SEND SAVED DATA TO PC
WEND
RETURN
Is there something about WHILE or REPEATS that doesn't allow interrupts? I also put a 1 ms pause in the loop and same problem.
You'll need to post ALL the code before folks can help I think, since the problem is not necessarily in this little bit. The "@ INT_RETURN" suggests these are the actual interrupt routines? One thing to be cautious about is that interrupts can occur while you are in your handler routine, causing the routine to restart and all sorts of other strange problems. Your interrupt routine should be as fast as possible - usually only a flag is set, that your main program loop can quickly detect and take action on. If you must do a few things in the routine, then you need to disable interrupts while in the routine, and risk missing something.
If you call a subroutine from the Interrupt Handler, you are still in the Interrupt.
Interrupts will not interrupt an interrupt.
The handler must complete and exit before another interrupt can occur.
DT
The entire code is a couple of hundred lines so not practical to post all of it. I stripped it down to the absolute minimum to focus on the handler. I am using the uart interrupt to monitor for a command. If the command is "S" then it will enter the scan subroutine which is just a while loop and print START on the terminal. If when in the loop I send a F it should exit the sub and print "STOP" to the terminal. The start works as it can be seen entering the SCAN subroutine but never exits when I send a stop request. The simplified code here, interrupt handler in red. No timing issues as I am entering the commands via a terminal manually.
Darrel's comment indicates that the scan routine has to complete on its own to exit the interrupt handler, which of course is not possible with the While loop as it is. That means that the Instant Interrupts doesn't support re-entry. I've written interrupt handlers but on large non-pic systems and re-entry is critical to real time OSes but it makes stack management complex. Guess one way to do it is to monitor the receive buffer in the scan loop to look for an exit character. Not as elegant as interrupt re-entry capability but may be my only solution.
Thanks for your feedback.
DEFINE OSC 40 ' 18F6628
@ __CONFIG _CONFIG1H, _OSC_HSPLL_1H
@ __CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_512_2H
;@ __CONFIG _CONFIG3H, _PBADEN_OFF_3H
@ __CONFIG _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L
'
'************** UART Definitions ******************
DEFINE HSER_SPBRG 42 '21=115200 42=57600 4=512000 @40MHz 2=921000
DEFINE HSER_TXSTA 24h '%00100100 brgh high
DEFINE HSER_RCSTA 90h '%10010000
DEFINE HSER_BAUD 57600 '57600 '512000 '115200 '57600
TRISC = %10010000
'*********** Interrupt Definitions & Init ***********
include "DT_INTS-18.bas"
include "ReEnterPBP-18.bas"
'
TRUE CON 1
FALSE CON 0
SCAN VAR BYTE
COMMAND VAR BYTE
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _SERIALINT, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
@ INT_ENABLE RX_INT ; enable external (INT) interrupts
MAIN:
PAUSE 1
GOTO MAIN
BEGINSCAN: 'START SCANNING PIEZO1
HSEROUT ["START",13,10] '0-65535
WHILE SCAN = TRUE
PAUSE 1
WEND
RETURN
SERIALINT:
HSERIN [COMMAND]
IF COMMAND = "S" THEN
SCAN = TRUE
GOSUB BEGINSCAN
ENDIF
IF COMMAND ="F" THEN
SCAN = FALSE
HSEROUT ["STOP",13,10] '0-65535
ENDIF
@ INT_RETURN
I made the following change in the WHILE loop to allow me to exit. As mentioned, I use the receive register and poll it for the command. Does work, just not as elegant as I would prefer. Addition in red.
Code:BEGINSCAN: 'START SCANNING PIEZO1 ' WHILE SCAN = TRUE PAUSE 1 if RCREG1 = "F" THEN SCAN = FALSE RETURN ENDIF WEND RETURN
My comment, and Darrel's comment both said the same thing - it is bad form to put a bunch of code in the interrupt routine. Using a GOSUB essentially puts the bulk of your code inside the routine at compile time.
In order to not get stuck in an interrupt routine forever, typically you would stop servicing interrupts while in the routine. Either you shut them off and risk missing other interrupts, or you set a flag, and exit fast (having only executed a couple instructions). Your main program loop, then checks for the flag and if it is set, executes the GOSUB code. That can be the whole main program loop: (start: -> IF flag=1 THEN GOSUB do_stuff ELSE GOTO start) Then your routine just makes flag = 1 and exits.
There are a number of reasons to not do it the way you are doing - when an interrupt occurs, everything going on in the processor is stuffed into memory and a new program is executed. If a second interrupt happens, then those memory locations get overwritten and your original point in the program is destroyed. It is not practical to allow many levels of saving - if you wish to do that, you'll have to write your own interrupt program. It won't be easy, because of the way the PIC does interrupts, and it is unlikely to be generic, or fast.
But honestly, I have not encountered a situation where it's necessary to do that, and neither have you with the code you posted.
Thanks, your post cleared it up nicely for me. New strategy now as it is a complex program with dozens of subroutines all invoked via a command from the serial port. As I mentioned, most of my interrupt handler experience has been with large scale mini-computers with realtime OSes and interrupt reentry was the norm. See now the pic architecture & picbasic is limited but still doable with the flags mentioned. That code snippet was just one of dozens of similar subroutines.
Thanks for the feedback.
Hi all
Thanks Henrik, Richard and Demon for the response with my problem, it is much appreciated.
It turns out Henrik spotted the problem and it is now sorted. Being lazy I copied and pasted a line for the interrupt enable from the handler line but didn't change from Handler to Enable as Henrik spotted. I then spent a week of evenings trying to find the problem, it is true sometimes you cannot see the wood for the trees.
Thanks again Geoff.
Good Afternoon All-
I have gone through this thread and apologies if this is not the correct place for me to post this question;
I have a home project in which I want to use 2 USARTs for my humble home automation idea. I know that DT's interrupts-18 will handle 2 serial ports and have used it - works quite well and again Kudos to DT!
The chip I want to use is the 16F1527 which looks to be a great choice, capable and cheap!
I see by DT's site that there is no 2nd serial interrupt as in the -18. In looking through DT_INTS-14 I do not see one either.
My question, is there a way (surely?) to add this to DT_INTS-14?
I read a post in where you can add an interrupt on change but I am not experienced enough to see how I might apply this philosophy to the 2nd serial port.
Any advice would be greatly appreciated.
BTW, after reading all 19 pages of this thread, my cap will no longer fit on my head - its swollen <grin>........
Regards to All.
"If we knew what we were doing, it wouldn't be called research"
- Albert Einstein
Hi,
If you have a way of testing the uarts you can try the below, no guarantees
I think if you define the the interupt and related registers, DT's macro will do the rest
for you? Edit DT_INTS-14.bas include file
Existing uart define, from DT_INTS-14.bas version 1.10
Code:#define TX_INT PIR1,TXIF, PIE1,TXIE ;-- USART Transmit #define RX_INT PIR1,RCIF, PIE1,RCIE ;-- USART Receive
Try adding this right below the above (info from page 89 pic16f1527 data sheet)
Code:#define TX1_INT PIR1,TX1IF, PIE1,TX1IE ;-- USART1 Transmit #define RX1_INT PIR1,RC1IF, PIE1,RC1IE ;-- USART1 Receive #define TX2_INT PIR4,TX2IF, PIE4,TX2IE ;-- USART2 Transmit #define RX2_INT PIR4,RC2IF, PIE4,RC2IE ;-- USART2 Receive
have a look at these threads with dt's guidance I added unsupported interrupts to dt_int18
http://support.melabs.com/threads/39...with-pic18f248
http://support.melabs.com/threads/32...TMR4-int-ERROR
Hi,
I think the problem is that you're mixing up the names of the interrupt source and the interrupt handler. The interrupt source is called IC3DRIF_INT - you can't call the interrupt handler that as well. This compiles just fine:/Henrik.Code:Include "DT_INTS-18.pbp" 'Include the interrupt system files. ASM INT_LIST macro ;IntSource Label Type ResetFlag INT_Handler IC3DRIF_INT, _InputSignal, ASM, yes endm INT_CREATE ENDASM @ INT_ENABLE IC3DRIF_INT Main: Toggle PortB.0 Pause 500 Goto Main InputSignal: @ NOP @ INT_RETURN
Bookmarks