- Joined Feb 25, 2013
Hi JT,Here you go.
Note that at the top you see:
The active setting speeds up the timers for use in the sim. Bigger number is slower timers.
Comment that out and uncomment the line above to set PR2 to 250 for the live version.
This code uses TIMER2 to generate an interrupt every 20ms. It drives a set of timers from that interrupt.
Each timer is one byte that counts from whatever value you set (0-255) down to 0 then stops at 0. Each timer is used as a guard timer on various info.
To know if a timer has timed out, just read it and test for 0 as you see in main_loop.
There are 2 periods in use:
20ms/count for the UART receive guard timer. This timer is set and begins to run whenever setUARTchannel is called to select a new channel. The default time is 5secs.
Note that in main_loop, it now polls the timer along with buf_done. Most of the time, buf_done will be true (meaning it got a sentence from $-W) before the timer runs to 0 and it will fall through to calling parse. If the timer DOES run to 0 before buf_full it means that it did not get a sentence within 5 seconds and it jumps to select the next channel then loops back to see what's happening on that one. In this way, a dead GPS or radio out of range won't lock up the system.Main waiting for new sentence OR timeout:
waitBuf: If buf_done = 0 Then 'Other processing.. If ms20_RXguard = 0 Then Goto sentence_done Endif Goto waitBuf Endif 'Sentence is received, proceed to parsing it 'Since parsing SHARES some variables with the IRQ service, you can't begin 'looking for the next sentence until parsing is complete. Gosub parse 'parse the received sentence 'Process any new data from parseing (while new sentence is being received) If prsed_GNRMC = 1 Then Hserout "T=", strtim, " N=", strlat, " W=", strlong, CrLf 'process new data prsed_GNRMC = 0 'and clear flag to indicate that new data has been "processed" Endif If prsed_QEIDEG = 1 Then Hserout "QEIDEG= ", qeideg, CrLf 'QEIDEG=BASE 4431 Opto encoder prsed_QEIDEG = 0 Endif If prsed_REMOTE = 1 Then Hserout "REMVOLT=", strremvolt, " REMALT=", strremalt, " REMDIST=", strremdist, CrLf prsed_REMOTE = 0 Endif If prsed_GOOD = 0 Then 'parse tried but string was unknown, corrupt or wrong length Hserout "Parse fail Chan: ", #datasw, CrLf Endif '-------------- SENTENCE PROCESSING COMPLETE --------------- 'Done receiving, parsing and processing ONE sentence. sentence_done: Gosub next_channel 'select next channel Gosub setUARTchannel 'start UART on channel(datasw), begins looking for sentence Goto main_loop
I also added a separate timer for each of the sentence types on the assumption that even if the system did not lock up waiting for a sentence, it would be handy to know which sentence(s) were missing i.e. if it's been too long since the data would be updated. Example, suppose lat and long haven't been updated in awhile, is it at rest or is the GPS dead? Nice to know. These timers are maintained by parse but the code doesn't check them for 0. You can add that as necessary if you want.
The timer names, periods, and default values are shown in the code as:
Setting a timer, in this case the RX sentence guard timer, looks like this:Timer names and settings:
'receive guard timer Dim ms20_RXguard As Byte 'native 20ms RX guard timer derived from TMR2 irq Const RXguardSet = 250 '20ms * 250 = 5 secs to wait for any RX sentence 'Guard timers for each sentence type and their set times Dim ms100_GNRMCguard As Byte 'GNRMC message guard timer * 100ms Const GNRMCguardSet = 100 '100ms * 100 = 10 secs to get a good GNRMC sentence Dim ms100_REMOTEguard As Byte 'REMOTE sentence guard timer *100ms Const REMOTEguardSet = 100 '100ms * 100 = 10 secs to get a good REMOTE sentence Dim ms100_QEIDEGguard As Byte 'QEI guard timer *100ms Const QEIDEGguardSet = 100 '100ms * 100 = 10 secs to get a good QEIDEG sentence
That's all there is to it.Setting the RX timer in chan_set::
chan_set: Gosub IRQinitBuf 'RCIE is off, init buffer, index, flags RCSTA.CREN = 1 RXIRQchar = RCREG RXIRQchar = RCREG PIE1.RCIE = 1 ms20_RXguard = RXguardSet 'set RX sentence timer Return
When you load this in the sim, use the 8xLED window to monitor the Yel and Red LED channel indicators without sending anything. You'll see them changing as ms20_RXguard runs down to 0 and main_loop exits and changes the channel.
In the 'Watch" window, you can see the values of the timers. You'll see the ms20_RXguard running round and round with the channel changing when it goes to 0 and gets reloaded.
Sentence guard timers:
When you send a good sentence and it's parsed, you'll see its timer get set and begin to run down. If you don't send anything else, it will run to 0 indicating it's been a long time since it received that sentence and the data is getting stale. Look at these as juggling to keep 3 balls in the air. As long as you are tossing the balls (receiving and processing valid sentences) they'll stay in the air (timer never runs to 0). Stop juggling and the balls hit the floor (timer runs to 0). Right now, we don't do anything with the timeout indication but if your code is interested in whether your data is recent, read the sentence's timer, if it's non-zero, the data is recent. If 0, stale.
The lesson here is what you've already found out - never wait endlessly on something from the horrible outside world to arrive.. always have some sort of mechanism to keep an eye on things, allow the code to keep moving and give you a chance to take action if something goes away unexpectedly.
Final note: the times were picked out of the air and are likely longer than necessary. They can be adjusted by changing the Const... values near the top of the file. I'm not sure what your sentence rate is.
This is new stuff but worth the study.
EDIT: add example setting timer
You used a juggling metaphor as an explanation, well, using the same metaphor, I'm now juggling 3x more balls than I'm capable of
Thanks you for this thought out solution. I can basically understand it, but not really. E,G, I try to visualise what would happen with an actual flying machine, and saw a line [10 secs to get a good REMOTE sentence] so, if I understand correctly, a flying machine may have moved for 10Secs, and they can go perhaps 20MPH. When flying near object this is too long to act. I did note however, that you mention correcting the timings, which I'll bear in mind if I do manage to follow your CODE properly, but you may be able to imagine it also.
I like that 'the end of one message triggers then next in the sequence', and think that this is the most efficient, if there is always a sentence, but if one doesn't arrive, then things happen. Previously, I had it that the DATASWITCH would switch through the sequence anyway, but not as fast. I was wondering if the DATASWITCH switched 3x/sec if the previous sentence didn't switch it, this would be faster.
Trying to visualise the timings of the receving sentences. Each of the sentences are arriving at 5x/sec but rather randonmly. The GPS has 2x values '5/sec' or '1/sec', the REMOTE and 4431 timings can be changed in their programs. The GPS is the most accurate I think, so it may be possible to use the 5/sec to trigger the DATASWITCH or the 18F4431. I also wondered about synching every thing together, using either the GPS or the 18LF4620 clock.
Anyway, I'll try your program, and see if I can follow it.