Timer.Bas

Introduction:

Timer is a GWBasic program that deviates from most of the command line programs that you will likely see.
While it is running, it responds to the FUNCTION KEYS and ignores the keyboard, with the exception of the control C, control BREAK and BREAK keys. The FUNCTION KEYS perform different things, when in the run mode than it does in the immediate mode. The Fn keys respond differently in the RUN mode than in the EDIT mode.
KEY n,function          executes durning the EDIT mode and are shown when KEY ON is in effect.
ON KEY (n) GOSUB     executes durning the RUN mode after the KEY(n) ON statement is declared.

Our program executes a GOTO self where it will continue to spin untile a FUNCTION KEY is closed. This is quite nice; however, it can be a bear for troubleshooting because a typical error mode is for the program to lock up....Very irritating.

This program demonstrates HARD IO, or writing directly to a peripheral device by using the INP and OUT statements. Be careful whild using this method, because unpredictable commands to a perif can really upset the system. For example, the mother board has three timers can can be rattled, but don't mess with the first two.

Timer 0 controls the real time clock and the incorrect count-down will cause the clock to run at the wrong rate.

Timer 1 determines the  refresh rate and if it is wrong, the computer memory will become forgetful and crash.

Timer 2 (the third one) can be connected to the internal speaker to generate a sound. We will use this one.

The function keys permit loading the timer with a desired frequency, turning the speaker on and off directly with hard IO using the INP and OUT statements. They are also used to RUN the program and terminate it.

To learn more about the neat thingys the timer can do, do a web search for the specifications of the 8253 Timer.


What it does:

Run the program as with any other GWBasic program. On initalization, a menu of the four FUNCTION KEY events are displayed. Then the operator is invited to Enter an audio frequency. The program then patiently awaits a FUNCTION KEY closure to perform any one of these four events.

   F1 toggles between program start and program stop. If stopped it will start. If running then it will stop.
   F2 displays the Banner again and prompts for an input frequency, followed by a return.
   F3 turns the speaker on.
   F4 turns the speaker off.
This is all this program does. The next section talks about how GWBasic does it.


How to RUN it:

Start the program as you would start any other GWBasic program.
  Enter some frequency to be sounded.
   Close Key 3 to turn the sound on.
    Close Key 4 to turn the sound off.
     Close Key 2 to change the frequency.
      Close key 3 to turn it on again
       Close key 1 to stop the program......
   Now you did it. The program is terminated and the sound is beeping merrily... and you can't turn it off with the
   FUNCTION KEY because the program isn't running.
      Close Key 1 again to restart the program,
    Close Key 4 to stop the music.
  Exit the program again with another Key 1 closure.
   Now wasn't that fun?


How it does it:

This program uses the FUNCTION KEYs in both the RUN and the IMMEDIATE mode of operation. This causes this program to resemble OOPS programming that is used extensively in Window's programs. The program waits for an event by the operator to perform a function. The computer may be used for other jobs during the wait time.

Interupt driven programs are valuable when a program must detect an event. The program may be doing other things during this wait, as would be the case if the program had to continuously poll the computer status until some trigger event occured. In our program, the only activity we do during that wait is to loop on self at LINE 780. However, other activities could be programmed during this time and will honor the FUNCTION KEY capture whenever it happens. This simple program is designed to demonstrate the programming philosophy.




Provide initial documentation and then vectors off to the program start.
10 '             Prog     timer
20 '
30 '
40 '
50 '
60 '
70 '
80 '
90 '
100 GOTO 650   '_____Branch to Program Start_____


Although un-necessary in this program, it is good practice to code all the sub-routines early on in the program. This permits the program to be less time bound. Each time a sub routine is called, the interpreter must search the code line by line until the sub routine is located. This search can be minimized if the time sensitive programs are early in the program. The four sub routines perform the functions described in the Banner Menu.
110 '
120 '


Simply post intent and exit the RUN mode into the IMMEDIATE mode.
Perhaps emptying the Type-ahead Buffer with INKEY$ commands might be added to swallow any characters typed during the RUN mode. These keystrokes will be executed on entry into the IMMEDIATE mode if present.
130 PRINT "program terminate": END   ' key 1 capture
140 '
150 '


The FUNCTION KEY events are displayed as part of the program BANNER.
160 '  Banner and select frequency   ' key 2 capture
170 CLS:
180 PRINT " Hard I/O to Timer 2"
190 PRINT " F1  Toggles between program RUN and program END"
200 PRINT " F2  Input and load the timer frequency"
210 PRINT " F3  Speaker on"
220 PRINT " F4  Speaker off"
230 '


A prompt to input an audio frequency halts the program until RETURN (ENTER) is typed.
Any invalid number entered will result in a re-prompt.
240 LOCATE 7,1: PRINT SPC(70): LOCATE 7,1
250 INPUT "Enter a frequency  19 to 119380 HZ ",F$
260 F= INT(ABS(VAL(F$))): IF F<19 OR F> 1193180! THEN 910
270 '


