• No results found

MICROCONTROLLER-DRIVEN DATA DISPLAY

A.R. KARKARE

T

his project shows as to how you can use the Atmel microcontroller AT89C51 to drive an LCD display module and in turn use it as a handheld device to set the parameters of a control unit through RS-232 serial link.

Figs 1 and 2 show the circuits of a microcontroller-driven control unit and microcontroller-driven remote handheld

device comprising LCD module, respec-tively. The circuit around IC1 (IC AT89C51) is configured as a control unit, while the circuit around IC2 (another IC AT89C51) is configured as the LCD driver unit. The two units are connected via an RS-232 serial link. The combination of an 8.2k resistor (R) and a 10μF capacitor (C) provides hardware power-on-reset to IC1 and IC2 at their pin 9. A 11.059MHz crys-tal is connected between pins 18 and 19 of microcontrollers IC1 and IC2 each to generate the required clock and baud rate of 9600.

Eight LEDs are connected to pins 39 (P0.0) through 32 (P0.7) of IC1, so we can see the status of each pin of port 0. Txd (pin 11) and Rxd (pin 10) are used to transmit and receive serial data through IC MAX232. IC3 and IC4 (MAX232) serve the pur-pose of linking the microcontrollers. Pin 14 (T1 OUT) of IC3 is connected to pin 13 (R1 IN) of IC4 and vice versa. The control unit contains the program

‘contr.asm’ to send and re-ceive data to the handheld device (LCD module).

IC2 contains the program ‘module.asm’ to drive the LCD. A 16-character x 4-row LCD dis-play is used to disdis-play the day-month-year. The LCD module is interfaced through 8-bit data bus of IC2 on its port 2 (pins 21 through 28). These pins are pulled high through the 10k resistor network. Internal registers of the LCD module are selected by pin 1 (P1.0) of IC2. The Write and Chip-Enable signals of LCD module are connected to pins 2 (P1.1) and 3 (P1.2) of

IC2, respectively.

Backlight current (intensity) is con-trolled through series resistor R12 at pin 16 of the LCD module. The contrast and viewing angle are controlled through pre-set VR1 at pin 3 of the LCD module.

Four pins of port 1 (pins 4 through 7) are used to sense which key has been pressed. The keys are Esc, Ok, Up, and Down. Usually, pins 4 through 7 are held high through 4.7k resistors, but any of the pins can be pulled down using the corresponding switches S1 through S4.

RS-232 link between the two circuits serves the purpose of transferring serial data from one microcontroller to the other.

It is assumed that the control unit has some basic data, say, someone’s birthday,

PARTS LIST Semiconductors:

IC1, IC2 - AT89C51 microcontroller IC3, IC4 - MAX232, RS-232 level

converter

LCD module - 16-character×4-line type LED1-LED8 - Red LED

Resistors (all ¼-watt, ±5% carbon, unless stated otherwise):

R1-R8 - 1-kilo-ohm R9, R10 - 8.2-kilo-ohm R11-R14 - 4.7-kilo-ohm R15 - 5-kilo-ohm

R16 - 18-ohm

RNW1 - 10-kilo-ohm×8 *SIL9 resistor network RNW2 - 4.7-kilo-ohm×4 SIL5

resistor network VR1 - 5-kilo-ohm preset (Note. *Serial-in-line 9-pin resistor, where pin 1 is a common pin.)

Capacitors:

C1-C5,

C9-C13 - 1μF, 10V electrolytic C6, C7,

C14, C15 - 22pF ceramic disk C8, C16 - 10μF, 10V electrolytic Miscellaneous:

XTAL1, XTAL2 - 11.059MHz

S1-S4 - Push-to-on tactile switch Con-1 - 9-pin ‘D’ female connector Con-2 - 9-pin ‘D’ male connector

stored in it. The day, month, and the year data are stored at 30H, 31H, and 32H RAM locations, respectively.

