Oshonsoft programs with INTERRUPTS and PARSE

sagor

Joined Mar 10, 2019
1,049
No, all interrupts should be handled in sequence. How you set which one you check first is up to you. In my code, I do something like:

if IO Interrupt flag set then
...do IO interrupt code
clear IO interrupt flag
endif

if Timer interrupt flag set then
...do timer code
clear Timer interrupt flag
endif

if PIR1.RXIF = 1 then
...do UART code
end if

exit interrupt routine.

You can also do it by just having multiple "IF" statements at the start of the interrupt routine, and jump to the first one you detect, but I find my method easier, as I check all interrupt flags every time through the interrupt routine. The extra "IF" statements, if nothing is set, adds very little time to the overall interrupt routine.
With a method with multiple IFs at the start of the interrupt routine, one has to eventually branch back to the start to check other flags before exiting, to see if anything else has to be processed.

My method is a straight linear processing method, and the order in which you put the code determines the "priority" in which you process the interrupts (do not confuse with high/low priority interrupt settings). Each of those interrupt routines should be as short as possible. Process the interrupt, set flags or indicators, then exit that routine.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
No, all interrupts should be handled in sequence. How you set which one you check first is up to you. In my code, I do something like:

if IO Interrupt flag set then
...do IO interrupt code
clear IO interrupt flag
endif

if Timer interrupt flag set then
...do timer code
clear Timer interrupt flag
endif

if PIR1.RXIF = 1 then
...do UART code
end if

exit interrupt routine.

You can also do it by just having multiple "IF" statements at the start of the interrupt routine, and jump to the first one you detect, but I find my method easier, as I check all interrupt flags every time through the interrupt routine. The extra "IF" statements, if nothing is set, adds very little time to the overall interrupt routine.
With a method with multiple IFs at the start of the interrupt routine, one has to eventually branch back to the start to check other flags before exiting, to see if anything else has to be processed.

My method is a straight linear processing method, and the order in which you put the code determines the "priority" in which you process the interrupts (do not confuse with high/low priority interrupt settings). Each of those interrupt routines should be as short as possible. Process the interrupt, set flags or indicators, then exit that routine.
Hi S,
I'm a bit confused!

I only have one INTERRUPT:

It's the "...do UART code" thats confusing me. I understand that it should be as short as possible.

How much of my INTERRUPT should be in the INTERRUPT routine?
C.
====================================================
On High Interrupt
Save System

If RCSTA.OERR = 1 Or RCSTA.FERR = 1 Then
RCSTA.CREN = 0
RCSTA.CREN = 1 'ENABLES RECEIVER
char = RCREG '1'char = RCREG '1
char = RCREG '2char = RCREG '2
err = 1 'ERROR
Endif

If PIR1.RCIF = 1 Then
char = RCREG
buf(rxpsn) = char

If char = "$" Then
rxpsn = 0
buf_fill = 1
Endif

If buf_fill = 1 Then
If char = "W" Then
buf_done = 1
RCSTA.CREN = 0 'INTERRUPT DISABLED
PIE1.RCIE = 0 'DISABLEs EUSART RECEIVE INTERRUPT
Endif
buf_fill = 0
Else
If buf_done = 0 Then
rxpsn = rxpsn + 1
Endif
Endif
Endif

If rxpsn > rxsize Then rxpsn = 0

Resume
 

sagor

Joined Mar 10, 2019
1,049
Without checking the nesting of all those "IF" statements, that looks generally correct. However, once you set err=1, should you not just exit the interrupt routine at the "resume" statement? The way it is written, if you get an error, you skip the code where you check PIR1.RCIF=1 of course because RCIF should be =0, but you are still checking rxpsn > rxsize. Is there a point to that if you have not received any valid charaters (err=1)?
That interrupt routine is relatively short, which is a good thing.

