Sie sind auf Seite 1von 35

LCD Interfacing ...................................................................................................................................

Frequently, an 8051 program must interact with the outside world using input and output devices that communicate directly with a human being. One of the most common devices attached to an 8051 is an LCD display. Some of the most common LCDs connected to the 8051 are 16x2 and 20x2 displays. This means 16 characters per line by 2 lines and 20 characters per line by 2 lines, respectively.

Fortunately, a very popular standard exists which allows us to communicate with the vast majority of LCDs regardless of their manufacturer. The standard is referred to as HD44780U, which refers to the controller chip which receives data from an external source (in this case, the 8051) and communicates directly with the LCD.

AN EXAMPLE HARDWARE CONFIGURATION

LCD Pin descriptions

The LCD discussed in this section has 16 pins. The function of each pin is given in Table.

Pin Symbol I/O 1 2 3 4 5 6 Vss Vcc VEE RS R/W E I/O I I -

Description Ground +5V Power supply Power supply to control Contrast RS = 0 to select command register RS = 1 to select data register R/W = 0 for write, R/W = 1 for read Enable

7 8 9 10 11 12 13 14 15 16

DB0 DB1 DB2 DB3 DB4 DB5 DB6 DB7 LEDLED+

I/O I/O I/O I/O I/O I/O I/O I/O I I

The 8-bit data bus The 8-bit data bus The 8-bit data bus The 8-bit data bus The 8-bit data bus The 8-bit data bus The 8-bit data bus The 8-bit data bus Ground for LED backlight +5v for LED backlight

44780 BACKGROUND

The 44780 standard requires 3 control lines as well as either 4 or 8 I/O lines for the data bus. The user may select whether the LCD is to operate with a 4-bit data bus or an 8-bit data bus. If a 4-bit data bus is used, the LCD will require a total of 7 data lines (3 control lines plus the 4 lines for the data bus). If an 8-bit data bus is used, the LCD will require a total of 11 data lines (3 control lines plus the 8 lines for the data bus).

The three control lines are referred to as EN, RS, and RW.

The EN line is called "Enable." This control line is used to tell the LCD that you are sending it data. To send data to the LCD, your program should first set this line high (1) and then set the other two control lines and/or put data on the data bus. When the other lines are completely ready, bring EN low (0) again. The 1-0 transition tells the 44780 to take the data currently found on the other control lines and on the data bus and to treat it as a command.

The RS line is the "Register Select" line. When RS is low (0), the data is to be treated as a command or special instruction (such as clear screen, position cursor, etc.). When RS is high (1), the data being sent is text data which sould be displayed on the screen. For example, to display the letter "T" on the screen you would set RS high.

The RW line is the "Read/Write" control line. When RW is low (0), the information on the data bus is being written to the LCD. When RW is high (1), the program is effectively querying (or reading) the LCD. Only one instruction ("Get LCD status") is a read command. All others are write commands--so RW will almost always be low.

Finally, the data bus consists of 4 or 8 lines (depending on the mode of operation selected by the user). In the case of an 8-bit data bus, the lines are referred to as DB0, DB1, DB2, DB3, DB4, DB5, DB6, and DB7.

LCD Interfacing

...................................................................................................................................

As we've mentioned, the LCD requires either 8 or 11 I/O lines to communicate with. For the sake of this tutorial, we are going to use an 8-bit data bus--so we'll be using 11 of the 8051's I/O pins to interface with the LCD. Let's draw a sample psuedo-schematic of how the LCD will be connected to the 8051. As you can see, we've established a 1-to-1 relation between a pin on the 8051 and a line on the 44780 LCD. Thus as we write our assembly program to access the LCD, we are going to equate constants to the 8051 ports so that we can refer to the lines by their 44780 name as opposed to P0.1, P0.2, etc. Let's go ahead and write our initial equates: DB0 EQU DB1 EQU DB2 EQU DB3 EQU DB4 EQU DB5 EQU DB6 EQU DB7 EQU EN EQU RS EQU RW EQU DATA EQU P1.0 P1.1 P1.2 P1.3 P1.4 P1.5 P1.6 P1.7 P3.7 P3.6 P3.5 P1

Having established the above equates, we may now refer to our I/O lines by their 44780 name. For example, to set the RW line high (1), we can execute the following instruction: SETB RW HANDLING THE EN CONTROL LINE As we mentioned above, the EN line is used to tell the LCD that you are ready for it to execute an instruction that you've prepared on the data bus and on the other control lines. Note that the EN line must be raised/lowered before/after each instruction sent to the LCD regardless of whether that instruction is read or write, text or instruction. In short, you must always manipulate EN when communicating with the LCD. EN is the LCD's way of knowing that you are talking to it. If you don't raise/lower EN, the LCD doesn't know you're talking to it on the other lines.

Thus, before we interact in any way with the LCD we will always bring the EN line high with the following instruction: SETB EN And once we've finished setting up our instruction with the other control lines and data bus lines, we'll always bring this line back low: CLR EN Programming Tip: The LCD interprets and executes our command at the instant the EN line is brought low. If you never bring EN low, your instruction will never be executed. Additionally, when you bring EN low and the LCD executes your instruction, it requires a certain amount of time to execute the command.
Formatted: Font: (Default) Times New Roman, 13.5 pt, Font color: White

CHECKING THE BUSY STATUS OF THE LCD As previously mentioned, it takes a certain amount of time for each instruction to be executed by the LCD. The delay varies depending on the frequency of the crystal attached to the oscillator input of the 44780 as well as the instruction which is being executed. While it is possible to write code that waits for a specific amount of time to allow the LCD to execute instructions, this method of "waiting" is not very flexible. If the crystal frequency is changed, the software will need to be modified. Additionally, if the LCD itself is changed for another LCD which, although 44780 compatible, requires more time to perform its operations, the program will not work until it is properly modified. A more robust method of programming is to use the "Get LCD Status" command to determine whether the LCD is still busy executing the last instruction received. The "Get LCD Status" command will return to us two tidbits of information; the information that is useful to us right now is found in DB7. In summary, when we issue the "Get LCD Status" command the LCD will immediately raise DB7 if it's still busy executing a command or lower DB7 to indicate that the LCD is no longer occupied. Thus our program can query the LCD until DB7 goes low, indicating the LCD is no longer busy. At that point we are free to continue and send the next command. Since we will use this code every time we send an instruction to the LCD, it is useful to make it a subroutine. Let's write the code: WAIT_LCD:

