1
Programming Hints
Blinking Characters
Frank C. Jones
Make your messages stand out by having them blink. The technique is easy and simple to add to your programs. Once the machine language routine is POKEd into memory, the BASIC program can be removed—leaving the machine language there to do the work necessary for "Blinking Characters."

The inverse video key on the Atari computer allows messages to be displayed in inverse video for special emphasis or eye-catching effects. Another, sometimes even more dramatic, method of catching the viewer's eye is to have the message flash on and off, or blink. There is no simple command in Atari BASIC to produce this effect, but the key to producing it lies in the register, maintained by the operating system, called CHACT, decimal address 755 ($253). If bit one in this register is set to one, inverse video characters are displayed in inverse video; if it is set to zero, they are displayed normally. However, if bit zero is set to one, these characters are displayed as blank spaces (inverse video or normal blanks depending on bit one).

Look for a Faster Solution

With this information we can immediately write a program that will produce blinking characters on the screen, as Program 1 does. The trouble with this approach is that our BASIC program is completely preoccupied with timing loops and toggling bit zero of CHACT. If we try to incorporate this routine in a program that does anything else, the timing gets very difficult if not downright impossible. What we really want is a routine that will sit in the background and toggle bit zero of CHACT on a regular basis without interfering with any BASIC program that might be running at the time. Fortunately, the Atari has in it the resources we need to do just this.

The Atari operating system maintains five separate timers that are incremented or decremented during every vertical blank period (the period between successive TV picture frames during which the screen is dark). Actually, most of them are updated only during a "second stage" vertical blank; more about this in a moment. One of these, called CDTMV2 ($21A), is a two-byte down counter that can be set to any value between 1 and 65535. Every sixtieth of a second, during a vertical blank, the operating system reduces this number by one, and when it counts to zero it performs a subroutine jump to the address that it finds in the two-byte vector called CDTMA2 ($228) and returns to the operating system, waiting for the next time the counter counts down to zero.

Program 2 achieves this result by POKEing a machine language program into memory starting at the middle of page 6, location 1664 ($680), and transferring control to it via the USR function. We use the upper half of page 6 because the lower half can be overwritten if an INPUT command recieves 128 or more bytes at one time.

Analysis of the Program

Program 3 is the machine language version of the program that does all the work. After setting up the equates that identify the various registers in lines 20-40 and starting the assembly at location $680 in line 50, we get down to setting ourselves up in business. Lines 80 to 170 pull the three parameters passed by the USR function off the stack and store them in the spaces we reserved for them in lines 260, 270, and 280. We will discuss these parameters further when we reach the points where they are used.

Lines 190 to 220 store the address of our routine that does the actual blinking in the two-byte vector CDRMA2 in the usual low-byte, high-byte order. Lines 230 and 240 take the value of the parameter we have called PERIOD and store it in the actual timer location CDTMV2. Since this is the value that is decremented each sixtieth of a second, it is clear that the parameter PERIOD is just what its name suggests: the period, in sixtieths of a second, of the blink. With this final act the USR function has completed its work, so it returns to BASIC with the RTS at line 250.

Lines 260 to 280 are the storage locations of the three parameters PERIOD, MASK, and FLIP; we already have seen the significance of PERIOD. The actual blink routine is simplicity itself. CHACT is loaded into the A register (line 300), the value is ANDed with the bits in MASK (line 310) to eliminate any bits that we do not want, and the remaining bits are exclusively ORed with the bits in FLIP (line 320) and restored in CHACT (line 330). We can now see the significance of the parameters MASK and FLIP: they define the bits of CHACT that we wish to use and toggle.

The routine ends by resetting the timer for the next period (lines 350, 360) and returning to the operating system vertical blank routines. After this, it is ready to wait for PERIOD more vertical blanks and then do it all over again.

The BASIC program that POKEs the machine language into place does not have to remain in memory once it has done its work. It may be removed with a NEW statement, and a different program that uses the blinking characters may be loaded. In fact, the call to the USR function in line 30 of the BASIC program may be eliminated, and a different program may turn on the blinking. Pressing <SYSTEM RESET> will stop the blinking, but another call to USR(1664, PERIOD, MASK, FLIP) will restore it.

You may experiment with the effect of toggling the various bits of CHACT by using different values of MASK and FLIP. Changing MASK to 23 and leaving FLIP at 1 causes the inverse video to remain on during the blanking. If both MASK and FLIP are changed to 3, inverse video is on while the characters are displayed, but the blanks are normal blanks. Setting both parameters to 2 produces an alternation between regular and inverse video that is quite eye-catching. Finally, setting MASK and FLIP to 4 causes an effect that you will just have to see for yourself; I still haven't figured out what this is used for, but it is spectacular. Of course, PERIOD may be set to any value between 1 and 255 that you may wish to vary the rate with which the characters change.

Since "second stage" vertical blank routines are suspended whenever IO is in progress, you will see that the blinking stops during any disk or cassette activity (or anything that uses the serial IO bus for that matter). You can achieve some unique effects with this short program, and I am sure that many novel programs will use this in ways that I have never thought of.


Program 1. Blinking Characters
10 CHACT=755
20 DELAY=200
30 PRINT "HELLO"
40 FOR I=1 TO DELAY:NEXT I
50 POKE CHACT,0
60 FOR I=1 TO DELAY:NEXT I
70 POKE CHACT,1
80 GOTO 40
90 END 

Listing. Blinking Characters.
Download (Saved BASIC) / Download (Listed BASIC)


Program 2. Character Blink Routine
10 FOR I=1664 TO 1718
20 READ B:POKE I,B:NEXT I
30 A=USR(1664,30,1,1)
40 END
50 DATA 104,104,104,141,161,6,104,104,141,162,6,104,104,141,163,6,169,164,141,40,2,169,6,141,41
60 DATA 2,173,161,6,141,26,2,96,0,0,0
70 DATA 173,243,2,45,162,6,77,163,6,141,243,2,173,161,6,141,26,2,96

Listing. Character Blink Routine.
Download (Saved BASIC) / Download (Listed BASIC)


Program 3. Machine Language Version
0010 ;CHARACTER BLINK ROUTINE
0020 CHACT     = $2F3
0030 CDTMV2    = $21A
0040 CDTMA2    = $228
0050           *=$0680
0060 ;PULL PARAMETERS FROM STACK
0070 ;AND STORE THEM
0080           PLA
0090           PLA
0100           PLA
0110           STA PERIOD
0120           PLA
0130           PLA
0140           STA MASK
0150           PLA
0160           PLA
0170           STA FLIP
0180 ;STORE VECTOR TO BLINK ROUTINE
0190           LDA #BLINK&$00FF
0200           STA CDTMA2
0210           LDA #BLINK/256
0220           STA CDTMA2+1
0230           LDA PERIOD
0240           STA CDTMV2
0250           RTS
0260 PERIOD    *=*+1
0270 MASK      *=*+1
0280 FLIP      *=*+1
0290 ;HERE IS THE BLINK ROUTINE
0300 BLINK     LDA CHACT
0310           AND MASK
0320           EOR FLIP
0330           STA CHACT
0340 ;RESET TIMER AND RETURN
0350           LDA PERIOD
0360           STA CDTMV2
0370           RTS

Listing. Machine Language Version.
Download (Saved OBJect) / Download (Listed ASeMbly)


Return to Table of Contents | Previous Section | Next Section