ENGSCI 232 Computer Systems 1 Lab 5: Parallel Port Software Interfacing Laboratory Your name: _________________ ID: ____________ Introduction This laboratory aims to demonstrate simple interfacing with the parallel port on a PC. Due Wednesday 21 Sept 9am The questions on this handout should be completed during the lab. Listings of the code you write, along with answers to the questions on this handout, should be handed in at the start of the next lab. You should have your code running to be checked off at the start of the next lab. You should aim to spend no more than 1 hour working on this outside lab time. Team Work You will be working in pairs in this lab. You can choose your own pairs. You should hand in your own answers to the questions on this handout, but may hand in joint code listings completed together (with both your names at the top). Hand in just one copy of the code. Warning This lab gives you the power to severely damage your computer, the I/O board, and the power supply units. Please be careful! Parallel Port The parallel port (also known as LPT, or LPT1) connects the computer to the physical world Parallel port pin-outs. The unlabelled pins through a 25-pin connector (right). This interface are ground (0 volts). From http://206.19.206.56/ has 8 output lines (D0…D7), and 4 input lines (S4, To PC Parallel Port S5, S6, S7 ), plus some extra lines we won’t use. Each output line DC In can be set to 0 volts or to 5 volts by setting the value of a particular bit in the computer to be either 0 or 1. The voltage (0 or 5V) at each Parallel port connector input pin can be determined by reading a bit inside the computer. power To help protect the computer from damage, we don’t wire things directly into the parallel port, but use an interface board which makes the input and output lines easy to connect to. We will refer to this board as the ‘Parallel Port Input/Output Board’, or ‘I/O Board’ for short. The board’s Out0…Out7 connectors are wired to the D0…D7 pins, while In4..In7 connect to S4, S5, S6, S7 . The board uses LEDs to show what is happening on the output lines (On=+5V, off =0V). The input lines are normally at 0 volts, but can be ‘pulled up’ to 5 volts by the user (by connecting the input line to a 5 volt supply, or pushing one of the input buttons.) Page 1 Out 0 Out 1 Out 2 Out 3 Out 4 Out 5 Out 6 Out 7 In 7 In 6 In 5 In 4 +5V Gnd o o o o o o o o In7 In6 In5 In4 O O O O input switches I/O Board Version 4.0 To PC Parallel Port DC In First Steps We begin by connecting the I/O board (shown in Figure 1) to its power supply & then the computer. As a general rule, it is safest to make sure the computer and the I/O board are both turned off before they are connected. The I/O board should then be turned on before the computer (and turned off last). However, in this lab we are unlikely to damage anything by connecting things while they are on, so we take this faster option. Parallel port connector power Out 0 Out 1 Out 2 Out 3 Out 4 Out 5 Out 6 Out 7 In 7 In 6 In 5 In 4 +5V Gnd o o o o o o o o In7 O In6 O In5 O In4 O input switches 1/ Turn on your computer, and start it booting up. Logon in the normal way. Figure 1: Breadboard (left) and I/O Board. 2/ There should be a PC parallel cable We use the breadboard later. (thick cable with a wide plug) and a DC power cable (thin cable, small round plug) coming up through your desk. Connect the plug on the DC power cable in to the “DC In” on the I/O Board. 3/ Next, connect the PC parallel cable plug to the I/O board as shown. (If you are doing this at home, note that the cable has male connectors (with protruding pins) that connect to female connectors (with holes) on the back of the computer and on the board. That is, the connector you use on the computer should look the same as the one on the I/O board. (There is another similar male connector on the back of the computer; this one is for the serial port, and should not be used.) 4/ Congratulate yourself on completing your (probably) first computer interfacing exercise! ParMon: Monitoring the Parallel Port The next step is to read and set values on the parallel port. To do this, we read or write values in the computer’s input/output address space. Because the smallest unit the computer works in is bytes (not bits), we will be reading and writing 8-bit numbers (between 0 and 255). All 8 output lines are controlled by putting values into the byte at input/output address 37816, while the voltages at the 4 input lines are determined by reading the byte at address 37916. To make this easy, we use the Parallel Port Monitor program “ParMon 2000”. This allows us to change bits (individual output lines) in the 37816 output, and continuously display the 37916 input.. 1. Run the Parallel Port Monitor (ParMon) program from the Start : The ParMon Program Programs Files : Other menu. 2. Use the small arrows to enlarge the display, and then turn on the Beep option and set the sampling rate to be ‘As fast as possible’. (The beep option may not work on all PCs.) You may also find it useful to choose ‘Always on Top’ option; this will keep this program in front of Excel when we run it. Page 2 Version 4.0 Report Questions What happens when you click on the top 8 red/black buttons on ParMon (shown right). Try a few to see how they work. Be sure to look at the I/O board as you do this, or you may miss something important! Hint: Each time you change a button, a new value is written to the memory location 37816. Explain how each button changes this value, and how the 8 output voltages (and hence what you observe) are related to the value that is written. The top buttons control the outputs. The push buttons on the I/O board change the byte that is read at 37916. ParMon is reading this all the time and showing the value in the “In 379” area. Complete the following to describe the value that is available at 37916. in terms of the 4 values (being 0=0V or 1=5V) at the 4 ‘in’ inputs The inputs as shown ‘In7’, ‘In6’, ‘In5’ and ‘In4’. (Remember, these voltages are normally 0, in Parmon but change to 5V when you push the button.) Note: The slightly strange behaviour can be blamed on IBM engineers making design decisions back in 1981. Their decisions made sense at the time when LPT1 was used for controlling dot matrix printers. Bitwise values: Give a value for each bit, being either 0, 1, or some value expressed in terms of one of inputs In7, In6, etc., where InX=0 (button up) or InX=1 (button down) Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Give a formula for the DataRead value in terms of the 4 inputs In7, In6, In5, & In4. Dataread value (in decimal) = Explain, in terms of the bits in the value being output, how the clock, count, and ripple functions work. (Hint: For the ripple, try watching it when there is just 1 output turned on.) Clock: Count: Ripple: Page 3 Version 4.0 Bit 0 Interfacing with the Parallel Port through VB Now launch Visual Basic 6. We will next write code in VB to interface with the parallel port. A partially completed VB Project file is available on the server in folder “LPT Project” . 1. Find (but do NOT open) the “LPT Project” folder in the ENGSCI232SC course folder under "Teaching". 2. Copy this folder into your own working directory. Do NOT open the original. The LPT1 Project 3. Open your copy of the folder, and double click on the pretty looking Project1 file (not the ugly one!), as shown in the figure (right). This will open up the project in VB to give a screen like that shown below. 4. This project has both a form and a module (named Module1 under Modules in the Project window, right). A module is used to contain code that is required, but doesn't really belong to a form. In our case, this module defines functions and subroutines that we use to access the parallel port. 5. Run this project. You will see its form (shown right) appear. Note that not all the buttons on this form work, yet! 6. Experiment with the "Read from LPT1" and "Write to LPT1" buttons to see how they work. Hint: Try pressing the switches on the I/O Board as you click the "Read from LPT1" button and changing the text box (the one containing 255) to other values before clicking "Write to LPT1". Watching ParMon may also give you clues as to what’s going on. There are a few lines of code that may be new to you… Const LPT1out As Long = &H378 Const LPT1in As Long = &H379 This defines LPT1out as a long integer and gives it the value 378 (in hex). This value is “constant”, ie cannot be changed by the program. This is the ‘address’ where we find the output part of the parallel port in the computers input/output memory. LPT1in works in a similar way. The VB Form lblReadValue = DlPortReadPortUchar(LPT1in) This reads the byte from the parallel port’s input, and puts it’s value (as text) in the “lblReadValue” label on the form. (DlPortReadPortUchar is a function defined in Module1.bas.) DlPortWritePortUchar LPT1out, Value This writes the number in “Value” into the parallel port’s output, thus controlling the voltages on the output connections. 7. Try clicking the "Count Clicks" button, and then pressing the buttons on the IO Board. Page 4 Version 4.0 8. The code listing for this project is shown in Appendix 1. Have a good look though this code to understand how the examples work. Note the names like "cmdCount" used for a button, "lblClickCount" used for a label, and "txtWriteValue" used for an editable text boxes. This naming convection is common in VB, and is required in any code you hand in from now on. This convention can also be applied to integers etc, although this is optional and not required in this course. The details are listed in Appendix 2. Be sure to follow this convention for any buttons, labels, pictures etc you add to the form. Report Exercises Complete the missing subroutines in the project (see listing in Appendix 2), but NOT the reaction timer (we do that later). Each of the buttons is already linked to a subroutine; you just have to fill in the gaps. Be sure to use the logical operators (AND, OR, XOR etc) if they are appropriate. Use compact code; marks will be deducted for doing things the long way. Full marks are reserved for easy-to-read code, ie well documented, properly indented, efficient, descriptive names, using the correct VB naming convention (Appendix 2) for all items on a form, etc. Next week the tutors will check that your code performs the following functions: Count completed (counts from 0 to 255): Echo completed (Each of 4 LEDs on when corresponding switch down): Bounce Completed (1 LED bounces down/up/down/up…): Toggle Completed (Each switch turns 1 LED on/off when the button goes down): Page 5 Version 4.0 Appendix 1: VB Code Listing ' Excel LPT 99 (c) 1999, 2000 A. Mason, Dept of Eng Sci, University of Auckland ' Some modification 1999 by S. Blackett and A. Mason in 2000, 2001, 2002 ' ' This program demonstrates interfacing with the parallel port from VBA. ' It requires dlportio from Scientific Software Tools, Inc. ' Visit www.sstnet.com to download dlportio if the code doesn't run ' Note: We ' frmXXX ' cmdXXX ' lblXXX ' txtXXX use the following naming convention: is a form is a command button is a text label is an editable text box ' Force all variables to be explicitly declared Option Explicit ' Declare the addresses of LPT1 for input and output. ' Note that &h means 'hex' (base 16). A 'Long' is a 32 bit integer Const LPT1out As Long = &H378 Const LPT1in As Long = &H379 '================================================================ ' The following subroutines read or write data entered by the ' user to or from LPT1 '================================================================ Private Sub cmdReadLPT1_Click() ' This macro reads LPT1, and places the byte value in the ' lblReadValue label on the form. ' Note that VB converts the number into text for displaying lblReadValue = DlPortReadPortUchar(LPT1in) End Sub Private Sub cmdWriteLPT1_Click() ' This macro takes the value entered into the txtWriteValue text box ' on the form and writes it to the LPT1 port. ' A beep is generated if the value is ' outside the range 0-255. Dim Value As Integer If Not IsNumeric(txtWriteValue) Then Beep ' user has not entered a number Else Value = txtWriteValue ' Get number out of the form's text box If Value >= 0 And Value <= 255 Then DlPortWritePortUchar LPT1out, Value Else Beep End If End If End Sub Page 6 Version 4.0 '================================================================ ' This subroutine demonstrates timing and counting on LPT1 '================================================================ Private Sub cmdCountClicks_Click() ' This subroutine counts the number of button changes (roughly speaking) ' in 5 seconds. The LPT1 input value and count is displayed on the form. ' It measures 5 seconds by using timeGetTime which returns the number of ' milliseconds since the computer was turned on. ' Note that while our code is running, VB doesn't get a chance to draw any ' changes to labels etc on the screen; we do this ourselves using Refresh. Dim StartTime As Long Dim ClickCount As Integer Dim NewInput As Byte, OldInput As Byte Const CountPeriod As Integer = 5000 ' 5000 milliseconds = 5 seconds MousePointer = vbHourglass ' Show an hour glass to indicate "thinking" ' Set our count so far to zero ClickCount = 0 lblClickCount = ClickCount ' set new value in the count label... lblClickCount.Refresh ' and force the label to redraw itself ' Display and remember the current input OldInput = DlPortReadPortUchar(LPT1in) lblReadValue = OldInput lblReadValue.Refresh ' force the label to redraw itself ' Remember our current time StartTime = timeGetTime ' Keep looping for 5 seconds While timeGetTime < StartTime + CountPeriod ' Read the input from LPT1 NewInput = DlPortReadPortUchar(LPT1in) ' Has it changed? If NewInput <> OldInput Then ' Yes... update count and display new value ClickCount = ClickCount + 1 lblClickCount = ClickCount lblClickCount.Refresh ' force the label to redraw itself ' Display new input value lblReadValue = NewInput lblReadValue.Refresh ' force the label to redraw itself ' and remember this current input OldInput = NewInput End If Wend MousePointer = vbDefault ' Restore the standard mouse pointer End Sub Page 7 Version 4.0 '================================================================ ' TASK 1: Count '================================================================ Private Sub cmdCountUp_Click() ' This subroutine outputs the values from 0 to 255 on LPT1 ' and also shows the LPT1 output value in lblCount using ' lblCount = Value ' lblCount.Refresh ' Unlike ParMon, it always starts at 0, and goes up to 255. ' It waits pauseTime=200 milliseconds between counts using: ' SleepEx pauseTime, 0 ' Press Ctrl-Break to interrupt execution of the subroutine. Const pauseTime As Long = 200 ' the pause between counts, in milliseconds. Dim Value As Integer ' the value we write to the output MousePointer = vbHourglass ' Show an hour glass to indicate "thinking" ' Here's a bit of code for you to start from... it will need changing. ' This code outputs the value 10; you will need to add a loop that changes ' the value being output from 0 to 255 Value = 10 lblCount = Value ' show value on the form lblCount.Refresh ' force label to redraw on the screen DlPortWritePortUchar LPT1out, Value SleepEx pauseTime, 0 ' wait for 200 milliseconds so we can see what's happening MousePointer = vbDefault ' Restore the standard mouse pointer End Sub '================================================================ ' TASK 2: Echo '================================================================ Private Sub ' This code ' is turned ' This code cmdEcho_Click() controls the LEDS so that each of LEDs 4, 5, 6, and 7 on if the corresponding button is down, and off otherwise. runs for 10 seconds Dim StartTime As Long Dim NewInput As Byte, NewOutput As Byte Const CountPeriod As Integer = 10000 ' 10 seconds MousePointer = vbHourglass ' Show an hour glass to indicate "thinking" StartTime = timeGetTime ' Remember our current time Do While timeGetTime < StartTime + CountPeriod ' Keep looping for 10 seconds ' Get new input value NewInput = DlPortReadPortUchar(LPT1in) ' Change the following line to calcuate the new output value ' We want the each light to be on when the button's down, and off when it's up ' Remember one of the buttons is different from the others... NewOutput = 0 ' Output new value to parallel port DlPortWritePortUchar LPT1out, NewOutput Loop MousePointer = vbDefault ' Restore the standard mouse pointer End Sub Page 8 Version 4.0 '================================================================ ' TASK 3: Bounce '================================================================ Private Sub cmdBounce_Click() ' This makes a single LED appear to bounce from top to bottom ' and back again (like the Knight Rider display!) with a ' small pause between steps. It does 20 'down and ups' ' Make sure it doesn't go too fast to see; a wait of ' around 200 milliseconds between changes might be good. Const pauseTime As Long = 200 ' the pause between steps, in milliseconds. ' Show an hour glass to indicate "thinking" MousePointer = vbHourglass ' Your code goes here ' This might be useful SleepEx pauseTime, 0 ' wait for 200 milliseconds so we can see what's happening MousePointer = vbDefault ' Restore the standard mouse pointer End Sub Page 9 Version 4.0 '================================================================ ' TASK 4" Toggle '================================================================ Private Sub cmdToggle_Click() ' This controls the LEDs so that the user can turn on or off ' each of LEDs 4, 5, 6, and 7 using the buttons 4, 5, 6 and 7. ' The user clicks a button (down and then up) once to turn an LED on, and ' then repeats this to turn it off. ' The LED change happens when the button goes down; nothing happens as it come back up ' This code runs for 10 seconds ' The following might be useful ' Old Button State New Button State ' Up Down ' Down Up Action Toggle LED No action required Dim StartTime As Long, OldInput As Byte, NewInput As Byte Dim InputChange As Byte, Output As Byte Const CountPeriod As Integer = 10000 ' 10,000 milliseconds = 10 seconds MousePointer = vbHourglass ' Show an hour glass to indicate "thinking" StartTime = timeGetTime ' Remember our current time ' Turn off all the lights Output = 0 DlPortWritePortUchar LPT1out, Output ' Read the current state of the buttons OldInput = DlPortReadPortUchar(LPT1in) Do While timeGetTime < StartTime + CountPeriod ' Keep looping for 10 seconds ' Get new button input NewInput = DlPortReadPortUchar(LPT1in) ' Change following line to calculate 'InputChange' which determines which ' buttons have changed since last time around the loop. ' Each bit in InputChange is equal to 1 only if the corresponding ' button has changed value since last time. ' The correct answer is one of: ' InputChange = OldInput and NewInput ' InputChange = OldInput or NewInput ' InputChange = OldInput xor NewInput InputChange = 0 ' We want to ignore buttons coming up; things only happen when buttons go down ' Add code in here that resets to zero the bits in any positions ' for which the corresponding button is not currently down. ' As a result of this InputChange will have a 1 in a position only if ' the user has just pushed down the curresponding button. ' We don't care what happens in bits 0, 1, 2, 3. InputChange = 0 ' Calculate the new output value so that the lights change (on to off, ' or off to on) in those positions for which the user has just pushed down ' the button. You only need 1 line of code. ' Use XORs and ANDs to calculate a new Output value from the ' current Output value and the InputChange variable ' We don't care what is output in bits 0, 1, 2, 3. Output = 0 ' Write new output value DlPortWritePortUchar LPT1out, Output ' Remember old button states to use next time around loop OldInput = NewInput Loop MousePointer = vbDefault ' Restore the standard mouse pointer End Sub Page 10 Version 4.0 '================================================================ ' GAME FOR NEXT LAB '================================================================ Private Sub cmdReaction_Click() ' This sub will be used for a game in the next Lab. ' For example it might turn off all the LEDs, wait for ' between 5 and 10 seconds, turn on the LEDs, and ' times how long until a button is pushed. ' The time is then output to lblReactionTime in milliseconds ' Hint: Rnd gets a random number between 0 and 1. MousePointer = vbHourglass ' Show an hour glass to indicate "thinking" MousePointer = vbDefault ' Restore the standard mouse pointer End Sub Page 11 Version 4.0 Appendix 2: The “Hungarian Notation” VB Naming Conventions (from http://www.vbasics.com/dev/conv/naming.htm). Hungarian Notation (HN) is a naming convention invented by Charles Simonyi from Microsoft. The naming conventions found on this page are relatively simplistic compared to other texts on the subject. On the other hand, it is short and simple enough to be easy to remember, implement, and follow on a regular basis. In this course, we won’t use any of the prefixes listed under ‘Variables’. Variables bol byt cur dat dbl dec err int lg obj sng str typ var Boolean Byte Currency Date Double Decimal Error Integer Long Object Single String User Defined Type Variant Form Objects cbo ComboBox chk CheckBox cht Chart cmd Command Button fra Frame img Image lbl Label lin Line lst ListBox opt OptionButton tgl ToggleButton txt TextBox pic Picture Box Common Objects cls Class Module fcls Form Class Module fdlg Form Dialog Box flkp Form Lookup Table frm Form fsub Sub Form mac Macro mod Module rpt Report rsub Sub Report Database Objects cnn Connection db Database fld Field idx Index prm Parameter qapp Append Query qdel Delete Query qdf Query Definition qfrm Query for a form qmak Make Table Query qpt Pass-Through Query qrpt Query for a report qry Query or View rdet Detail Report rpt Report rs Recordset rsub Sub Report srpt Sub Report tbl Table tdf Table Definition trel Relationship Table Note: In addition to the conventions listed below, scope must be considered when naming a variable: When declaring module level variables, add an 'm' to the variable prefix, eg mintMarkTotal. Add a 'g' prefix for global variables, eg gintMaxMark. Page 12 Version 4.0