SETB EN CLR RS SETB RW MOV DATA,#0FFh MOV A,DATA JB ACC.7,WAIT_LCD CLR EN CLR RW RET

;Start LCD command ;It's a command ;It's a read command ;Set all pins to FF initially ;Read the return value ;If bit 7 high, LCD still busy ;Finish the command ;Turn off RW for future commands

Thus, our standard practice will be to send an instruction to the LCD and then call our WAIT_LCD routine to wait until the instruction is completely executed by the LCD. This will assure that our program gives the LCD the time it needs to execute instructions and also makes our program compatible with any LCD, regardless of how fast or slow it is. Programming Tips: The above routines does the job of waiting for the LCD, but were it to be used in a real application a very definite improvement would need to be made: as written, if the LCD never becomes "not busy" the program will effectively "hang," waiting for DB7 to go low. If this never happens, the program will freeze. Of course, this should never happen and won't happen when the hardware is working properly. But in a real application it would be wise to put some kind of time limit on the delay--for example, a maximum of 256 attempts to wait for the busy signal to go low. This would guarantee that even if the LCD hardware fails, the program would not lock up.

INITIALIZING THE LCD


...................................................................................................................................

Before you may really use the LCD, you must initialize and configure it. This is accomplished by sending a number of initialization instructions to the LCD. The first instruction we send must tell the LCD whether we'll be communicating with it with an 8-bit or 4-bit data bus. We also select a 5x8 dot character font. These two options are selected by sending the command 38h to the LCD as a command. As you will recall from the last section, we mentioned that the RS line must be low if we are sending a command to the LCD. Thus, to send this 38h command to the LCD we must execute the following 8051 instructions: SETB EN CLR RS MOV DATA,#38h CLR EN LCALL WAIT_LCD Programming Tip: The LCD command 38h is really the sum of a number of option bits. The instruction itself is the instruction 20h ("Function set"). However, to this we add the values 10h to indicate an 8-bit data bus plus 08h to indicate that the display is a two-line display. We've now sent the first byte of the initialization sequence. The second byte of the initialization sequence is the instruction 0Eh. Thus we must repeat the initialization code from above, but now with the instruction. Thus the next code segment is: SETB EN CLR RS

MOV DATA,#0Eh CLR EN LCALL WAIT_LCD Programming Tip: The command 0Eh is really the instruction 08h plus 04h to turn the LCD on. To that an additional 02h is added in order to turn the cursor on. The last byte we need to send is used to configure additional operational parameters of the LCD. We must send the value 06h. SETB EN CLR RS MOV DATA,#06h CLR EN LCALL WAIT_LCD Programming Tip: The command 06h is really the instruction 04h plus 02h to configure the LCD such that every time we send it a character, the cursor position automatically moves to the right. So, in all, our initialization code is as follows: INIT_LCD: SETB EN CLR RS MOV DATA,#38h CLR EN LCALL WAIT_LCD SETB EN CLR RS MOV DATA,#0Eh CLR EN LCALL WAIT_LCD SETB EN CLR RS MOV DATA,#06h CLR EN LCALL WAIT_LCD RET Having executed this code the LCD will be fully initialized and ready for us to send display data to it.

CLEARING THE DISPLAY

...................................................................................................................................

When the LCD is first initialized, the screen should automatically be cleared by the 44780 controller. However, it's always a good idea to do things yourself so that you can be completely sure that the display is the way you want it. Thus, it's not a bad idea to clear the screen as the very first operation after the LCD has been initialized. An LCD command exists to accomplish this function. Not surprisingly, it is the command 01h. Since clearing the screen is a function we very likely will wish to call more than once, it's a good idea to make it a subroutine:

CLEAR_LCD: SETB EN CLR RS MOV DATA,#01h CLR EN LCALL WAIT_LCD RET How that we've written a "Clear Screen" routine, we may clear the LCD at any time by simply executing an LCALL CLEAR_LCD WRITING TEXT TO THE LCD Now we get to the real meat of what we're trying to do: All this effort is really so we can display text on the LCD. Really, we're pretty much done. Once again, writing text to the LCD is something we'll almost certainly want to do over and over--so let's make it a subroutine. WRITE_TEXT: SETB EN SETB RS MOV DATA,A CLR EN LCALL WAIT_LCD RET The WRITE_TEXT routine that we just wrote will send the character in the accumulator to the LCD which will, in turn, display it. Thus to display text on the LCD all we need to do is load the accumulator with the byte to display and make a call to this routine. Pretty easy, huh?

A "HELLO WORLD" PROGRAM


...................................................................................................................................

Now that we have all the component subroutines written, writing the classic "Hello World" program--which displays the text "Hello World" on the LCD is a relatively trivial matter. Consider: LCALL INIT_LCD LCALL CLEAR_LCD MOV A,#'H' LCALL WRITE_TEXT MOV A,#'E' LCALL WRITE_TEXT MOV A,#'L' LCALL WRITE_TEXT MOV A,#'L' LCALL WRITE_TEXT MOV A,#'O' LCALL WRITE_TEXT MOV A,#' ' LCALL WRITE_TEXT MOV A,#'W' LCALL WRITE_TEXT MOV A,#'O' LCALL WRITE_TEXT MOV A,#'R' LCALL WRITE_TEXT

