Stamp
we will reset it before moving on. If you modify the
program for a smaller display, be sure to update this
section of code.
The code at Next_Digit actually updates the display.
We start by turning it off — this will prevent ghosting when
we change the anode (segments) values. Next, we’re going
to check a couple of values that can be set by the user via
serial commands (more on that later). The first is the
blanking bit, which turns the display off without affecting
the contents of the display buffer. When blanking is
enabled, we jump right out of the ISR before enabling the
current column. The next value checked is the column
limit. This lets us decide how many columns to activate
(starting from the rightmost position). If the column
pointer is beyond the column limit, we jump out of the ISR
before activating the current column.
Finally, when blanking is off and the current column
is active, we will move the contents of the anodes buffer
for that column to the display. Then, we activate the
column by setting its cathode control line to 0 and we’re
done.
Take another breath. The really cool thing about all
this is that the multiplexing code was written in Basic —
SX/B Basic. That’s really neat. Now, before you get too
excited, there is something very important to keep in
mind: You must keep the longest path through the ISR
to less than the number of cycles assigned to the ISR
activation, minus three cycles (101, for this project). If we
go over, what will happen is that an interrupt cycle may get
ignored if it occurs while the current interrupt is still
running (the SX disables interrupt while running the ISR)
and this could be catastrophic for programs that require
specific interrupt timing.
You can check the length of the ISR by looking at the
assembly output — using Ctrl-L in the SX-Key editor is a
quick way to do this. In this program, the final address of
the ISR is $0056 ( 86), so we’re in good shape.
Back to Easy Street
With the interrupt routine coded and working, the rest
of the program is downright simple. Let’s go through the
important parts. In the beginning, we want to wait for the
proper header string before processing any commands —
this keeps us AppMod-compatible. The header for the LED
controller is “!SS8” and will be followed by a command and
one or more data bytes.
Main:
GOSUB Get_Byte, @cmd
IF cmd <> “!” THEN Main
GOSUB Get_Byte, @cmd
IF cmd <> “S” THEN Main
GOSUB Get_Byte, @cmd
IF cmd <> “S” THEN Main
GOSUB Get_Byte, @cmd
IF cmd <> “8” THEN Main
JANUARY 2005
This code looks very similar to what we did in the line
follower program. It simply goes through the input until
the sequence “!SSR” is received. Remember that our
serial input is being placed into a circular buffer by
the ISR, so we need to write a routine to retrieve the first
available byte.
_Get_Byte:
IF rxTail = rxHead THEN _Get_Byte
regAddr = __PARAM1
temp1 = rxBuf(rxTail)
INC rxTail
rxTail = rxTail & $0F
__RAM(regAddr) = temp1
RETURN
Just as we did last time, we can pass the desired
variable address by using the “@” preface. In the Get_Byte
routine, this causes the address of that byte to be saved.
Then the routine compares the value of the tail pointer
(where we will get the byte) to the head pointer (where the
next incoming byte will be saved). If these values are
equal, the buffer is empty and we’ll loop to the top of the
routine until something arrives.
When the buffer isn’t empty, we will move the byte
currently sitting in the tail position to a temporary variable.
As we did with the head pointer in the ISR, we have to
update the position of the tail pointer and force it to stay
within the 0 to 15 range of valid buffer addresses. Finally,
we move the serial byte (sitting in temp1) to the variable
specified by the caller by using the system __RAM()
address. This is new in SX/B version 1.1 and makes it easy
to modify or retrieve any SX RAM address.
Once we have the header, we will grab the command
byte and then jump to a routine that takes care of any data
or processing required by the command.
Get_Cmd:
GOSUB Get_Byte, @cmd
IF cmd = “R” THEN Do_Reset
IF cmd = “C” THEN Do_Config
IF cmd = “X” THEN Do_Blanking
IF cmd = “W” THEN Do_Write
IF cmd = “B” THEN Do_Block
IF cmd = “<” THEN Do_ShiftL
IF cmd = “>” THEN Do_ShiftR
GOTO Main
To some, this structure may look a bit clunky, but
keep in mind that SX/B is designed to be very close
to assembly language. This lets the code compile very
cleanly and, more importantly, it lets us learn from the
compiled code. In many instances, you’ll see that there is
a one-to-one relationship between SX/B instructions and
SX instructions. SX/B is built for speed.
Let’s have a look at the valid instructions, starting with
“R” for reset. The purpose of this command is to clear the
serial buffer, clear the display buffer, and set the display
mode for each column.
81