SimpleHMI: Introducing Events
The first sample program above already handles one event, namely the Connect event. What happens is that when you click the Connect button on the SPLat/PC SimpleHMI screen, a special message is sent to the SPLat via the serial port. The SPLat detects this and automatically does a GoSub to your event handler. The event handler is simply a subroutine that does whatever is required in response to that event. It must exit via a Return instruction.
| This event-based mechanism is carried through the whole set of HMI hash functions. Events are also generated by button clicks and by user data entry. |
Events provide a lot of the power of SimpleHMI programming. Every time your SPLat program defines an event and names an event handler, a new, totally unique event code is set up in the SimpleHMI. Thus every event is unique, and unambiguously tied to its own event handler. A program may contain up to 127 event handlers. You can reference an event handler multiple times.
Consider this: SimpleHMI has a limited number of buttons, which can be re-used on different screens. On screen A button 1 may be the “Pump On” button. On screen B it may be the “Launch Missile” button. For each use you will have a separate handler subroutine. Now, it is only if screen B is actually showing that pressing that button will send back the event code for Launch_Missile. This means your program does not have to keep track of which screen it is showing in order to know how to respond to button 1.
Here’s a program that illustrates this point (You will get best value from this if you have indicator lights on outputs 0, 1, and 2 of your controller). There is a detailed description of each segment after the program. In this example I am using specific buttons to illustrate a point. Since the original writing the need to explicitly nominate buttons is all but eliminated but the point remains to be made:
(Click here for some tips for working around problems with copy and paste out of Internet Explorer and HTML-help (.chm) files)
This code was originally written to run on SimpleHMI on Windows. However, SimpleHMI on Windows is no longer supported. This new version of the code is written to run on an HMI430 or HMI700. However, the controller will need to be power-cycled for the code to work.
;Demonstrate re-use of buttons, and unique event handlers for each use;**** This example will require the HMI module to be restarted by a power cycle *******HMIPort EQU 251 ;Define the port number we want to use.#HMI ConnectEvent(HMI_Connect) ;Where to GoSub when the SimpleHMI connectsLaunchTask HeartBeat ;Show we are aliveRunTasksForever;----- HeartBeat task, shows we are alive by flashing an output -----HeartBeat:On 0Pause 2Off 0Pause 50GoTo HeartBeat;---- Event handler for the HMI Connected event generated by SimpleHMI -------HMI_Connect:GoSub HomeScreen ;Paint home screenReturn;----- Event handler for Home button ------HomeScreen:#HMI Cls();#HMI HideAllButtons()#HMI ButtonEvent2(id:1, y:4, x:9, h:3, w:20, t:"Pump On", ev:PumpOnEvent)#HMI ButtonEvent2(id:2, y:9, x:9, h:3, w:20, t:"Pump Off", ev:PumpOffEvent)#HMI ButtonEvent2(id:3, y:14, x:9, h:3, w:20, t:"Launch Screen", ev:LaunchScreen)Return;----- Event handler for Pump On button ------PumpOnEvent:On 1Return;----- Event handler for Pump Off button ------PumpOffEvent:Off 1Return;----- Event handler to paint Launch Screen ------LaunchScreen:#HMI SetColors(b:'HFF000000) Cls() ButtonEvent2(id:1, y:12, x:9, h:10, w:20, t:"Launch Missile", ev:Launch_Missile)#HMI ButtonEvent2(id:2, y:21, x:0, h:3, w:8, t:"Home", ev:HomeScreen)Return****** Launch the missile *********Launch_Missile:LaunchTask MissileLaunch ;A new MultiTrack taskGoSub HomeScreen ;Display the home screenReturn;==================================================================;A separate MultiTrack task to create a "spectacular" launch displaybCount defBYTEMissileLaunch:SetMem bCount,150 ;150 flashes#HMI ButtonEvent2(id:5, x:30, y:15, w:4, h:2, t:b(*bCount), m:"d1m1", ev:Return)FLoop:#HMI ButtonEvent2(id:5, t:b(*bCount) )On 2Pause 10Off 2Pause 90DMGNZ bCount,FloopKilltaskReturn:Return
Here’s a blow by blow description of each segment of the program:
Startup code
Defines the handler for the HMI ConnectEvent, launches the heartbeat task and gets MultiTrack running.
Heartbeat task
Trivial. I use this because it’s helpful to know during development that my program is actually running, especially as there’s a 10 second delay when initialising a serial protocol.
Connect event handler
Just calls the subroutine that paints the home screen. This is also called from elsewhere.
Handler for Home button
Cls() clears the screen to the current background colour (more on that later). HideAllButtons() … I’ll let you work that out!
Once the screen is returned to a blank state, we position and label buttons 1, 2, and 3, and define their event handler names.
Pump handlers
Trivial, but notice how little effort it has taken to tie the buttons to the physical actions.
Launch screen
This is the program’s second screen. It sets the background colour to red before clearing the screen. Then it defines a large, impressive “Launch Missile” button and a more modest Home button. Notice we are using button 1, which on the home screen is the Pump On button.
Launch button handler
This handler launches a fresh MultiTrack task whose job it is to manage the missile launch sequence.
MissileLaunch task
Creates a light and sound show (minus sound!) consisting of 150 rapid flashes of an output, then kills itself.
But there’s a problem, Housten!
When you test the program you will discover that on returning to the home screen from the launch screen, the red background colour persists. That was not the intention.
Exercise: Study the program and fix it.
A subtle hazard
I have positioned the Launch Screen button on the home screen, and the Launch Missile button on the launch screen, deliberately overlapping each other. If you click very rapidly on the overlapping buttons, you will be able to crash the program. The reason is that every time you launch the missile you also launch another copy of the MissileLaunch task. When you get to the limit of 32 running tasks, the controller crashes.
Exercise: Find a solution.
Hint: Use a semaphore that is set when the launch missile task is launched, and reset when it completes. Use that semaphore to prevent it from being launched a second time when it is already running.
This effect does not occur in Android, because Android and Windows have different way of rendering overlapping buttons. This example is intended only for the Windows versions of SimpleHMI.
Note: It took me longer to write this page than to write the sample program.
Exercise: Modify the program so it is impossible to launch while the pump is on.