MOV A,#'L' LCALL WRITE_TEXT MOV A,#'D' LCALL WRITE_TEXT The above "Hello World" program should, when executed, initialize the LCD, clear the LCD screen, and display "Hello World" in the upper left-hand corner of the display. CURSOR POSITIONING The above "Hello World" program is simplistic in the sense that it prints its text in the upper left-hand corner of the screen. However, what if we wanted to display the word "Hello" in the upper left-hand corner but wanted to display the word "World" on the second line at the tenth character? This sounds simple--and actually, it is simple. However, it requires a little more understanding of the design of the LCD. The 44780 contains a certain amount of memory which is assigned to the display. All the text we write to the 44780 is stored in this memory, and the 44780 subsequently reads this memory to display the text on the LCD itself. This memory can be represented with the following "memory map": In the above memory map, the area shaded in blue is the visible display. As you can see, it measures 16 characters per line by 2 lines. The numbers in each box is the memory address that corresponds to that screen position. Thus, the first character in the upper left-hand corner is at address 00h. The following character position (character #2 on the first line) is address 01h, etc. This continues until we reach the 16th character of the first line which is at address 0Fh. However, the first character of line 2, as shown in the memory map, is at address 40h. This means if we write a character to the last position of the first line and then write a second character, the second character will not appear on the second line. That is because the second character will effectively be written to address 10h--but the second line begins at address 40h. Thus we need to send a command to the LCD that tells it to position the cursor on the second line. The "Set Cursor Position" instruction is 80h. To this we must add the address of the location where we wish to position the cursor. In our example, we said we wanted to display "World" on the second line on the tenth character position. Referring again to the memory map, we see that the tenth character position of the second line is address 4Ah. Thus, before writing the word "World" to the LCD, we must send a "Set Cursor Position" instruction--the value of this command will be 80h (the instruction code to position the cursor) plus the address 4Ah. 80h + 4Ah = C4h. Thus sending the command C4h to the LCD will position the cursor on the second line at the tenth character position: SETB EN CLR RS MOV DATA,#0C4h CLR EN LCALL WAIT_LCD The above code will position the cursor on line 2, character 10. To display "Hello" in the upper left-hand corner with the word "World" on the second line at character position 10 just requires us to insert the above code into our existing "Hello World" program. This results in the following:

LCALL INIT_LCD LCALL CLEAR_LCD MOV A,#'H' LCALL WRITE_TEXT MOV A,#'E' LCALL WRITE_TEXT MOV A,#'L' LCALL WRITE_TEXT MOV A,#'L' LCALL WRITE_TEXT MOV A,#'O' LCALL WRITE_TEXT SETB EN CLR RS MOV DATA,#0C4h CLR EN LCALL WAIT_LCD MOV A,#'W' LCALL WRITE_TEXT MOV A,#'O' LCALL WRITE_TEXT MOV A,#'R' LCALL WRITE_TEXT MOV A,#'L' LCALL WRITE_TEXT MOV A,#'D' LCALL WRITE_TEXT

LCD command Codes & Character Code


CodeHex) Command to LCD Instruction Register 1 2 4 5 6 7 8 A C E F 10 14 18 1C 80 C0 38

...

...................................................................................................................................

Clear display screen Return Home Decrement cursor (shift cursor to left) Increment cursor (shift cursor to right) shift display right shift display left Display off, cursor off Display off, cursor on Display on, cursor off Display on, cursor blinking Display on, cursor blinking Shift cursor position to left Shift cursor position to right Shift the entire display to the left Shift the entire display to the right Force cursor to the beginning of 1st line Force cursor to the beginning of 2nd line 2 lines and 5 x 7 matrix

Formatted: Font: (Default) Times New Roman, 13.5 pt, Font color: White

RTC (DS1307) Interfacing with AT89C2051

...................................................................................................................................

Circuit Diagram ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% ; PORT DECLERATION ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% SDA EQU P3.5 ;SDA=PIN5 SCL EQU P3.4 ;SCL=PIN6 DS1307W DS1307R EQU EQU 0D0H 0D1H ; SLAVE ADDRESS 1101 000 + 0 TO WRITE ; SLAVE ADDRESS 1101 000 + 1 TO READ

; ********************************************************** ; Main Program ; ********************************************************** CALL OSC_CONTROL ;Initilize the RTC REPEAT: CALL READ_CLOCK ;Read Clock AJMP REPEAT ; ********************************************************** ; SUB SETS THE DS1307 OSCILLATOR ; **********************************************************

OSC_CONTROL: ACALL SEND_START ; GENERATE START CONDITION MOV A,#DS1307W ; 1101 0000 ADDRESS + WRITE-BIT ACALL SEND_BYTE ; SEND BYTE TO 1307 MOV A,#00H ; ADDRESS BYTE TO REGISTER 00H ACALL SEND_BYTE ; SECONDS REGISTER, ALWAYS LEAVE SETB LASTREAD ; REG 00H-BIT #7 = 0 (LOW) ACALL SEND_STOP ; IF REG 00H-BIT #7 = 1 CLOCK ACALL SEND_START ; OSCILLATOR IS OFF. MOV A,#DS1307R ; 1101 0001 ADDRESS + READ-BIT ACALL SEND_BYTE ; ACALL READ_BYTE ; READ A BYTE FROM THE 1307 CLR ACC.7 ; CLEAR REG 00H-BIT #7 TO ENABLE OSC_SET: ; OSCILLATOR. PUSH ACC ; SAVE ON STACK ACALL SEND_STOP ; ACALL SEND_START ; MOV A,#DS1307W ; SETUP TO WRITE ACALL SEND_BYTE ; MOV A,#00H ; REGISTER 00H ADDRESS ACALL SEND_BYTE ; POP ACC ; GET DATA TO START OSCILLATOR ACALL SEND_BYTE ; SEND IT ACALL SEND_STOP RET ; ********************************************************** ; THIS SUB CONTROLS THE SQW OUTPUT 1HZ ; ********************************************************** SQW_CONTROL_1HZ: LCALL SEND_START ; SEND START CONDITION MOV A,#DS1307W ; SET POINTER TO REG 07H ON ; DS1307 LCALL SEND_BYTE MOV A,#07H LCALL SEND_BYTE MOV A,#90H ; SQW/OUT ON AT 1HZ JNB SQW,SQW_SET ; JUMP IF SQW BIT IS ACTIVE MOV A,#80H ; TURN SQW/OUT OFF OFF HIGH SQW_SET: LCALL SEND_BYTE LCALL SEND_STOP RET ; ********************************************************** ; THIS SUB READS ONE BYTE OF DATA FROM THE DS1307 ; ********************************************************** READ_BYTE: MOV MOV SETB READ_BITS: SCL_HIGH MOV RLC CLR DJNZ JB BITCNT,#08H; SET COUNTER FOR 8-BITS DATA A,#00H SDA ; SET SDA HIGH TO ENSURE LINE ; FREE ; TRANSITION SCL LOW-TO-HIGH C,SDA ; MOVE DATA BIT INTO CARRY A ; ROTATE CARRY-BIT INTO ACC.0 SCL ; TRANSITION SCL HIGH-TO-LOW BITCNT,READ_BITS ; LOOP FOR 8-BITS LASTREAD,ACKN ; CHECK TO SEE IF THIS IS ; THE LAST READ