Just an observation. Using strings in Oshonsoft uses a lot of system routines to parse them vs processing byte values directly. In a simple 8Mhz emulation, checking for "$" as a string:
if string_char = "$" then string_buf=string_char, took 86uS (8Mhz clock)
whereas as direct binary comparison like: ($ ACSII is 0X3F hex, or 63 decimal)
if byte_char = 0x3f then byte_buf = byte_char is only about 3uS !!
That means simple string comparisons are about 20-30 times longer to process than byte processing. I see no reason to use "strings", as UART data are byte values anyway, and you can always look up what the ASCII character values are for things like "IF" statements.
If you want to save time in the main loop (and interrupt routine), you should look at processing all UART data as bytes, not strings.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
Without checking the nesting of all those "IF" statements, that looks generally correct. However, once you set err=1, should you not just exit the interrupt routine at the "resume" statement? The way it is written, if you get an error, you skip the code where you check PIR1.RCIF=1 of course because RCIF should be =0, but you are still checking rxpsn > rxsize. Is there a point to that if you have not received any valid charaters (err=1)?
That interrupt routine is relatively short, which is a good thing.

Just an observation. Using strings in Oshonsoft uses a lot of system routines to parse them vs processing byte values directly. In a simple 8Mhz emulation, checking for "$" as a string:
if string_char = "$" then string_buf=string_char, took 86uS (8Mhz clock)
whereas as direct binary comparison like: ($ ACSII is 0X3F hex, or 63 decimal)
if byte_char = 0x3f then byte_buf = byte_char is only about 3uS !!
That means simple string comparisons are about 20-30 times longer to process than byte processing. I see no reason to use "strings", as UART data are byte values anyway, and you can always look up what the ASCII character values are for things like "IF" statements.
If you want to save time in the main loop (and interrupt routine), you should look at processing all UART data as bytes, not strings.
Hi S,
As my routine is generally correct, hopefully I'll try to test the nesting, so I'll work with this and re-check this post for the other changes, i,e, STRING ASCII, stuff later. I've always had trouble with nesting, and can see a possible change, but if anyone would check it properly, it would be helpfull.
Thanks,

EDIT: I can see errors in the nesting LOOPs!
C.
 
Last edited:

Thread Starter

camerart

Joined Feb 25, 2013
3,830
Hi,
I'm always reluctant to mess about with CODE when it's almost working, but today I made an exception.

I looked at the nesting of what I posted in #182, and could see errors, and hopefully corrected them. I tried it, and can see that the INTERRUPT section may be much better. Here it is:

Because I've changed it there is now an error in the MAIN LOOP, that I should be able to correct.
C
Code:
On High Interrupt
Save System

REG register And receiving Next valid Byte)
If RCSTA.OERR = 1 Or RCSTA.FERR = 1 Then
        RCSTA.CREN = 0
        RCSTA.CREN = 1  'ENABLES RECEIVER
        char = RCREG  'char = RCREG
        char = RCREG  'char = RCREG
        err = 1  'ERROR
Endif

If PIR1.RCIF = 1 Then
        char = RCREG
        buf(rxpsn) = char
        If char = "$" Then
                rxpsn = 0
                buf_fill = 1
        Else
            If buf(0) = "$" And char = "W" Then
                buf_done = 1
                buf_fill = 0
                RCSTA.CREN = 0  'INTERRUPT DISABLED
                PIE1.RCIE = 0  'DISABLEs EUSART RECEIVE INTERRUPT
            Endif
        Endif
        rxpsn = rxpsn + 1
Endif

If rxpsn > rxsize Then rxpsn = 0

Resume
 
Last edited:

sagor

Joined Mar 10, 2019
1,049
If you indent your "IF" statements, it makes it a lot easier to follow.ie:
Code:
On High Interrupt
Save System

If RCSTA.OERR = 1 Or RCSTA.FERR = 1 Then
    RCSTA.CREN = 0
    RCSTA.CREN = 1 'ENABLES RECEIVER
    char = RCREG 'char = RCREG 1
    char = RCREG 'char = RCREG 2
    err = 1 'ERROR
Endif

If PIR1.RCIF = 1 Then
    char = RCREG
    buf(rxpsn) = char
    If char = "$" Then
        rxpsn = 0
        buf_fill = 1
    Else
        If char = "W" Then
            buf_done = 1
            buf_fill = 0
            RCSTA.CREN = 0 'INTERRUPT DISABLED
            PIE1.RCIE = 0 'DISABLEs EUSART RECEIVE INTERRUPT
        Endif
    Endif
rxpsn = rxpsn + 1
Endif

If rxpsn > rxsize Then rxpsn = 0

Resume
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
If you indent your "IF" statements, it makes it a lot easier to follow.ie:
Code:
On High Interrupt
Save System

