ECE 471 LAB 3 FALL 2008 PURPOSE: Fun with I/O Ports, including 7-segment display, using interrupts. EXERCISE: In this lab you will use the 7-segment display and the push buttons for a "memory peek" program. When your program runs, it will display a 4-digit hex value representing a memory location in the 7-segment display. When the PC1 button is pushed, the left two digits will increment, and when the PC0 is pushed, the right two digits will increment. Incrementing will occur at two increments per second as long as a button is pushed; however, whenever the PA0 button is also pressed (at the same time), incrementing will occur at 25 times per second. If the right two digits overflow ($FF --> $00), it should NOT increment the left two digits. Whenever PA0 is pushed without PC0 or PC1 being pressed, then display the double byte value of the memory location now pointed to. Display for as long as PA0 is pressed. When PA0 is released, then return to displaying the address (display the same address again) and loop back for entering a new memory location. Your main program will first initialize the interrupt (see below) and then it will watch the buttons, keep track of addresses and decide what value to display. It will put the current display value in a "mailbox" memory location (global variable). Your interrupt service routine will be in charge of the display. It will be a timer interrupt service routine which is set up to occur every 5 ms. As described below, only one digit of the display is actually lit up at any given time. The routine can work as follows: If we have already displayed the MSD, then reset the "PORTD pattern" to the "rightmost digit" position and reload "TEMPDISP" with the current value to display (from the "mailbox" mentioned above). Now, display the digit represented by the rightmost four bits of TEMPDISP (mask the bits and do a table lookup - display in the position indicated by the current PORTD pattern), then right shift TEMPDISP by four bits (hint: LSRD), and then rotate the PORTD pattern. See below for further information. Writing a one to a bit in PORTB lights up the corresponding segment of an LED digit. Segments are mapped as follows: --A-- --0-- | | | | F B 5 1 |--G--| |--6--| E C 4 2 | | | | --D-- --3-- The first figure shows conventional segment labeling, while the second shows how the bits of PORTB are mapped to the segments. FYI the decimal point is controlled by bit 7. See www.eece.maine.edu/~eason/ece471/sevenseg.txt for a table of digits. There are four digits in the display, so we must use multiplexing in order to display in all four positions. Port D controls which digit is currently being displayed. Use it as follows: If bits 5, 4, 3, and 2 of PORTD are all high, then none of the digits are on. Clearing bit 5 of PORTD lights up the segments of the leftmost digit with the PORTB pattern, clearing bit 4, lights up the 2nd digit with the PORTB pattern and so on. Normally you only bring one of these bits low at a time. Delay 5 ms between displaying each digit. Notes: You must make bits 2,3,4, and 5 of PORTD outputs. Do this by writing ones to the corresponding bit positions of the PORTD Data Direction Register. When a button is pushed, the corresponding port bit goes to zero. The rightmost two DIP switches must be in the up position (OFF) in order for PC1 and PC0 to work. Make your interrupt occur exactly every 5 ms. All timing functions (e.g., address increment) should use this for timing. Hint: put a "counter" in some memory location, let the Timer ISR increment the counter. Reset it in the main code. Your lab notebook should contain this lab sheet, a flowchart or pseudo code of your implementation, and a listing file. Also include anything else you think is important. OUTPUT COMPARE INTERRUPT INITIALIZATION (The following assumes TOC3): 1) Disable global interrupts (check out CLI and SEI instructions) 2) Insert interrupt vector in the jump vector table: Memory $FFE4 contains $00D9, so insert a JMP XXXX instruction at $00D9 (where XXXX is the address of your TOC3 service routine. Note: the opcode for JMP is $7E. 3) Read the current Timer Count from TCNT (pg. 374), add your DELAY to it, and store the result in TOC3 (pg. 409). This defines when you want the next interrupt to occur. 4) Set OC3I bit in TMSK1 to enable TOC3 interrupts (pg. 410). 5) Clear the OC3F bit in TFLG1 to clear any previous interrupt condition. (pg. 410). IMPORTANT!!! Note that you must write a 1 to this bit to clear it! Do not use BSET! See the discussion on page 387. 6) Optional: Write to OM3 and OL3 bits in TCTL1 register to define how the OC3 output pin will behave when the interrupt occurs (pg. 412). 7) Enable global interrupts. TOC3 SERVICE ROUTINE: 1) Define when the next interrupt should occur by adding your DELAY to TOC3. 2) Display the next digit. 3) Optionally increment some global counter for use in main program timing. 4) Clear the OC3F bit in TFLG1 to clear the interrupt condition (SEE ABOVE). 5) Return from interrupt when done (pg. 181).