Note that tasks do not take parameters. Now, in the
main body of our program we can set up the task’s timing
and enable it:
TASKS SET, 0, BLINK_LED, 250
TASKS ENABLE
By using TASKS SET, we have assigned task slot zero
to BLINK_LED and it will run every 250 task ticks; in this
case, every 250 milliseconds. Finally, TASKS ENABLE
allows this task (and others if defined) to run. The task
code itself looks very much like a subroutine except that it
is blocked with TASK and ENDTASK:
TASK BLINK_LED
IF alarmOn THEN
TOGGLE AlarmLed
ELSE
AlarmLed = IsOff
ENDIF
ENDTASK
I stated earlier that we can’t pass parameters to a task
but SX/B does; with this we can do more than one thing
with a given task. We start by defining task slots that point
to the same task routine:
TASKS SET, 0, BLINK_LED, 250
TASKS SET, 1, BLINK_LED, 100
TASKS ENABLE
So, how do we know which slot called the task? The
slot number will be passed to the task code in __PARAM1.
Here’s an update to BLINK_LED that looks at the slot
number that called it:
TASK BLINK_LED
slot VAR __PARAM1
IF slot = 0 THEN
IF alarmOn THEN
TOGGLE AlarmLed
ELSE
AlarmLed = IsOff
ENDIF
ELSEIF slot = 1 THEN
IF sysReady THEN
TOGGLE SystemLed
ELSE
SystemLed = IsOff
ENDIF
ENDIF
ENDTASK
For clarity, I’ve aliased __PARAM1 as slot. A simple
IF-THEN structure determines which LED to work with.
Note that the code is simple and we will want to keep
task code fairly trim. Interrupts still work and will, in fact,
interrupt a task, but what we don’t want is for a task to be
24 November 2008
running when its own timer expires and it needs to be
called again. Using tasks can be fun and save some
programming headaches but it does take a little time to
get used to. Start easy by playing with the LED code.
That’s where we always start, right? With blinking LEDs.
Once you get used to that, you can start combining some
of the new memory features with tasks.
For example: Let’s say we’d like an RTC without
adding a physical device like a DS1320 or DS1307.
Here’s a possible way of handling that. We’ll start by
defining the clock variables:
clock VAR Byte (4)
huns VAR Byte clock(R_HUNS)
secs VAR Byte clock(R_SECS)
mins VAR Byte clock(R_MINS)
hrs VAR Byte clock(R_HRS)
Whoa, Neo, that’s a little different, isn’t it? The clock()
array is easy; what we’ve done though is create pointers
into that array — technically these are just offsets and we
could use them with another array altogether (that’s really
advanced and we’ll explore it in the future). By defining
the elements this way, we can tell SX/B to use the clock
variables and have access to the internals as if they were
regular variables instead of array elements. Here’s what
I mean:
‘ Real-time BCD clock, hh:mm:ss.xx
‘ — modifies: clock(); values stored as BCD
‘ — set task to run every 10 milliseconds
TASK BCD_RTC
BANK @clock
INC huns
huns = huns + $06
IF DC = 0 THEN
huns = huns - $06
ENDIF
IF huns <= $99 THEN RTC_Done
huns = $00
INC secs
secs = secs + $06
IF DC = 0 THEN
secs = secs - $06
ENDIF
IF secs <= $59 THEN RTC_Done
secs = $00
INC mins
mins = mins + $06
IF DC = 0 THEN
mins = mins - $06
ENDIF
IF mins <= $59 THEN RTC_Done
mins = $00
INC hrs
hrs = hrs + $06
IF DC = 0 THEN
hrs = hrs - $06
ENDIF
IF hours <= $23 THEN RTC_Done
hrs = $00