If RCSTA.OERR = 1 Or RCSTA.FERR = 1 Then
    RCSTA.CREN = 0
    RCSTA.CREN = 1 'ENABLES RECEIVER
    char = RCREG 'char = RCREG 1
    char = RCREG 'char = RCREG 2
    err = 1 'ERROR
Endif

If PIR1.RCIF = 1 Then
    char = RCREG
    buf(rxpsn) = char
    If char = "$" Then
        rxpsn = 0
        buf_fill = 1
    Else
        If char = "W" Then
            buf_done = 1
            buf_fill = 0
            RCSTA.CREN = 0 'INTERRUPT DISABLED
            PIE1.RCIE = 0 'DISABLEs EUSART RECEIVE INTERRUPT
        Endif
    Endif
rxpsn = rxpsn + 1
Endif

If rxpsn > rxsize Then rxpsn = 0

Resume
Hi S,
I figured out how to do it and updated #185 :)
C.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
Hi,
Way back at #163, I reported that: messages are at the RX PIN, and in the Simulator the program works, but 'live' it doens' appear that the sentences are being READ. I'm still having the same problem
If the sentence was being READ, then a LED would flash and the TX would show it, but it isn't, how do I test for it?

EDIT: I tried [ If PIR1.RCIF = 1 Then LED ON ] the LED came ON, so the PIC is 'seeing' the Sentence at the RX PIN. It appears to be a probelm in my INTERRUPT? Therefore, I may be able to work through the program 'live' and find the blockage?
C.
 
Last edited:

sagor

Joined Mar 10, 2019
1,049
Are you remembering to turn the UART and interrupts back on in the main program, in the right place? Since you turn them off in the interrupt routine when you have a full sentence, you must have some place to turn it back on.
I see a bit of a problem:
Code:
If PIR1.RCIF = 1 Then
    char = RCREG
    buf(rxpsn) = char
    If char = "$" Then
        rxpsn = 0
        buf_fill = 1
If char = $, you have already stored it in buf(rxpsn), but now you set rxpsn=0. What was rxpsn before??? You don't store the "$" in position zero (start of string buffer). Maybe you designed it this way, to not store the "$"? How do you reset if you get a second "$" while still receiving a valid string part way thru?
You use a flag buf_fill=1, but I don't see it anywhere in the interrupt routine. Could you not use that to flag that you are currently receiving a string
Logic like:
Check if buf_fill=0 = see if "$" is there to start filling. Else exit routine - nothing valid yet. If = "$", then start saving string and set buf_fill=1 and exit routine.

if buf_fill=1 means we have a valid start, just store character, increment pointer
if buf_fill=1 then chack if terminator "W" received, then set all flags and pointers as needed. Set "done" flag, disable UART and clear buf_fill

You have to follow your code mentally with all possible conditions and combinations to see how your code handles it. For example, what if you get two "$" in a row? What if you get a "$" while already receiving a valid string? What if you never get a "$" but just see "W"? What if you get overflow and reset the pointer, then get a "W" right after? Add onto all those, the combination of an OERR error, how do you handle your pointers/flags and UART?
 

sagor

Joined Mar 10, 2019
1,049
One observation, when you hit a too long buffer and reset the pointer:

If rxpsn > rxsize Then rxpsn = 0

Resume

You should also zero the buf_fill =0, as you had an overflow and want to wait for a new "$" to start saving a valid buffer again. By leaving buf_fill=1, your interrupt routine will simply put the next character into position buf(0), and it will not likely be a "$" at all. Then you may lock yourself out because you will never see buf(0)=$ when you get a "W", and never get buf_done=1
So, when you get an "error" like buffer overflow, you have to reset everything that is used to check and store into that buffer
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
One observation, when you hit a too long buffer and reset the pointer:

If rxpsn > rxsize Then rxpsn = 0

Resume

You should also zero the buf_fill =0, as you had an overflow and want to wait for a new "$" to start saving a valid buffer again. By leaving buf_fill=1, your interrupt routine will simply put the next character into position buf(0), and it will not likely be a "$" at all. Then you may lock yourself out because you will never see buf(0)=$ when you get a "W", and never get buf_done=1
So, when you get an "error" like buffer overflow, you have to reset everything that is used to check and store into that buffer
Hi S,
I deleted my last post, here is the ammended program, with your observation:
Thanks,

