Professional Documents
Culture Documents
No. AN9702
February 1997
Harris Digital
Author: Christopher Mazzanti
Operation
This section is divided into two sections: Keypad Scan and LCD Interface. Each of these sections gives an overview of the operation of the hardware and software associated with each type of interface. KEYPAD SCAN INTERFACE The keypad scan interface described in this application note uses the Port B interrupt/pull-up mask option of the CDP68HC05C16B. Before an explanation of the keypad scanning routine, a brief description of these options is detailed. Port B Interrupts and Pullups Note: The Port B interrupts and pull ups described here are in terms of the CDP68HC05C4B, C8B and C16B. Port A interrupts and pull ups on the CDP68HC05J4B function similarly except where noted. In addition to being a standard bidirectional port, each bit of Port B has a mask option to connect a pullup device to the I/O pad and to simultaneously feed the input to the internal interrupt logic. When the mask option is not selected, each Port B pin behaves as a standard bidirectional port pin. When the mask option is selected, a pullup PMOS device with an impedance of approximately 20k is connected between the pad and VDD (see Figure 1B for Pullup Current IIN) and the input signal is inverted and internally ORed with the IRQ signal (refer to Figure 1A). The interrupt behavior of any port B pin which has the pullup/interrupt mask option activated is identical to the results one would achieve by externally ORing (active low) the signal with the IRQ signal.
Copyright
1.0
2.0
3.0
4.0
5.0
6.0
FIGURE 1B. C4B, C8B, C16B P-FET PULL UP DEVICE CHARACTERIZATION CURVE
Port B pull-ups. Once the source of the IRQ has been determined to be a keypress, the next thing to do is to debounce it. This needs to be done because switch bounce (caused by the switch contacts closing, separating and the closing again) can cause the 68HC05 to read the switch during a bounce and incorrectly assume that no key is being pressed. To avoid this we use a 5ms timing delay loop. This delay gives the contacts plenty of time to bounce and settle into position. Now that the keypress has been detected and debounced, the interrupt routine must now gure out which key is being pressed. To do this we read in the column bits and test them sequentially to determine in which column a key is being pressed in. If two keys are being pressed simultaneously, this scan routine will detect the one in the column scanned rst. Once it has been determined which column the key is in, the service routine must now determine which row in that column the key is in, thus giving us the key location. At this point we write 1s to all of the row locations except for the rst one (i.e., row 1 in this case). We then test the column bit where we determined previously that the key being pressed was in. If this line is low, then we have found the key. If not, then we write 1s to all of the row lines except for row 2 and test the column again. In this way we can scan through the keypad and determine the exact location of the keypress. Running at 4MHz, the 68HC05 can scan the keypad much faster than a human can press a key and release it (even with the 5ms debounce delay). If the routine determines that no key is pressed, then it simply returns from the interrupt and continues from where it left off. The IRQ service routine in the assembly listing later in the document details the entire keypad scanning process. LCD INTERFACE Strictly speaking, the interface described here does not connect a 68HC05 with an LCD. To do so would require special control circuitry in the 68HC05 itself and many more I/O lines than are available even with the 40 pin CDP68HC05C16B. Rather, this interface is to the Hitachi LCD driver/display control chip set specically designed for controlling text LCD displays. These chips have become very standard in their interface and are used by many LCD module manufacturers such as Optrex. The LCD unit used for this application note is an Optrex DMC16202. This is a 16 character by 2 line display, although larger displays (in terms of character length and line count) work similarly. The standard LCD interface (as the Hitachi-interface will be referred to from now on) will need a maximum of 14 lines connected to the LCD module - 8 data, 3 control, 2 power and 1 contrast (see the LCD technical information for details on power supply and contrast connections) of which anywhere from 6 to 11 lines will need to be connected to the MCU. Data can be transferred to the LCD in either byte-wide transfers or nibble-wide transfers, but since all text to be displayed on the LCD is encoded in an 8-bit ASCII-like format, choosing four bit operation means that two transfer operations will be needed for every character sent to the LCD. 8bit transfers require more I/O port lines, but they do speed up LCD transfers and make the software interface a bit more
The IRQ service routine is where all of the keypad scanning, debouncing and key identication takes place. In the IRQ service routine, the rst thing that has to be done is to determine the source of the IRQ. If the user code is using the IRQ pin of the MCU to connect to another peripheral (a Harris 65C51 UART for example), the IRQ service routien must determine if the interrupt came from the IRQ pin or from the
PORT I/O 4 PORT B [7:4] PORT B [3:0] 4 68HC05C8B NOTE: IRQ/PULL-UP OPTION ON PORT B [7:4]
LCD RS E R/W
KEYPAD
ROW COLUMN
LCD RS E R/W
DATA [7:4]
1 LINE 1 LINE 2 00 40
2 01 41
3 02 42
4 03 43
5 04 44
6 05 45
7 06 46
13 0C 4C
14 0D 4D
15 0E 4E
RS tAS R/W PWEH E tER tEF tDSW DB0 ~ DB7 VALID DATA tCYCE tH tAH tAH
tER
PWEH
tAH
FIGURE 5A. WRITE OPERATION TABLE 1. TIMING CHART ITEM Enable Cycle Time Enable Pulse Width, High Level Enable Rise and Decay Time Address Setup Time, RS, R/W-E Data Delay Time Data Setup Time Data Hold Time (Write Operation) Data Hold Time (Read Operation) Address Hold Time SYMBOL TCYCE PWEH tEr, tEf tAS tDDR tDSW tH tDHR tAH
MEASURING CONDITION Write, Read Write, Read Write, Read Write, Read Read Write Write Read Write, Read
TYP -
MAX 25 320 -
UNIT ns ns ns ns ns ns ns ns ns
The LCD interface contains a read/write control line that can allow the MCU to read data from the LCD module. Since the characters being displayed each have their own address location within the LCDs display RAM, they can be addressed and read just like any other peripheral RAM. Chances are that most applications will not need to do this. However, being able to read the LCD means that the LCD subroutines can check the status of the LCD busy ag. Each operation the LCD performs takes a certain amount of time to complete. Most of these times are around to 40s range, although some operations can take as long as 1.64ms to complete. With a MCU running at 4MHz, this can be quite a long time. During one of the operations, the LCD ignores all data transmissions until it is done. To avoid sending the LCD data that will be ignored, the MCU must either poll the busy ag by reading a control byte from the LCD or sit in delay loops until the LCD has completed its operation. The second alternative saves an I/O line (the LCD read/write bit would simply be tied low) but does require extra timing loops in the source program that may be unnecessary. Another drawback to using timing loops is that for every write to the LCD, at least 40s of MCU time will be wasted, most of it in unproductive delay loops. If the busy ag is only polled at the beginning of a write sequence, so if the MCU was doing other things between writes to the LCD (as would probably be the case), chances are that the LCD will almost always have time to complete a write cycle. If the LCD is busy when a write starts, then and only then will the 68HC05 wait for the LCD to complete its operation. If the operation is a clear display (or similar) that takes 1.64ms to complete, even more MCU time is wasted if timing loops are
used. Also, there is still the risk that the LCD is not nished with an operation even though the timing loop is nished. Reading the LCD has the drawback of the added I/O line and code complexity, but is assures that the LCD is done with previous operations before being written to. As long as I/O port constraints and code size permit it, we recommend polling the busy ag over timing loops.
7 4 1 0 8 5 2 9 6 3 C /
* +
Software The software routines written for this application note include all of those needed to interface a 4x4 matrix keypad and a 16x2 Optrex LCD display. Included in the assembly listing are all of the subroutines necessary to read data from the LCD, write data to the LCD and scan the keypad. Also included are some higher level subroutines (i.e., they call the LCD read/write routine WLCD and RLCD) to make string display a little easier. The basic function of the main program listed here is to wait for a keypress and display the key that was pressed. The LCD will be cleared and the cursor set to the home position when the C key is hit. Each of the 16 keys on the keypad have been assigned an ASCII value in a setup similar to a calculator keypad (Figure 6). All of the keypad scanning is done in the IRQ interrupt service routine.
Cursor at Home
1.64ms
I/D
40s
Display On/Off
40s
S/C
R/L
40s
DL
40s
CGRAM address set DDRAM address set Busy Flag/ Address Read CG/DDRAM Data Write CG/DDRAM Data Read
CGRAM Address
40s
DDRAM Address
40s
BF
Address Counter (Both DDRAM and CGRAM) Reads the Busy Flag (BF) and address counter contents. Write Data Writes data into DDRAM or CGRAM
40s
40s
Read Data
40s
I/D: 0 = increment, 1 = decrement S: 0 = no shift, 1 = shift display S/C: Display Shift, 1 = Cursor Shift
R/L: 0 = Shift Left, 1= Shift Right DL: 0 = 4-bit, 1 = 8-bit N: 0 = 1 line, 1 = 2 lines
F: 0 = 5x7 dots, 1 = 5x10 dots BF: 0 = LCD ready, 1 = LCD Busy x = dont care
irqIsr - this is the IRQ interrupt service routine and where all of the keypad scanning and key identication takes place. The rst thing that is done here is a delay subroutine called debounce is called. The purpose of this routine is to give the switch contacts enough time to settle so that reads of the keypad wont produce erroneous results. This delay here is set for approximately 5ms (at 4MHz) but can easily be shorted or lengthened to suit different applications. Next, the columns of the keypad are scanned to see in which column the key being pressed is in. Note that this routine relays heavily on the keypad constants dened at the beginning of the assembly listing. Col is dened as the I/O port to which the keypad columns are connected. Likewise, row is the port to which the keypad row lines are connected. row1, row2, col1, etc., are the bits within the row and col ports that those respective keypad lines are connected to. In this way the keypad columns and rows can be moved to different port locations without changing the assembly code. Once the column that the key being pressed is in is identied, its value minus 1 (i.e., column 1 = 0) is stored in the RAM variable colID. Next the rows are scanned.
This is done in a loop where each row line is individually driven low while the others are high and the columns checked for a keypress. When the row that the key is in is identied, its row location is stored in rowID the same way as the column number was stored in colID. Now that the row and column of the key are known, colID and rowID are put together (rowID:colID) to form a unique four bit ID of the key that was pressed (This method can be used to scan keypads up to 16x16). This ID number is then used as an offset into a table (keyTable). The table here simply contains the ASCII values of the keys for display on the LCD. This ASCII value for the key that was pressed is stored in the RAM variable keyData for return to the main routine. The keyFlag variable also has its bit 0 set to indicate to the main program that a keypress has occurred. Before the RTI is issued, this particular routine waits until the key is released. This is done because the key being pressed could interfere with accesses to the LCD and cause false interrupts to be issued. If the keypad does not share I/O ports with another peripheral, this part of the routine can be removed.
$000F = $000F =
;***************************************************************************** ; RAM Variables: The following RAM locations must be allocated for the ; proper use of the LCD and keypad scanning subroutines. ; lcdTemp1-6 - temp storage locations used by WLCD and RLCD. These ; can be used by the main program in between calls. ; ramSub1-4 - used to create a RAM subroutine, used by TXLCD2 only. ; rowID - used as temp storage for row detection in keypad scanning ; colID - used as temp storage for column detection ; scanMask - used to hold scanning mask during keypad scan ; keyFlag - used as keypad status (bit 0 only) ; keyData - used to store key ID from keypad scan routine ;***************************************************************************** 0050 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D $0000 = $0001 = 005E 0180 0180 0181 0182 0184 0185 0188 018B 018E 0190 0193 0195 0197 019A 019C 019F 01A1 01A2 01A5 01A7 01A9 01AB 01AD 01B0 01B2 01B4 01B7 01B9 01BC 9C 9B 125D 4F C73FDF CD0311 CD0230 AE00 CD024C A606 AE07 CD0260 A6C0 CD0277 3F5D 9A waitKey 015DFD break 3F5D B65E A143 2705 CD027B 20F0 clrLine AE0F CD024C A6C0 CD0277 20E4 ldx jsr lda jsr bra #clearMes&$FF txlcd1 #$C0 wclcd waitKey ;clear line 2 ;reposition cursor clr lda cmp beq jsr bra keyFlag keyData #'C' clrLine wdlcd waitKey ;clear keypad flag ;get keypad data ;check for "C" ;if C, clear line 2 ;else write character ;get another key brclr 0,keyFlag,* ;wait for key press section vars, $50 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 ds 1 equ 0 equ 1 ds 1 section code, $180 rsp sei bset clra sta jsr jsr ldx jsr lda ldx jsr lda jsr clr cli
0 1
lcdTemp1 lcdTemp2 lcdTemp3 lcdTemp4 lcdTemp5 lcdTemp6 ramSub1 ramSub2 ramSub3 ramSub4 rowID colID scanMask keyFlag keyin imask keyData
;\ ; | ; | ; | ; | ;/ ;\ ; | ; | ;/ ;\ ; | ; | ; | ; | ; | ;/
These locations are used for temp storage in the LCD subroutines
These locations are used for the LCD subroutine TXLCD2 only
imask,keyFlag option lcdIni kbiIni #msg&$FF txlcd1 #msg2/256 #msg2&$FF txlcd2 #$C0 wclcd keyFlag
;interrupts masked ;set C16B IRQ to edge only ;initialize LCD ;initialize keypad ;send 1st half of lcd message ;send 2nd half of lcd message
colID keyTable,x keyData 0,keyFlag ;use rowID:colID as offset ;get key ID from table ;store to keyData ;set keypress flag
;and quit ;\ ; | ; | ; | ; | ~5ms delay loop ; | for debouncing keypress ; | ; | ; | ;/ ;keypad lookup table
"789/456*123-0.C+"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; **** HEX2ASC **** ; ; This routine converts a hexadecimal number in the low nibble ; ; of ACCA to ASCII for output to the LCD ; ; Calls: None Modified: ACCA ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 0243 0245 0247 0249 024B AB30 A13A 2B02 AB07 81 HEX2ASC ADD CMP BMI ADD RTS #$30 #$3A SKIP #$07
SKIP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; **** TXLCD1 **** ; ; This routine takes the ASCII message pointed to by ; ; mesPage:X and displays it on the LCD. This routine ass; ; umes the entire message in on memory page mesPage. This ; ; routine is smaller than TXLCD2 because it only increments ; ; one value (X) and only uses 1 RAM location (mesPage). The ; ; first byte of the message pointed to should be the control ; ; code for placement of the message in the LCD. The last ; ; byte of the message MUST be $00. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TXLCD1 024C 024E 0251 0253 0254 0257 0259 025B 025D 025F B750 D60600 AD24 mesloop 5C D60600 2704 AD20 20F6 B650 81 incx lda beq bsr bra mesLoopDone lda rts mespage,x mesLoopDone wdlcd mesLoop lcdtemp1 ;increment pointer into message ;get next byte of message ;check for $00 (end of message) ;send byte to LCD as data ;loop until end of message ;restore ACCA sta lda bsr lcdTemp1 mespage,x wclcd ;PRESERVE ACCA AND IX ;get first byte of message ;and use it as control (position LCD)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; **** TXLCD2 **** ; ; This routine takes the ASCII message pointed to by ; ; ACCA:IX and displays it on the LCD. This routine uses ; ; more RAM than TXLCD2 but does have the advantage that the ; ; text message can be anywhere in memory. This routine uses ; ; four bytes of memory (in addition to temp locations) and ; ; is slighly longer than TXLCD1. The first byte of the ; ; message pointed to should be the control code for place; ; ment of the message in the LCD. The last byte of the ; ; message MUST be $00. ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TXLCD2 0260 0262 0264 0266 0268 026A 026C 026E 0270 0272 B757 BF58 BD56 AD0F mesloop2 3C58 2602 3C57 noIncHi BD56 2704 AD07 jsr beq bsr ramSub1 mesLoopDone2 wdlcd ;get next byte on message ;check for end of message ($00) ;if not end, write data to LCD inc bne inc ramSub3 noIncHi ramSub2 ;increment message pointer low byte ;ckeck for overflow, increment high byte of ;necessary sta stx jsr bsr ramSub2 ramSub3 ramSub1 wclcd ;store ACCA and IX for subroutine jump ;use ram subroutine to get byte ;position LCD
10
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; **** WCLCD **** ; ; This routine takes the contents of ACCA and writes it to ; ; the LCD as a conrtol byte. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 0277 0279 1F02 2002 WCLCD BCLR BRA RS,LCDCTL WLCD ;Pull RS line low for control ;byte write
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; **** WDLCD **** ; ; This routine takes the contents of ACCA and writes it to ; ; the LCD as a data byte. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 027B 1E02 WDLCD BSET rs,LCDCTL ;Pull RS line high for data byte write
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; **** WLCD **** ; ; This subroutine takes the contents of ACCA and writes it ; ; to the LCD. This routine polls the LCD busy flag and ; ; waits until it is low before writing to the LCD. This ; ; This routine does NOT control the RS bit of the LCD, so ; ; the contents of ACCA may be either display data or ; ; control data. This routine has a conditional assembly ; ; flag "4bit" that controls the LCD interface length. If ; ; the 4 bit interface is chosen, data is transfered on the ; ; low nibble of the port. ; ; RAM used: ; ; lcdTemp2 - byte to send ; ; lcdTemp3 - RS preserved for RCLCD call ; ; lcdTemp4 - preserved LCD port data ; ; lcdTemp5 - preserved LCD DDR port data ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
WLCD 027D 027F 0281 0283 0285 0287 0289 028B 028D 028F 0291 0293 0295 0297 TRUE 0299 029B 029D 029F 02A1 02A3 02A5 02A7 02A9 02AB 02AC 02AD 02AE 02AF FALSE B751 B602 A480 B752 waitLcd AD47 A580 26FA B652 BA02 B702 B606 B754 1D02 1B02 #if 4bit B602 A4F0 B753 AA0F B702 B606 AA0F B706 B651 44 44 44 44 BB53 #else #endif B702 1A02 9D 1B02 sta bset NOP bclr lcd e,lcdctl e,lcdctl ;port data and store to LCD i/o port ;raise E strobe to LCD ;timing delay for 2us pulse width ;lower E strobe lda and sta ora sta lda ora sta lda lsra lsra lsra lsra add lcd #$F0 lcdTemp4 #$0F lcd lcd+4 #$0F lcd+4 lcdTemp2 ;get current port data ;and preserve in RAM ;make IRQ bits high before setting DDRs ;to avoid false interrupts bsr bit bne lda ora sta lda sta bclr bclr rclcd #$80 waitLcd lcdTemp3 lcdctl lcdctl lcd+4 lcdTemp5 rw,lcdctl E,lcdctl ;read control bit of the LCD ;to make sure no internal write ;operation is going on. Loop until ;busy flag is clear ;\ ; |-restore state of RS bit ;/ sta lda and sta lcdTemp2 lcdctl #2!rs lcdTemp3 ;save data byte in ACCA ;save state of RS bit
;make lower nibble of LCD port output ;get data byte stored previously ;shift upper nibble to lower nibble, ;fill rest with 0's.
lcdTemp4
11
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; **** RCLCD **** ; ; This routine reads a byte from the LCD as a control byte ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RCLCD 02CE 02D0 1F02 2002 bclr bra rs,lcdctl rlcd
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; **** RDLCD **** ; ; This routine reads a byte from the LCD as a control byte ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RDLCD 02D2 1E02 bset rs,lcdctl
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; **** RLCD **** ; ; This subroutine reads a byte from the LCD module and re- ; ; turns it in ACCA. This routine does not control the RS ; ; bit of the LCD module, this should be done by either ; ; RCLCD or RDLCD. This routine has a conditional assembly ; ; flag "4bit" that controls the LCD interface length. If ; ; the 4 bit interface is chosen, data is transfered on the ; ; low nibble of the port. ; ; RAM used ; ; lcdTemp4 - preserved LCD port data ; ; lcdTemp5 - preserved LCD DDR data ; ; lcdTemp6 - temp store LCD read ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RLCD 02D4 02D5 02D7 02D9 02DB 02DD 02DF 9B B606 B754 1C02 1B02 B602 B753 sei lda sta bset bclr lda sta lcd+4 lcdTemp5 rw,lcdctl E,lcdctl lcd lcdTemp4 ;mask interrupts (need only if LCD port ;has interruptable pins on it) ;\ preserve LCD DDR port ;/ ;set LCD for read operation ;lower E
TRUE 02E1 02E3 02E5 02E7 02E9 02EA 02EC 02EE 02F0 02F1 02F2 02F3 02F4 02F6 02F8 02FA 02FC 02FE 0300 FALSE 0302
#if 4bit B606 A4F0 B706 1A02 9D B602 A40F 1B02 48 48 48 48 1A02 B755 B602 A40F 1B02 BB55 B755 #else #endif B653 lda lcdTemp4 lda and sta bset nop lda and bclr lsla lsla lsla lsla bset sta lda and bclr add sta lcd+4 #$F0 lcd+4 E,lcdCtl lcd #$0F E,lcdCtl ;make lcd port input ;make LCD port input ;raise strobe for data ;delay ;get high nibble ;mask and shift ;lower strobe
;first nibble read, get 2nd ;store high nibble ;get low nibble ;lower strobe ;put nibbles together
12
0600 0600 0604 0607 060B 060F 0613 0617 061B 061F 3FF4 3FF4 3FF6 3FF8 3FFA 3FFC 3FFE
80507265 msg 737300 85206120 msg2 6B657900 C0202020 clearMes 20202020 20202020 20202020 202000
;message page
",$00
13