When the remote handheld device (LCD module) is connected to the control unit through RS-232 link (IC MAX232), IC2 is reset to start functioning. The data stored in the control unit is displayed on the LCD screen. The user can then select the data (day, month or year). To change the data, in-crement or dein-crement it using Up or Down key, and then trans-fer the data back to the control unit.

Software

In the beginning section of the assembly file (refer Fig. 3 and the module.lst file), RAM locations are reserved for saving various variables such as the day’s units and tens digits.

One location (45H) has been defined for sensing the flag to find whether serial port has been interrupted or not. Port pins connected to pins 4 through 6 of the LCD module are defined as

‘rs’, ‘rw’, and ‘en’. Keys Esc, Ok, Up, and Down are defined as Port 1, which are connected to pins 4 through 7 of IC2, respectively.

The main program starts at location 0000H, while a jump

in-struction has been set at location 0023H for the serial port interrupt service routine (ISR). Whenever the serial port is interrupted, the program is automatically branched to location 0023H.

Start. The main program starts at location 0030H. Initially the stack pointer is initialised to some safe location where it will not get disturbed by normal routines of the program. Timer 1 is set as a NOT-gated timer for 8-bit auto-reload function mode. The reload value of timer 1 is set for generating a baud rate of 9600 bits per second. The SCON register is set for Mode 1 operation and is kept ready for reception.

Start timer 1 and set the required in-terrupt request bits as enabled. The inter-rupt flag is kept cleared to start. Now pro-ceed as per the flowchart shown in Fig. 3.

A few steps after the ‘clr intflg’

in-structions and before step1 are for initialising the LCD module.

Step 1. Screen 1, screen 2, etc to be displayed on the LCD module are pre-defined as scr1, scr2, etc at respective locations. As the program enters step 1, it first sets the data pointer to point at the first screen to be displayed. The setup subroutine displays the screen.

The first screen displayed is a welcome massage. The program waits for the user to press Ok key to come out from the welcome screen display. When the user presses Ok key, the program control passes to Step 2.

Step 2. The program now displays the birthday screen, indicating day, month, and year. A small arrow pointer (>) indicator gets added at LCD location C0H, so the arrow points at ‘day’, indicating that the parameter ‘day’ is being selected.

The first character of each line on the LCD module has a unique address: The first character of first, second, third, and fourth lines has address as 80H, C0H, 90H, and D0H, respectively.

As the program executes the add_day, add_month, and add_year subroutines, the day, month, and year data is retrieved from the master IC 89C51 (IC1), converted into proper ASCII format, and saved at LCD locations. The display now shows the day, month, and year also on the LCD screen.

If the user wishes to select month or year, he needs to press Down key and shift the arrow pointer to the required selection place. On pressing Down key, the arrow pointer shifts down.

Similarly, on pressing Up key, the ar-row pointer shifts up. This way the user can select the parameter he wishes to Fig. 2: Handheld unit comprising LCD module

change. In case no parameter is to be se-lected, by simply pressing Esc key, the user can go back to Step 1, which is the welcome screen. Once the user has se-lected the parameter, pressing Ok key takes the program to the next step.

Step 3. Here the screen displays all the birthday characters, except the arrow has been shifted to indicate month.

Step 4. Here also the screen displays all the birthday characters, except the ar-row has been shifted to indicate year.

Step 5. Depending upon the user’s selection of day or month or year, the program branches to Step 5 or Step 6 or Step 7, where the screen displays ‘set day’

or ‘set month’ or ‘set year’, respectively.

On screen 5, the LCD displays ‘set day’. The day then gets added on the screen. At key5 label, the program checks, which key is pressed. As long as no key is pressed, the program keeps looping back to key5 label.

When the user presses Up key, the parameter increments, as the ‘advance day’ and ‘display day’ subroutines are called in. Similarly, by pressing Down key, the parameter decrements.

During the ‘advance day’ subroutine, the program first checks whether the day is already 31. If so, it resets the day to 01, and doesn’t allow it to increment to 32.