EDIT: I'll recheck this later and probably re-post it, as I think I copied errors?
C.
Code:
main:
WaitMs 1000

'If buf_fill = 1 Then yled = 1
'If buf_done = 1 Then rled = 1

If buf_done = 1 Then
    Hserout "BUF COMPLETE", CrLf
    buf_done = 0  'Buf filled
    Gosub parse
    prs_done = 1  'Parse Done
Endif

If prs_done = 1 Then
    strbuf = ""
    RCSTA.CREN = 1  'INTERRUPT ENABLED
    PIE1.RCIE = 1  'ENABLEs EUSART RECEIVE INTERRUPT
    Gosub switch
    prs_done = 0  '??????????????????
Endif

'@@@@@@
'For x = 0 To 79  'CLEARS STR1
    'str1(x) = 0
'Next x
'@@@@@

If Len(strtim) <> 0 Then  'if string is zero length don't hserout........
    Hserout "T=", strtim, " N=", strlat, " W=", strlong, CrLf
    WaitMs 5  '????????????
Endif

If Len(qeideg) <> 0 Then
    Hserout "QEIDEG=  ", qeideg, CrLf  'QEIDEG=BASE 4431 Opto encoder
    WaitMs 5  '??????????
Endif

If Len(strremvolt) <> 0 Then
    Hserout "REMVOLT=", strremvolt, " REMALT=", strremalt, " REMDIST=", strremdist, CrLf
    WaitMs 5  '??????????
Endif

'If PIR1.RCIF = 1 Then yled = 1'??????????????????
'INTCON.GIE = 1  '????


Goto main
End

On High Interrupt
Save System

'OERR-BIT1..if over run error then flush RXD buffer
'FERR-BIT2..framing error(can be cleared by reading RCREG register And receiving Next valid Byte)
If RCSTA.OERR = 1 Or RCSTA.FERR = 1 Then
        RCSTA.CREN = 0  'BIT4
        RCSTA.CREN = 1  'ENABLES RECEIVER
        char = RCREG  'char = RCREG
        char = RCREG  'char = RCREG
        err = 1  'ERROR
Endif

'PIR1 %00010000 = TXIF 1 = The EUSART transmit buffer, TXREG, is empty (cleared when TXREG is written)
'PIR1 %00100000 = RCIF 1 = The EUSART receive buffer, RCREG, is full (cleared when RCREG is Read)

If PIR1.RCIF = 1 Then
    char = RCREG
        If char = "$" Then
            rxpsn = 0
            buf_fill = 1
        Endif
        If buf_fill = 1 Then
            buf(rxpsn) = char
            rxpsn = rxpsn + 1
        Endif
        If buf(0) = "$" And char = "W" Then
            RCSTA.CREN = 0  'INTERRUPT DISABLED
            PIE1.RCIE = 0  'DISABLEs EUSART RECEIVE INTERRUPT
            buf_fill = 0
            buf_done = 1
        Endif
Endif

If rxpsn > rxsize Then
    rxpsn = 0
    buf_fill = 0
Endif

Resume      



parse:
   
'For x = 0 To rxi  'REMOVE
    'Hserout str1(x)
'Next x

Hserout CrLf, CrLf
'If BAUDCON.RCIDL = 1 Then  'NEVER 1! in SIM
'...SET DATASWITCH: 'S0=1 S1=0 =TX4431,  S0=0 S1=H =HC-12, S0=0 S1=0 =GPS
    For cnt = 1 To rxpsn
        char = buf(cnt)
        strchr = Chr(char)
            strbuf = strbuf + strchr
            If buf(5) = "C" Then  '1 in DATASWITCH sequence
                Gosub get_valg  'GPS
                datasw = 2  'Set to next in DATASWITCH sequence
            Endif
            If buf(1) = "R" Then  '2 in sequence
                Gosub get_valr  'REMOTE
                datasw = 3  'Set to next in sequenc
            Endif
                If buf(1) = "Q" Then  '3 in DATASWITCH sequence
                Gosub get_valq  'QEIDEG
                datasw = 1  'Set to next in sequence
            Endif
    Next cnt
    rxpsn = 0  'RESET RX position
'Endif
Return                                          