CLR ACKN: SCL_HIGH CLR RET

SDA

; IF NOT LAST READ SEND ACK-BIT ; PULSE SCL TO TRANSMIT ACKNOWLEDGE ; OR NOT ACKNOWLEDGE BIT

SCL

; ********************************************************** ; SUB SENDS START CONDITION ; ********************************************************** SEND_START: SETB CLR CLR JNB JNB SETB SCL_HIGH CLR ACALL CLR RET FAULT: SETB RET _2W_BUSY ACKS BUS_FLT SCL,FAULT SDA,FAULT SDA SDA DEELAY SCL BUS_FLT ; INDICATE THAT 2-WIRE ; OPERATION IS IN PROGRESS ; CLEAR STATUS FLAGS ; BEGIN START CODITION

; ********************************************************** ; SUB SENDS STOP CONDITION ; ********************************************************** SEND_STOP: CLR SDA SCL_HIGH SETB SDA CLR _2W_BUSY RET ; ********************************************************** ; SUB DELAYS THE BUS ; ********************************************************** DEELAY: NOP ; DELAY FOR BUS TIMING RET ; ********************************************************** ; THIS SUB SENDS 1 BYTE OF DATA TO THE DS1307 ; CALL THIS FOR EACH REGISTER SECONDS TO YEAR ; ACC MUST CONTAIN DATA TO BE SENT TO CLOCK ; ********************************************************** SEND_BYTE: MOV BITCNT,#08H; SET COUNTER FOR 8-BITS SB_LOOP: JNB ACC.7,NOTONE; CHECK TO SEE IF BIT-7 OF SETB SDA ; ACC IS A 1, AND SET SDA HIGH JMP ONE NOTONE: CLR SDA ; CLR SDA LOW ONE: SCL_HIGH ; TRANSITION SCL LOW-TO-HIGH RL A ; ROTATE ACC LEFT 1-BIT CLR SCL ; TRANSITION SCL LOW-TO-HIGH DJNZ BITCNT,SB_LOOP; LOOP FOR 8-BITS SETB SDA ; SET SDA HIGH TO LOOK FOR

SCL_HIGH CLR JNB SETB SB_EX:

; ACKNOWLEDGE PULSE ACKS SDA,SB_EX ACKS ; CHECK FOR ACK OR NOT ACK ; SET ACKNOWLEDGE FLAG FOR ; NOT ACK

CALL DEELAY ; DELAY FOR AN OPERATION CLR SCL ; TRANSITION SCL HIGH-TO-LOW CALL DEELAY ; DELAY FOR AN OPERATION RET ; ********************************************************** ; SUB READS THE CLOCK AND WRITES IT TO THE SCRATCHPAD MEMORY ; ON RETURN FROM HERE DATE & TIME DATA WILL BE STORED IN THE ; DATE & TIME REGISTERS FROM 24H (SECS) TO 2AH (YEAR) ; ALARM SETTINGS IN REGISTERS 2CH(HRS) AND 2DH(MINUTES). ; ********************************************************** READ_CLOCK: MOV R1,#SECS ; SECONDS STORAGE LOCATION MOV BYTECNT,#00H CLR LASTREAD CALL SEND_START MOV A,#DS1307W CALL SEND_BYTE MOV A,#00H CALL SEND_BYTE CALL SEND_STOP CALL SEND_START MOV A,#DS1307R CALL SEND_BYTE READ_LOOP: MOV CJNE SETB A,BYTECNT A,#09H,NOT_LAST LASTREAD

NOT_LAST: CALL READ_BYTE MOV @R1,A MOV A,BYTECNT CJNE A,#00H,NOT_FIRST MOV A,@R1 CLR ACC.7 ; ENSURE OSC BIT=0 (ENABLED) MOV @R1,A NOT_FIRST: INC R1 INC BYTECNT MOV A,BYTECNT CJNE A,#0AH,READ_LOOP CALL SEND_STOP RET ;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&& ;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((( ; STORE THE TIME TO RTC CHIP ;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((( STORE_RTC: LCALL SEND_START ; SEND 2WIRE START CONDITION MOV A,#DS1307W ; LOAD DS1307 WRITE COMMAND

LCALL SEND_BYTE ; SEND WRITE COMMAND MOV A,#01H ; SET DS1307 DATA POINTER TO BEGINNING LCALL SEND_BYTE ; OF 00H MOV A,MINS ; Send min LCALL SEND_BYTE MOV A,HRS ;send hr SETB ACC.6 ;12 HR MODE JNB AMS,YUH CLR ACC.5 ;AM/PM 1=PM,0=AM AJMP YUH1 YUH: SETB ACC.5 YUH1: LCALL SEND_BYTE MOV A,DAY ; Send Day LCALL SEND_BYTE MOV A,DATE1 ; Send date LCALL SEND_BYTE MOV A,MONTH ; Send month LCALL SEND_BYTE MOV A,YEAR ; Send yr LCALL SEND_BYTE LCALL SEND_STOP ; SEND 2WIRE STOP CONTION RET ;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$

