Set up a region of memory to contain segment on/off information for the TEC-1's 6 7-segment displays. Write a routine to send this information to the TEC-1's displays by rapidly scanning the displays one at a time, activating each display for a short time before moving on to the next display. To create the illusion that all 6 displays are being lit simultaneously, this scan process needs to happen faster than the human eye can perceive.
The TEC-1 controls its display using latches on two ports: the lower 6 bits (bits 0 - 5) of port 1 controls which digit of the 6 7-segment displays is illuminated. A 1 in bit 0 and all zeros in the other 5 illuminates the rightmost digit.
Bit | digit | selector |
---|---|---|
0 | digit 0 | #01 |
1 | digit 1 | #02 |
2 | digit 2 | #04 |
3 | digit 3 | #08 |
4 | digit 4 | #10 |
5 | digit 5 | #20 |
6 | serial | #40 |
7 | speaker / LED | #80 |
One complication is that the bit-banged serial used by MINT on some hardware configurations need bit 6 (#40) to be kept high during the scanning so that random noise isn't transmitted to the serial terminal.
The eight bits of port 2 control the segments which are illuminated according to the scheme below:
Bit | segment | desc |
---|---|---|
0 | a | top |
1 | f | top left |
2 | g | middle |
3 | b | top right |
4 | dp | point |
5 | c | bottom right |
6 | e | bottom left |
7 | d | bottom |
The first step is to declare a buffer of 6 bytes and initialise them all to zero (off). The easiest way to that is to do that is to declare a 6 item byte array full of zeroes.
\[0 0 0 0 0 0] ' b!
\[
indicates that the numbers following are byte values which will be stored in a byte array allocated on the heap.0 0 0 0 0 0
is 6 literal zeros to initialise the array]
indicates the end of the array. This pushes the address of the array on to the stack followed by its length in bytes.'
we don't actually need this length so we can drop it.b!
we store the address of the array in the variableb
so we can access it later.
Write a command which takes the segment data for a digit and a byte which selects the digit. Update the hardware display ports with this data.
\\ selector segments --
:A 2\> #40| 1\> 10() #40 1\> ;
Where:
:A
declare a command calledA
2\>
outputsegments
data to port 2#40|
ensure that bit 6 of theselector
byte is high1\>
output selector info to port 110()
delay for about half a millisecond#40 1\>
turn off all segments, leave bit 6 high;
end of command
Write a command which scans the buffer to the display
:B #20 b@ 6( %% \@ A 1+ $}$ ) '' ;
Where:
:B
declare a command calledB
#20
initial selector value, the hex value #20 selects the leftmost digitb@
get the address of the start of the display buffer6(
loop 6 times, once for each of the 6 digits%%
duplicate the top two itemsselector
andaddress
\@
read segments data fromaddress
A
call A withselector
and segments data1+
increaseaddress
to point to the next digit in buffer$}$
swap top two items so thatselector
is on top, shift right 1 bit and swap back)
end of loop''
drop the top two items;
end of command
:C b@ 6( #FF % \! 1+ ) ' 1000(B) ;
Where:
-
:C
declare a command calledC
-
b@
get the address of the start of the display buffer -
6(
loop 6 times, once for each of the 6 digits -
#FF
segment data to display8.
-
%
copy address to top of stack. Top two items aresegments
andaddress
-
\!
writesegments
data toaddress
, consumes both -
1+
increaseaddress
to point to the next digit in buffer -
)
end of loop -
'
drop the top item -
1000(B)
scan the display for about 10 seconds (on a 4MHz Z80) -
;
end of command\[0 0 0 0 0 0] ' b! :A 2\> #40| 1\> 10() #40 1\> ; :B #20 b@ 6( %% \@ A 1+ $}$ ) '' ; :C b@ 6( #FF % \! 1+ ) ' 1000(B) ;
Run code with command C
To write out the numbers we need to look up their segment data in a table.
\\ number -- segments
\[#EB #28 #CD #AD #2E #A7 #E7 #29 #EF #2F #6F #E6 #C3 #EC #C7 #47] ' c!
:E c@ + \@ ;
\[
indicates that the numbers following are byte values which will be stored in a byte array allocated on the heap.#EB #28 #CD
... hexadecimal segment data#EB
is the segment data for0
.]
indicates the end of the array. This pushes the address of the array on the stack followed by its length.'
we don't need the length so we drop it.c!
we store the address of the array in the variablec
so we can access it later.:E
declare a command calledE
c@
get the address of the start of the segments table+
addnumber
to address of segments table\@
get segments data corresponding to number;
end of command
:F b@ 6( \i@E % \! 1+ ) ' 1000(B) ;
-
:F
declare a command calledF
-
b@
get the address of the start of the display buffer -
6(
loop 6 times, once for each of the 6 digits -
\i@E
get loop counter variable and get segment data -
%
copy buffer address to top of stack. Top two items aresegments
andaddress
-
\!
write segments data to buffer address, consume both -
1+
increment address -
)
end of loop -
'
drop the top item -
1000(B)
scan the display for about 10 seconds (on a 4MHz Z80) -
;
end of command\[0 0 0 0 0 0] ' b! :A 2\> #40| 1\> 10() #40 1\> ; :B #20 b@ 6( %% \@ A 1+ $}$ ) '' ; \[#EB #28 #CD #AD #2E #A7 #E7 #29 #EF #2F #6F #E6 #C3 #EC #C7 #47] ' c! :E c@ + \@ ; :F b@ 6( \i@E % \! 1+ ) ' 1000(B) ;
Run code with command F
\\ number address --
:G $ #0F& E $ \! ;
:G
declare a command calledG
$
swap so thatnumber
is on top#0F&
mask bottom 4 bits ofnumber
E
get segments for nibble$
swap so thataddress
is on top\!
write segments data to buffer address;
end of command
\\ number --
:H b@ 3+ 4( %% G 1- $ }}}} $ ) '' ;
:H
declare a command calledH
b@
get the address of the start of the display buffer3+
get address of 3rd digit (we will write segment data for digits 3,4,5 and 6)4(
loop 4 times, once for each of the 4 digits%%
duplicate the top two items of stack:number
andaddress
G
convert the lower 4 bits ofnumber
into segments and store ataddress
, consume both1-
decrement address$
swap so thatnumber
is on top}}}}
shiftnumber
right by 4 bits$
swap so thataddress
is on top)
end of loop''
drop the top two items;
end of command
:I #FFFF( \i@ H 100(B) ) ;
:I
declare a command calledI
#FFFF(
count up from 0 to #FFFF\i@
get loop counter variableH
convert to segments in buffer100(B)
scan the display for about 1 second (on a 4MHz Z80))
end of loop;
end of command
\[0 0 0 0 0 0] ' b!
:A 2\> #40| 1\> 10() #40 1\> ;
:B #20 b@ 6( %% \@ A 1+ $}$ ) '' ;
\[#EB #28 #CD #AD #2E #A7 #E7 #29 #EF #2F #6F #E6 #C3 #EC #C7 #47] ' c!
:E c@ + \@ ;
:G $ #0F& E $ \! ;
:H b@ 3+ 4( %% G 1- $ }}}} $ ) '' ;
:I #FFFF( \i@ H 100(B) ) ;
Run code with command I