'----------------------------------------------------------------------
'To avoid a framing error, you are best to switch DATASWITCH between Ascii characters
'by checking BAUDCON.RCIDL=1. If it is =1, Then the UART is idle And Not receiving any
'serial data stream.
'----------------------------------------------------------------------
''This subr extracts the main values from the QEIDEG string, into named value messages.
''also converts the string to a named numeric value, for maths.
get_valq:  '$QEIDEG,359,?
qeideg = MidStr(strbuf, 8, 3)
Return                                          
'This subr extracts the main values from the REMOTE string, into named value messages
'also converts the string to a named numeric value, for maths
get_valr:  'REMOTE= ,12,20,50,?  [remvolt,remalt,remdist]
'If BAUDCON.RCIDL = 1 Then
'SET DATASWITCH: 'S0=1 S1=0 =TX4431,  S0=0 S1=H =HC-12, S0=0 S1=0 =GPS
'Endif
strremvolt = MidStr(strbuf 8, 2)
strremalt = MidStr(strbuf 11, 2)
strremdist = MidStr(strbuf 14, 2)

Return                                          
'This subr extracts the main values from the GPS string, into named value messages
'also converts the string to a named numeric value, for maths
get_valg:  'GPS $GNRMC,123519,A,4807.038,N,01131.000,W,022.4,084.4,230394,003.1,W*6A?
'If BAUDCON.RCIDL = 1 Then
'SET DATASWITCH: 'S0=1 S1=0 =TX4431,  S0=0 S1=H =HC-12, S0=0 S1=0 =GPS
'Endif
strtim = MidStr(strbuf, 7, 2) + ":" + MidStr(strbuf, 9, 2) + ":" + MidStr(strbuf, 11, 2)
strlat = MidStr(strbuf, 16, 10)  'Number of digits in the STRING
''''''''sinlat = StrValS(strlat)MOVE JUST BEFORE CALCULATION##########
strlong = MidStr(strbuf, 27, 11)
''''''''sinlong = StrValS(strlong)MOVE JUST BEFORE CALCULATION##########

Return                                          
'INTCON.GIE = 1  '????

switch:
''If prs_done = 1 Then
    If datasw = 1 Then
        dataswitch_S0 = 0  'GPS
        dataswitch_S1 = 0
        rled = 0
        yled = 0
    Endif
    ''WaitMs 50
    If datasw = 2 Then
        dataswitch_S0 = 1  'REMOTE HC-12
        dataswitch_S1 = 0
        rled = 1
        yled = 0
    Endif
    ''WaitMs 50
    If datasw = 3 Then
        dataswitch_S0 = 0  'QEI 4431
        dataswitch_S1 = 1
        rled = 0
        yled = 1
    Endif
    ''WaitMs 50
''Endif

Return
 
Last edited:

Thread Starter

camerart

Joined Feb 25, 2013
3,830
Hi,
Earlier the difference between HSERIN and char = RCREG was discussed, and it was stated that they are both the same, only HSERIN takes longer, but I've noticed a difference, that is relevant.

In this system there are 3x $Sentences to be READ and PARSED. They are addressed in series, by the last message triggering an on board DATASWITCH.

1x message comes from the GPS and starts with a $ and has a W well before the end.
1x message comes from the on board 184431 PIC READing the QEI, [ $QEIDEG,111,W$QEIDEG,222,W ]
1x messages comes from a computer serial port with MACRO, sending simulated messages from the 'not ready yet REMOTE' [ $REMOTE,11,22,33,W$REMOTE,44,55,66,W ]

I noticed that when my 2x messages are gong through the simulator, the $ is missed because it's in the buffer while the W is finishing the sentence, and discarded.

I don't fully understand the differences betewwen the Simulator and LIVE, but I assume I can add a couple of digits to the MACRO and PIC sentences to correct this, or do I need to change the INTERRUPT?

I assume that if the INTERRUPT was switched off while each digit was being READ, then this would work, but I also assume it would slow it down like the HSERIN does. Is this correct?
C
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
Hi,
As mentioned the program works in simulation, but not in 'live' tests.