Similarly, the month doesn’t go beyond 12 and the year doesn’t go beyond 99.

However, if the user is decrementing the day parameter, the program first checks whether the day is already 01. If so, it resets the day to 31, the month to 12, and the year to 99.

Whenever the desired value of the day is seen on the screen, pressing Ok key takes the program to transfer the day data to the master IC 89C51 (IC1). The trfr_day subroutine transfers the value to the ap-propriate RAM location in the control unit and returns to the step2 screen.

Steps 6 and 7 are similar to Step 5.

As soon as the control unit of IC1 sends some data to the serial port, the serial interrupt at location 0023H gets activated and the program control is passed to the serial port by the spint ISR (serial port interrupt program).

spint subroutine. First, all the inter-rupts are disabled, since we do not want any interrupt while serving this subrou-tine. Pushing the program status word (psw) on the stack saves any useful infor-mation on the psw and accumulator. The sbuf register is then read and the same is stored at register B. ‘ri’ bit is then cleared for receiving the next character; flag is set to indicate the interrupt had occurred, and finally the program returns from the

subroutine.

Send subroutine. The program first disables all the interrupts and clears the transmission completion flag. Then it loads the buffer register to start the transmission from IC2 to the control unit (IC1). As long as ‘ti’ bit remains low, we need to wait. When the transmission is over, ‘ti’ bit goes high. The program then enables the interrupt and returns to the main control.

Setup subroutine. The program first sets the address pointer (register r2) to the first-line, first-column position (80H) of the LCD. It writes this address to the LCD using the wi subroutine. The pro-gram then gets the character from the screen data library and writes data to the LCD using the wd subroutine. The setup subroutine displays the character on the LCD screen.

Both the data pointer and the address pointer (register r2) are then incremented.

The program checks whether the first line of LCD has been written. If so, it modifies the address pointer to the second line, which is C0H. Similarly, when the second line is over, the third-line, first-character address is set, and then fourth-line, first-character address is set as address pointer.

Fig. 3: Flowchart of microcontroller-driven data display

wi subroutine.

This subroutine is used for transferring control instructions to the LCD.

It first sets up the LCD for writing instructions (rw=0, en=0, rs=0) and then moves the data to Port 2 (P2.0 through P2.7) from the accumulator. It then reads the busy bit at the rdbusy subroutine and waits until the writing process is completed, and finally returns to the main program.

wd subroutine.

This subroutine is used for transferring data to the LCD. It first sets the LCD for writing data (rw=0, en=0, rs=1) and moves data to Port 2 from the accumulator. It then reads the busy bit by the rdbusy subroutine and waits until the writing process is completed, and finally returns to the main program.

rdbusy subrou-tine. This subroutine is used for testing the busy bit during the writing operation to the LCD. It first selects the read set-up for the LCD (rw=1, en=0, rs=0).

Then it sets Port 2-bit 7 (P2.7) and waits until this bit becomes low after successfully writing to the LCD.

Finally, it returns to the main program. is set as a pointer for the control unit where the day information is stored. The send_con subrou-tine gets the data from the address pointer of the control unit. This data is now

directly available in the two-digit ASCII format for the tens and units digits of day. The tens and units digits of the day are stored and then displayed at LCD locations C7H and C8H, resp-ectively. The add_ month and add_year subroutines are similar to the add_day subroutine.

keyprs? subrou-tine. This subroutine checks which key (Esc, Ok, Up, or Down) has been pressed. If no key is pressed, the subrou-tine returns with the accumulator containing FFH. Key switches are connected to Port 1 (P1.3 through P1.6). Pins P1.3 through P1.6 usually remain high until a key is pressed.

If any key is sensed low, the program jumps to confirm whether it was an unin-tentional low or it really happ-ened by keypress. For confirming so, the program waits for the bounce period of 10 millisec-onds and then checks for the low again on the same key.