RTC (DS1307) Interfacing with AT89C2051 ...................................................................................................................................

Circuit Diagram ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%% ; PORT DECLERATION

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%% SDA SCL EQU EQU P3.5 ;SDA=PIN5 P3.4 ;SCL=PIN6

DS1307W EQU 0D0H DS1307R EQU 0D1H

; SLAVE ADDRESS 1101 000 + 0 TO WRITE ; SLAVE ADDRESS 1101 000 + 1 TO READ

; ********************************************************** ; Main Program ; ********************************************************** CALL OSC_CONTROL REPEAT: CALL READ_CLOCK AJMP REPEAT ;Initilize the RTC ;Read Clock

; ********************************************************** ; SUB SETS THE DS1307 OSCILLATOR ; **********************************************************

OSC_CONTROL: ACALL MOV ACALL MOV ACALL SETB ACALL ACALL MOV SEND_START ; GENERATE START CONDITION A,#DS1307W ; 1101 0000 ADDRESS + WRITE-BIT SEND_BYTE ; SEND BYTE TO 1307 A,#00H ; ADDRESS BYTE TO REGISTER 00H

SEND_BYTE ; SECONDS REGISTER, ALWAYS LEAVE LASTREAD ; REG 00H-BIT #7 = 0 (LOW) SEND_STOP ; IF REG 00H-BIT #7 = 1 CLOCK SEND_START ; OSCILLATOR IS OFF. A,#DS1307R ; 1101 0001 ADDRESS + READ-BIT

ACALL ACALL CLR OSC_SET: PUSH ACALL ACALL MOV ACALL MOV ACALL POP ACALL ACALL RET

SEND_BYTE ; READ_BYTE ; READ A BYTE FROM THE 1307 ACC.7 ; CLEAR REG 00H-BIT #7 TO ENABLE ; OSCILLATOR. ACC ; SAVE ON STACK

SEND_STOP ; SEND_START ; A,#DS1307W ; SETUP TO WRITE SEND_BYTE ; A,#00H ; REGISTER 00H ADDRESS

SEND_BYTE ; ACC ; GET DATA TO START OSCILLATOR

SEND_BYTE ; SEND IT SEND_STOP

; ********************************************************** ; THIS SUB CONTROLS THE SQW OUTPUT 1HZ ; ********************************************************** SQW_CONTROL_1HZ: LCALL SEND_START MOV A,#DS1307W ; DS1307 LCALL SEND_BYTE MOV A,#07H LCALL SEND_BYTE MOV A,#90H JNB SQW,SQW_SET ; SQW/OUT ON AT 1HZ ; JUMP IF SQW BIT IS ACTIVE ; SEND START CONDITION ; SET POINTER TO REG 07H ON

MOV A,#80H SQW_SET: LCALL SEND_BYTE LCALL SEND_STOP RET

; TURN SQW/OUT OFF OFF HIGH

; ********************************************************** ; THIS SUB READS ONE BYTE OF DATA FROM THE DS1307 ; **********************************************************

READ_BYTE: MOV MOV SETB BITCNT,#08H; SET COUNTER FOR 8-BITS DATA A,#00H SDA ; SET SDA HIGH TO ENSURE LINE

; FREE READ_BITS: SCL_HIGH MOV RLC CLR DJNZ C,SDA A SCL ; TRANSITION SCL LOW-TO-HIGH ; MOVE DATA BIT INTO CARRY

; ROTATE CARRY-BIT INTO ACC.0 ; TRANSITION SCL HIGH-TO-LOW

BITCNT,READ_BITS ; LOOP FOR 8-BITS

JB

LASTREAD,ACKN ; CHECK TO SEE IF THIS IS ; THE LAST READ

CLR

SDA

; IF NOT LAST READ SEND ACK-BIT

ACKN:

SCL_HIGH CLR RET SCL

; PULSE SCL TO TRANSMIT ACKNOWLEDGE ; OR NOT ACKNOWLEDGE BIT

; ********************************************************** ; SUB SENDS START CONDITION ; **********************************************************

SEND_START: SETB CLR CLR JNB JNB SETB _2W_BUSY ; INDICATE THAT 2-WIRE ACKS ; OPERATION IS IN PROGRESS

BUS_FLT ; CLEAR STATUS FLAGS SCL,FAULT SDA,FAULT SDA ; BEGIN START CODITION

SCL_HIGH CLR ACALL CLR RET FAULT: SETB RET BUS_FLT SDA DEELAY SCL

; ********************************************************** ; SUB SENDS STOP CONDITION ; **********************************************************

SEND_STOP: CLR SDA

SCL_HIGH SETB CLR RET ; ********************************************************** ; SUB DELAYS THE BUS ; ********************************************************** DEELAY: NOP RET ; ********************************************************** ; THIS SUB SENDS 1 BYTE OF DATA TO THE DS1307 ; CALL THIS FOR EACH REGISTER SECONDS TO YEAR ; ACC MUST CONTAIN DATA TO BE SENT TO CLOCK ; ********************************************************** SEND_BYTE: MOV SB_LOOP: JNB SETB JMP NOTONE: CLR ONE: SCL_HIGH ; TRANSITION SCL LOW-TO-HIGH SDA ; CLR SDA LOW ACC.7,NOTONE; CHECK TO SEE IF BIT-7 OF SDA ONE ; ACC IS A 1, AND SET SDA HIGH BITCNT,#08H; SET COUNTER FOR 8-BITS ; DELAY FOR BUS TIMING SDA _2W_BUSY

RL CLR DJNZ SETB

A SCL

; ROTATE ACC LEFT 1-BIT ; TRANSITION SCL LOW-TO-HIGH

