ZBasic Language Reference
64
ZBasic Microcontrollers
3.4.1 System Queues
The console I/O routines like Console.Read() and Console.Write() use the input and output queues
associated with Com1. Because of their special use in this manner, the queues associated with Com1
are called system queues. The values Register.RxQueue and Register.TxQueue give the address
of the system input queue and system output queue respectively. The function CByteArray() can be
used to convert these values to a reference to a Byte array allowing them to be passed to the queue-
related routines. The example code below shows how to determine if there is any data available in the
system input queue using this technique.
If StatusQueue(CByteArray(Register.RxQueue)) Then
b = Console.Read()
End If
The system queues are initially set to be small pre-defined queues. If your code opens Com1, the
queues that you provide with the OpenCom() invocation become the system queues until you
subsequently close Com1. At that time, the system queues will revert to the pre-defined queues.
Of the two pre-defined queues, the output queue is the smallest, having space for only a few data bytes.
Because of this, if you send a fairly long string to the output queue using Console.Write() your application
will experience a delay until the strings characters can all be transferred to the output queue. If this
causes a problem in your application you can define a larger queue to be used as the output queue. The
example code below does so while retaining the pre-defined input queue.
Private sysOutQueue(1 to 40) as Byte
Call OpenQueue(sysOutQueue, SizeOf(sysOutQueue))
Call CloseCom(1, 0, 0)
Call OpenCom(1, Option.Com1Speed, _
CByteArray(Register.RxQueue), sysOutQueue)
For native mode devices (e.g. the ZX-24n) you can specify the default sizes for the system queues using
the directives Option TxQueueSize and Option RxQueueSize.
3.5 Multitasking
The concept of multitasking is a very powerful one although it can be, at first, somewhat confusing. In a
single task system, there is only one program and it runs continuously until it is terminated. During the
course of execution of the program it may perform several different functions, e.g. checking the keyboard
to see if a character is available, updating the display unit, etc. The fundamental idea behind multitasking
is that these activities are divided into related groups, each of which is called a task. Each task executes
for a period of time and then the next task executes. There are two basic types of multitasking:
cooperative and preemptive. In cooperative multitasking it is left up to each task to determine when to
suspend itself and allow the next task to run. In preemptive multitasking a part of the operating system
called a task scheduler determines, generally, how long a task is allowed to run before switching to the
next task.
The multitasking in ZBasic is, fundamentally, preemptive multitasking. The task scheduler switches tasks
on each RTC tick (approximately 1.95mS). A task can, however, lock itself to avoid (with some
exceptions) giving up execution. This capability should be used sparingly because it defeats the
equitable sharing of processing resources.
It is not necessary, of course, to structure your program to utilize the multitasking capabilities. If there is
only one task defined (the subroutine Main()) the task scheduler will simply allow it to run continuously. If
your application might benefit from being divided into tasks, it is simple to define them. Each task has two
core elements: a task main routine and a task stack. The task main routine is the (usually parameterless)
subroutine with which the task begins execution. The task stack is a portion of RAM set aside exclusively
for the task. The example below shows how to define a task stack and how to activate a second task.
|