If the key is not sensed low now, it is assumed to be an accidental low and the subroutine returns as if no key was pressed.

But if the key is sensed low for the second time also, the program accepts the key and waits for the user to release the key in about 300 miliseconds. After 300 miliseconds, even if the user does not re-lease the key, the program repeats the action as if the key is being pressed again and again. The program control returns with a code in the accumulator.

Codes for the keys are:

• ‘01’ for pressing Esc key

• ‘02’ for pressing Ok key

• ‘03’ for pressing Up key

• ‘04’ for pressing Down key

trfr_day subroutine. This subroutine transfers the day data to the appropriate location in the control unit. When this subroutine is called, the data is available as two digits (tens and units) in the ASCII format. As the data needs to be stored at one RAM location in the hex format, the program has to convert the two ASCII digits into a single hex digit by the asci_hex subroutine. At the end of the asci_hex subroutine, an equivalent hex number is available as hex variable.

The program now starts sending the characters. First, start code 02H is sent to the control unit, signaling it to get ready as the data is coming. Second, the ad-dress 30H is sent, where the day data is to be stored. Finally, the hex variable is sent, which is the current day data. The trfr_month and trfr_year are similar subroutines.

Fig. 4: Actual-size, single-side PCB layout for the handheld unit comprising LCD module (above) and the control unit (below)

Fig. 5: Component layout for the PCB shown in Fig. 4

Only the address where the data is to be stored is different in each case.

hex_asci subroutine. First the units and tens digits are reset to ASCII zero.

Then check whether the hex number is already zero. If yes, simply return. Else, advance the units. If the units digit has crossed ASCII 9, we need to reset the units digit to zero and advance the tens digit.

Simultaneously, the hex number has to be decremented. The process keeps repeating until hex number becomes zero. The accu-mulated tens and units are equivalent to the hex number originally loaded.

asci_hex subroutine. Here the process is almost opposite to what we did while converting hex into ASCII. First, the hex number is reset to zero. Then we check whether both the units and tens digits are zero. If so, we simply return.

Otherwise, we have to advance the hex number. Simultaneously, the units and tens digits are to be decremented. The process keeps repeating itself until units and tens digits become zero.

adv_day subroutine. This subroutine advances the day data, but ensures that

it does not go beyond 31. The first part checks whether the day’s units digit is 1 (decimal) and tens digit is 3 (decimal). If so, the program sets the units digit to 1 and the tens digit to 0 before returning.

The second part of the subroutine ad-vances the day’s units digit until it crosses 9 (ASCII 39). After 9, the day’s units digit is reset to 0 and the tens digit is advanced.

Similarly, if the tens digit crosses 9, the program sets it to 0.

dec_day subroutine. This subrou-tine decrements the day value. The first part checks whether the day’s units digit is 1 (decimal) and the tens digit is 0 (deci-mal). If so, the program sets the tens digit to 3 before returning.

In the second part, as the day’s units digit is decremented, the program tests whether it has gone below zero. (When ASCII 30h decrements, it will become ASCII 2fh.) The program sets the units digit to 9 (ASCII 39h) and decrements the tens digit. As the tens digit is decremented, the program tests whether it has gone below zero. If so, the program sets the tens digit to 9.

The adv_month and adv_year tines are similar to the adv_day subrou-tine, and the dec_month and dec_year routines are similar to the dec_day sub-routine.

send_con subroutine. This subroutine first sends the address to the control unit and waits for the interrupt flag to go high.

This means the data from the control unit is to be received at the specified address.

After receiving the data, the interrupt flag gets cleared for the next instruction. The data is received from register B, saved as the hex variable, and converted into the ASCII code that is required for the LCD module.

The actual-size, single-side PCB layout for the handheld unit comprising LCD module and control unit is shown in Fig. 4 and its component layout in Fig. 5.

The combined PCB can be cut along the dotted lines to separate the control unit and handheld unit comprising LCD module.

Note. The software program of module.lst and contr.lst are included in the CD.