I've been searching the CODE for why, and had to add LEDs into the program, and work there way throught it, till I found the offending lines.
Here is how I changed in and it now works in SIM, but there are still errors.
C
Code:
If PIR1.RCIF = 1 Then
        char = RCREG
        If char = "$" Then
            rxpsn = 0
            buf_fill = 1
        Endif
        If buf_fill = 1 Then
            buf(rxpsn) = char
            If rxpsn <= 39 Then........................... ADDED........................
                rxpsn = rxpsn + 1
            Endif..................................................................................................
        Endif
        If buf(0) = "$" And char = "W" Then
            RCSTA.CREN = 0  'INTERRUPT DISABLED
            PIE1.RCIE = 0  'DISABLEs EUSART RECEIVE INTERRUPT
            buf_fill = 0
            buf_done = 1
        Endif
Endif

'If rxpsn > rxsize Then................REMOVED..................
    'rxpsn = 0
'buf_fill = 0
'Endif................................................................................
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
Hi,
I'm pretty near to getting the INTERRUPT/PARSE routine working.
It READs the 3x $sentences and PARSES them, but when I changed the 1sec MS delay it started missing messages. I've got a few WAITMS times in the program, that I've tried changing, but I would like to know how to time this better please?
Times are marked with ????????????????
Here's the CODE:
C.
 

Attachments

Thread Starter

camerart

Joined Feb 25, 2013
3,830
Hi,
I've been testing different ways to switch the DATASWITCH, and may have cured my problem, I'll re-check, tidy up and re-post the program.
Sorry, I'f you've been working on it.
C.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
Hi,
I've been having a few problems with the DATASWITCH switching, and now find that it is something to do with the receiving radio RX being suppressed.
Here is a terminal view directly from the radio RX. It shows the $REMOTE signal being received from the computer terminal TX, as the PCB is being switched on. At first the signal is being received, until the program starts, then the Rx appears to be stopped in some way.
Does any one have any ideas, please?
C.
 

Attachments

JohnInTX

Joined Jun 26, 2012
4,787
Code:
On High Interrupt
Save System

If RCSTA.OERR = 1 Then  'BIT1..if over run error then flush RXD buffer
    If RCSTA.FERR = 1 Then  'BIT2..framing error(can be cleared by reading RCREG register And receiving Next valid Byte)
        RCSTA.CREN = 0
        RCSTA.CREN = 1  'BIT4 ENABLES RECEIVER
        char = RCREG  '1
        char = RCREG  '2
        err = 1  'ERROR
    Endif
Endif
Hi C.
One idea. You test for OERR but then require that FERR is also set before you fix the UART. You are unlikely to get a framing error if your baud rate is correct. In this code, if you get an overrun error without a framing error (likely), you will never get to the required fixup code and the UART will be kaput. You don't need to reset the UART on a framing error, it will still continue to receive characters and generate interrupts (but you have to discard the data). Treat the errors as separate with separate fixes.

A thought for you: Once I get a serial link set up, I never turn it off. I always receive every character sent with the appropriate error checking/recovery. The problem with on and off is that you don't know where you are in the input stream when you turn it back on. Clearly a good error detection / recovery scheme will handle that (as it must when you are powering up or after a uC reset) but I just don't like jumping into a stream mid-character. My solution is to have a flag to indicate when I don't want to process any characters. Receive/error check/recover as normal then check the flag to see if the received character should be processed or discarded. That way, a simple flag turns the data stream on and off. In your case, enabling the data processing would also begin looking for the '$'. Such a scheme also allows you to monitor the presence and integrity (no hardware error flags) of the stream continuously, even if you are not processing the data.

It READs the 3x $sentences and PARSES them, but when I changed the 1sec MS delay it started missing messages. I've got a few WAITMS times in the program, that I've tried changing, but I would like to know how to time this better please?
Why have any delays at all? Get a buffer full, parse and process it, use that data then get back to the top and wait for the next buffer full. Mixing real-time processing needs (receiving from a UART with no flow control) with blocking delays is pretty much guaranteed to drive you crazy, especially when you try to get lucky with just-in-time timings. Ask me how I know these things.

While we're at it. Keep in mind that any test you send to the terminal is likely using a blocking delay. Most simple implementations write to TXREG then poll a flag to see when that character has been sent and the UART can take another. At 9600 baud, each character is about 1ms. So saying 'ERROR!' bogs your system down 60ms more or less. Note that the simulator may not take the time to transmit into account but just put the characters up on the window adding to your timing woes between sim and hardware. I don't know how Oshensoft does it but have been bit by that on other systems.

Just my .02
Good luck!
 
Last edited:
Top