BITCNT,SB_LOOP; LOOP FOR 8-BITS SDA ; SET SDA HIGH TO LOOK FOR ; ACKNOWLEDGE PULSE

SCL_HIGH CLR JNB SETB ACKS

SDA,SB_EX ; CHECK FOR ACK OR NOT ACK ACKS ; SET ACKNOWLEDGE FLAG FOR

; NOT ACK SB_EX: CALL CLR CALL RET ; ********************************************************** ; SUB READS THE CLOCK AND WRITES IT TO THE SCRATCHPAD MEMORY ; ON RETURN FROM HERE DATE & TIME DATA WILL BE STORED IN THE ; DATE & TIME REGISTERS FROM 24H (SECS) TO 2AH (YEAR) ; ALARM SETTINGS IN REGISTERS 2CH(HRS) AND 2DH(MINUTES). ; ********************************************************** READ_CLOCK: MOV MOV CLR CALL MOV CALL R1,#SECS ; SECONDS STORAGE LOCATION BYTECNT,#00H LASTREAD SEND_START A,#DS1307W SEND_BYTE DEELAY SCL DEELAY ; DELAY FOR AN OPERATION ; TRANSITION SCL HIGH-TO-LOW ; DELAY FOR AN OPERATION

MOV CALL CALL CALL MOV CALL

A,#00H SEND_BYTE SEND_STOP SEND_START A,#DS1307R SEND_BYTE

READ_LOOP: MOV CJNE SETB A,BYTECNT A,#09H,NOT_LAST LASTREAD

NOT_LAST: CALL MOV MOV CJNE MOV CLR MOV NOT_FIRST: INC INC MOV CJNE CALL RET R1 BYTECNT A,BYTECNT A,#0AH,READ_LOOP SEND_STOP READ_BYTE @R1,A A,BYTECNT A,#00H,NOT_FIRST A,@R1 ACC.7 @R1,A ; ENSURE OSC BIT=0 (ENABLED)

;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&& ;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ; STORE THE TIME TO RTC CHIP