The timer clock frequency of 1.193180 HZ is devided by the selected frequency to obtain the down-count required for the counter to generate the selected audio frequency. The value is integerized witn the INT statement to illiminate any fractional component.
280 C= INT(1193180!/F)

The high 256 squared byte value is stored in register HIX for loading into the timer.
290 HIX= INT(C/256)

The high byte value is subtracted from the timer frequency to obtain the low 256 raised to the one, value.
300 LOX= C-(256*HIX)
310 '


The results of the calculations are posted and the program returns to wait for another FUNCTION KEY closure.
320 LOCATE 7,1: PRINT SPC(70): LOCATE 7,1
330 PRINT "Frequency=";F; "    ";
340 PRINT "Timer Counter=";C;"    ";
350 PRINT "hi byte=";HEX$(HIX);"    ";
360 PRINT "lo byte=";HEX$(LOX);"    "
370 RETURN
380 '
390 '
400 '


The load instruction prepares the timer to receive two bytes, the low byte and high byte for the count.
Then the low byte is and then the high byte are loaded into the timer.
Notice the enable is at port address 43 HEX and both bytes are loaded into location 42 HEX
410 '  Load coutdown to timer 02     ' key 3 capture
420 OUT &H43,&HB6    ' input enable
430 OUT &H42,LOX     ' low byte
440 OUT &H42,HIX     ' high byte
450 '
460 '
470 '


The value in the PIA is read, the two least significant bits are forced to 11 and written back out to the PIA.
The 11 (binary) in the lsb connects the timer output to the speaker.
480 '  Turn Speaker on
490 N= INP(&H61)
500 N= N OR 3     ' binary 0000 0011
510 OUT &H61, N
520 RETURN
530 '
540 '


The existing value in the PIA has its two least significant bits set to 00, disconnecting the Speaker from the Timer.
550 '   Turn Speaker off              ' key 4 capture
560 N= INP(&H61)
570 N= N AND 252  ' binary  1111 1100
580 OUT &H61,N
590 RETURN
600 '
610 '
620 '
630 '
640 '


Program environmental initalization followed by a single one line loop that waits for orders.......
650 '      ______ Program Start ______

Turn off the Immediate Mode FUNCTION KEY menu at the bottom of the monitor view-port.
660   KEY OFF

Define a low byte in LOX and high byte in HIX to be loaded into the timer on startup.
    (this step is un-necessary unless you later decide to load and sound a tone on start up)
670   LOX= 54: HIX= 124

KEY(1) is programmed to RUN if used in the IMMEDIATE mode.
680 KEY 1,"run"+CHR$(13)
690 KEY 3,""
700 KEY 4,""


ON KEY(1) through ON KEY(4) are programmed to vector the their respective sub-routines.
Key(1) ON throuth KEY(4) ON enable the FUNCTION KEYs to execute during the RUN mode.
710 ON KEY(1) GOSUB 130: KEY(1) ON
720 ON KEY(2) GOSUB 830: KEY(2) ON
730 ON KEY(3) GOSUB 410: KEY(3) ON
740 ON KEY(4) GOSUB 550: KEY(4) ON


The BANNER sub routine is called to permit the operator to INPUT an audio frequency
and load the TIMER count-down register.
750 GOSUB 160  '  Banner and frequency select
760 '


Post that the program will halt and wait for a FUNCTION KEY closure.
Then it will loop on self in line 770, keeping the program executing.
770 PRINT "            waiting for function key closure"
780 GOTO 780
790 '
800 '
810 '
820 '
830 '
840 '


This is a handy way to periodically save this program during editing, for back-up purposes.
850 '        ______________________________________
860 END        ' Back-up work
870 PRINT "Backing up program": SAVE "timer",A
880 '______________ program end ___________________





Just a note on notes:                 ( Cute Pun on notes....;-)
 
If you are interested in the frequencies of the musical notes, this might help.

440 HZ is the note A below middle C. The frequencies of the notes above this number can be calculated by multiplying successive notes re-cursively to get their frequency. Multiply each successive note by the twelvth root of two to get the next note. For example 440 times the 2^(1/2) ... twelvth root of two... yields Bb. Do the same thing to the frequency of Bb to get B, and so on. Notice that the exponents add during multiplication, so multiplying a number times the twelvth root of two, twelve times will eventually double that number. One octave.

This simple one liner with print out an octave beginning with A below middle C.
A= 440: PRINT A: FOR N= 1 to 12: A= A^( 1/12 ): PRINT A: NEXT N

This one goes down an octave, using minus one twelvth for an exponent because the exponents subtract.
A= 440: PRINT A: FOR N= 1 to 12: A= A^( -1/12 ): PRINT A: NEXT N

_________________________________________________