;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( STORE_RTC: LCALL SEND_START MOV A,#DS1307W LCALL SEND_BYTE MOV A,#01H LCALL SEND_BYTE MOV A,MINS LCALL SEND_BYTE MOV A,HRS SETB ACC.6 JNB AMS,YUH CLR ACC.5 AJMP YUH1 YUH: SETB ACC.5 YUH1: LCALL SEND_BYTE ; Send Day ;AM/PM 1=PM,0=AM ;send hr ;12 HR MODE ; SEND 2WIRE START CONDITION ; LOAD DS1307 WRITE COMMAND ; SEND WRITE COMMAND ; SET DS1307 DATA POINTER TO BEGINNING ; OF 00H ; Send min

MOV A,DAY LCALL SEND_BYTE MOV A,DATE1 LCALL SEND_BYTE MOV A,MONTH LCALL SEND_BYTE MOV A,YEAR LCALL SEND_BYTE

; Send date

; Send month

; Send yr

LCALL SEND_STOP RET

; SEND 2WIRE STOP CONTION

;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

Seven Segment Display Interfacing


The 7 segment display is found in many displays such as microwaves or fancy toaster ovens and occasionally in non cooking devices. It is just 7 LEDs that have been combined into one case to make a convenient device for displaying numbers and some letters. The display is shown on the left. The pin out of the display is on the right.

This version is a common anode version. That means that the positive leg of each LED is connected to a common point which is pin 3 in this case. Each LED has a negative leg that is connected to one of the pins of the device. To make it work you need to connect pin 3 to 5 volts. Then to make each segment light up, connect the ground pin for that led to ground. A resistor is required to limit the current. Rather than using a resistor from each LED to ground, you can just use one resistor from Vcc to pin 3 to limit the current. The following table shows how to form the numbers 0 to 9 and the letters A, b, C, d, E, and F. '0' means that pin is connected to ground. '1' means that pin is connected to Vcc.

To Display 0 1 2 3 4 5 6 7 8 9 A b C d E F

a (Pin 1) 0 1 0 0 1 0 0 0 0 0 0 1 0 1 0 0

b (Pin 10) 0 0 0 0 0 1 1 0 0 0 0 1 1 0 1 1

c (Pin 8) 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 1

d (Pin 6) 0 1 0 0 1 0 0 1 0 1 1 0 0 0 0 1

e (Pin 5) 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 0

f (Pin 2) 0 1 1 1 0 0 0 1 0 0 0 0 0 1 0 0

g (Pin 9) 1 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0

Now, we want to run the display with the AT89C51 microcontroller. We will use Port 0 to run the

display. Connect the AT89C51 to the 7 segment display as follows.

Program to display "0" on the seven segment display

; PROG2 - Second Program, Display 0 on seven segment display ; ORG 0000H ; Execution starts here

SETB P0.3 CLR CLR CLR CLR CLR CLR P0.1 P0.0 P0.6 P0.5 P0.4 P0.2

; Turn off the g segment ; Turn on the a segment ; Turn on the b segment ; Turn on the c segment ; Turn on the d segment ; Turn on the e segment ; Turn on the f segment

HERE:

AJMP HERE

; Loop here forever

END

This chapter gives an idea of how flexible the I/O pins are, despite their simple design. The Program given below polls 2 button s connected to the I/O pins (which pull the line to ground from its normal pulled-up state) and passes the state of the pin to another one and lights an LED when the button is being pressed. Connect the following circuit in the bread board

Code:
KEYLEFT KEYRIGHT LEDLEFT LEDRIGHT ORG SETB BIT P1.0 BIT P1.1 BIT P1.2 BIT P1.3 00H KEYLEFT

;Bit Definition

LOOP:

SETB MOV MOV MOV MOV LJMP END

KEYRIGHT C,KEYLEFT LEDLEFT,C C,KEYRIGHT LEDRIGHT,C LOOP

;For reading, the first to write a

Serial EEPROM Interfacing (AT24C08 with AT89C2051)


Introduction:

...................................................................................................................................

Many designers today are implementing embedded systems that require low cost non-volatile memory. Microchip has addressed this need with a full line of serial EEPROMs, in a variety of memory configurations, using the industry-standard 2- or 3-wire communication protocols. Circuit Diagram
Formatted: Font: (Default) Times New Roman, 13.5 pt, Font color: White

SDA1

EQU

P1.1

;SDA=PIN5

SCL1 WTCMD EQU RDCMD EQU

EQU 10100000B 10100001B

P1.0

;SCL=PIN6 ;WRITE DATA COMMAND ;READ DATA COMMAND

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% ; STORE A BYTE IN EEPROM (Data 8F in address location 2AH) ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% MOV A,#WTCMD ;LOAD WRITE COMMAND CALL OUTS ;SEND IT MOV A,#2AH ;GET BYTE ADDRESS CALL OUT ;SEND IT MOV A,#8FH ;GET DATA CALL OUT ;SEND IT CALL STOP ;SEND STOP CONDITION ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% ; READ A BYTE FROM EEPROM FROM ADDRESS LOCATION 4DH ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% MOV A,#WTCMD ;LOAD WRITE COMMAND TO SEND ADDRESS CALL OUTS ;SEND IT MOV A,#4DH ;GET LOW BYTE ADDRESS CALL OUT ;SEND IT CALL CREAD ;GET DATA BYTE MOV A,R1 CALL MDELAY RET ;********************************************************************* ** ; EEPROM ROUTINES ;********************************************************************* ** ;********************************************************************* ** ; THIS ROUTINE SENDS OUT CONTENTS OF THE ACCUMULATOR ; to the EEPROM and includes START condition. Refer to the data sheets ; for discussion of START and STOP conditions. ;********************************************************************* ** OUTS: MOV SETB SETB NOP NOP NOP CLR NOP NOP NOP CLR R2,#8 SDA1 SCL1 ;LOOP COUNT -- EQUAL TO BIT COUNT ;INSURE DATA IS HI ;INSURE CLOCK IS HI ;NOTE 1 ;START CONDITION -- DATA = 0 ;NOTE 1 ;CLOCK = 0

SDA1

SCL1

OTSLP:

BITLS: OTSL1:

RLC JNC SETB JMP CLR SETB NOP NOP NOP CLR DJNZ SETB NOP SETB NOP NOP NOP CLR RET

A BITLS SDA1 OTSL1 SDA1 SCL1

;SHIFT BIT ;DATA = 1 ;CONTINUE ;DATA = 0 ;CLOCK HI ;NOTE 1

SCL1 R2,OTSLP SDA1 SCL1

;CLOCK LOW ;DECREMENT COUNTER ;TURN PIN INTO INPUT ;NOTE 1 ;CLOCK ACK ;NOTE 1

SCL1

;********************************************************************* * ; THIS ROUTINE SENDS OUT CONTENTS OF ACCUMLATOR TO EEPROM ; without sending a START condition. ;********************************************************************* * OUT: OTLP: MOV RLC JNC SETB JMP CLR SETB NOP NOP NOP CLR DJNZ SETB NOP SETB NOP NOP NOP CLR RET STOP: CLR NOP NOP NOP SETB R2,#8 A BITL SDA1 OTL1 SDA1 SCL1 ;LOOP COUNT -- EQUAL TO BIT COUNT ;SHIFT BIT ;DATA = 1 ;CONTINUE ;DATA = 0 ;CLOCK HI ;NOTE 1

BITL: OTL1:

SCL1 R2,OTLP SDA1 SCL1

;CLOCK LOW ;DECREMENT COUNTER ;TURN PIN INTO INPUT ;NOTE 1 ;CLOCK ACK ;NOTE 1

SCL1

SDA1

;STOP CONDITION SET DATA LOW ;NOTE 1

SCL1

;SET CLOCK HI

NOP NOP NOP

;NOTE 1

SETB SDA1 ;SET DATA HIGH RET ;******************************************************************* ; THIS ROUTINE READS A BYTE OF DATA FROM EEPROM ; From EEPROM current address pointer. ; Returns the data byte in R1 ;******************************************************************* CREAD: MOV A,#RDCMD ;LOAD READ COMMAND CALL OUTS ;SEND IT CALL IN ;READ DATA MOV R1,A ;STORE DATA CALL STOP ;SEND STOP CONDITION RET ;********************************************************************* * ; THIS ROUTINE READS IN A BYTE FROM THE EEPROM ; and stores it in the accumulator ;********************************************************************* * IN: INLP: MOV SETB CLR NOP NOP NOP NOP SETB CLR JNB CPL RLC DJNZ CLR RET R2,#8 SDA1 SCL1 ;LOOP COUNT ;SET DATA BIT HIGH FOR INPUT ;CLOCK LOW ;NOTE 1

INL1:

SCL1 C SDA1,INL1 C A R2,INLP SCL1

;CLOCK HIGH ;CLEAR CARRY ;JUMP IF DATA = 0 ;SET CARRY IF DATA = 1 ;ROTATE DATA INTO ACCUMULATOR ;DECREMENT COUNTER ;CLOCK LOW

;********************************************************************* ; This routine test for WRITE DONE condition ; by testing for an ACK. ; This routine can be run as soon as a STOP condition ; has been generated after the last data byte has been sent ; to the EEPROM. The routine loops until an ACK is received from ; the EEPROM. No ACK will be received until the EEPROM is done with ; the write operation. ;********************************************************************* ACKTST: MOV A,#WTCMD ;LOAD WRITE COMMAND TO SEND ADDRESS MOV R2,#8 ;LOOP COUNT -- EQUAL TO BIT COUNT CLR SDA1 ;START CONDITION -- DATA = 0 NOP ;NOTE 1 NOP NOP AKTLP: CLR RLC JNC SCL1 A AKTLS ;CLOCK = 0 ;SHIFT BIT

AKTLS: AKTL1:

SETB JMP CLR SETB NOP NOP NOP CLR DJNZ SETB NOP SETB NOP NOP NOP JNB JMP CLR CLR NOP NOP NOP

SDA1 AKTL1 SDA1 SCL1

;DATA = 1 ;CONTINUE ;DATA = 0 ;CLOCK HI ;NOTE 1

SCL1 R2,AKTLP SDA1 SCL1

;CLOCK LOW ;DECREMENT COUNTER ;TURN PIN INTO INPUT ;NOTE 1 ;CLOCK ACK ;NOTE 1

EXIT:

SDA1,EXIT ACKTST SCL1 SDA1

;EXIT IF ACK (WRITE DONE) ;START OVER ;CLOCK LOW ;DATA LOW ;NOTE 1

SETB SCL1 ;CLOCK HIGH NOP NOP SETB SDA1 ;STOP CONDITION RET ;*********************************************************************

Infrared Receiver Interfacing (TSOP 1738)


...................................................................................................................................

This section describes how to interface an Infrared Receiver (TSOP 1738) to the microcontroller AT89C51/52 and to control 8 LED's through a RC5 Remote control.

Formatted: Font: (Default) Times New Roman, 13.5 pt, Font color: Blue

The circuit explains how to connect an Infrared Sensor to the Microcontroller, the program to control 8 devices through a standard RC5 Remote control. INCLUDE reg_51.pdf INPUT signal EQU P3.2 ; Port3,Bit2 is used as input. The demodulated ; with active low level is connected to this pin RB0 EQU 000H RB1 EQU 008H use DSEG ORG ; Select Register Bank 0 ; Select Register Bank 1 ...poke to PSW to

20H

; This is internal data memory ; Bit adressable memory 1 FLAGS.0 FLAGS.1 ; toggles with every new keystroke ; Bit set when a new command has been

FLAGS: DS CONTROL BIT NEW BIT received

COMMAND: DS 1 ; Received command byte SUBAD: DS 1 ; Device subaddress TOGGLE: DS 1 ;Toggle every bit ANS: DS 1 ; ADDR: DS 1 STACK: DS 1 ; Stack begins here CSEG ; Code begins here ;---------==========----------==========---------=========--------; PROCESSOR INTERRUPT AND RESET VECTORS ;---------==========----------==========---------=========--------ORG 00H ; Reset JMP MAIN ORG 0003H ; External Interrupt0 JMP RECEIVE ;---------==========----------==========---------=========---------

; ---------==========----------==========---------=========--------; Interrupt 0 routine ; ---------==========----------==========---------=========--------RECEIVE: CPL P2.2 MOV 2,#235 ; Time Loop (3/4 bit time) DJNZ 2,$ ; Waste Time to sync second bit MOV 2,#235 ; Time Loop (3/4 bit time) Djnz 2,$ ; Waste Time to sync second bit Mov 2,#134 ; Time Loop (3/4 bit time) Djnz 2,$ ; Waste Time to sync second bit clr a mov r6,#07h pol1: rlc Mov mov a ; Waste time for next BIT ; Time Loop (3/4 bit time) ; Waste Time to sync second bit ; Time Loop (3/4 bit time) ; Waste Time to sync second bit ; Time Loop (3/4 bit time) ; Waste Time to sync second bit c,Input

2,#235 Djnz 2,$ Mov 2,#235 Djnz 2,$ Mov 2,#235 Djnz 2,$ Mov 2,#105 Djnz 2,$ djnz r6,pol1 MOV SUBAD,A mov pol2: mov rlc Mov c,Input a r6,#06h

2,#235 Djnz 2,$ Mov 2,#235 Djnz 2,$ Mov 2,#235 Djnz 2,$ Mov 2,#105 Djnz 2,$ djnz r6,pol2 Mov COMMAND,A MOV A,SUBAD MOV ADDR,A ANL A,#0FH MOV SUBAD,A CJNE A,#03H,ZXC1 MOV A,COMMAND CPL A MOV COMMAND,A AJMP ASZ MOV A,SUBAD CJNE A,#00H,ANSS AJMP ASZ MOV A,ADDR ANL A,#20H MOV TOGGLE,A

; Waste time for next BIT ; Time Loop (3/4 bit time) ; Waste Time to sync second bit ; Time Loop (3/4 bit time) ; Waste Time to sync second bit ; Time Loop (3/4 bit time) ; Waste Time to sync second bit ; Save Command at IRData memory

ZXC1:

ASZ:

ANSS: WAR:

CJNE A,ANS,ANSS AJMP WAR JMP ANS1 MOV A,COMMAND CJNE A,#01H,DSP1 CPL P0.0 CJNE A,#02H,DSP2 CPL P0.1 CJNE A,#03H,DSP3 CPL P0.2 CJNE A,#04H,DSP4 CPL P0.3 CJNE A,#05H,DSP5 CPL P0.4 CJNE A,#06H,DSP6 CPL P0.5 CJNE A,#07H,DSP7 CPL P0.6 CJNE A,#08H,DSP8 CPL P0.7 CJNE A,#0CH,DSP9 MOV P0,#0FFH MOV ANS,TOGGLE MOV A,ANS CPL ACC.5 MOV ANS,A SETB NEW

DSP1: DSP2: DSP3: DSP4: DSP5: DSP6: DSP7: DSP8: DSP9:

; Set flag to indicate the new

command ;################################################################ ANS1: RETI ; ---------==========----------==========---------=========--------; Main routine. Program execution starts here. ; ---------==========----------==========---------=========--------MAIN: MOV SP,#60H SETB EX0 Interrupt0 CLR IT0 transition ; Enable external ; triggered by a high to low

SETB EA; /* Enable global interrupt */ MOV ANS,#00H ;clear temp toggle bit CLR LOO: JNB NEW,LOO CLR NEW AJMP LOO END NEW

Das könnte Ihnen auch gefallen