;******************************************* ;* Tutorial: * ;* 1. Hex to Decimal converting routine * ;* 2. Decimal to Ascii converting rout. * ;* 3. LCD (4x40) driving functions * ;******************************************* ;This program was written using Raisonance RIDE MA-51 ;my email: jacek.bogusz@ep.com.pl ;at89s8252 at 11.0592 MHz ;****************************************************************************** ; LCD connections: ; ; Pin description | AT89S8252 ; --------------------------------------- ; enable | P0.4(35) ; read lcd | P0.5(34) ; reg.select | P0.6(33) ; d0..d7 | P2.0 .. P2.7 (21..28) ; ;****************************************************************************** $include (REG_8252.PDF) NAME Tutorial ;Stack size (initial value of SP register) StackAddr EQU 0E0H ;stack address (equals size) ;some of hd44780 (lcd controler) orders ClrScr EQU 01H ;clear screen RetHome EQU 02H ;return to Home pos. CursorLeft EQU 10H ;cursor left CursorRight EQU 14H ;cursor right ScreenLeft EQU 1CH ;screen left ScreenRight EQU 18H ;screen right DisplyOn EQU 0CH ;display on DisplyOff EQU 08H ;disply off SetDDRam EQU 80H ;set ddram address LCDLineLength EQU 20 ;lcd's line length LCDRowsNum EQU 4 ;lcd's max.row number DSEG AT 30H t_buffer: DS 8 ;transponder receiver buffer (64 bits) LCD_1: DS 20 ;lcd display buffer LCD_2: DS 20 LCD_3: DS 20 LCD_4: DS 20 lcdenable BIT P0.4 ;enable signal for lcd display lcdread BIT P0.5 ;read signal for lcd lcdreg BIT P0.6 ;when H switch to command register, when L to data register lcdbusy BIT P2.7 ;data line 7 od lcd, for busy state testing mainprog SEGMENT CODE INBLOCK ;interrupt vectors CODE AT 0H AJMP InitProc ;reset CODE AT 3H AJMP IrqExt0 ;int0 CODE AT 0BH AJMP IrqTmr0 ;timer 0 CODE AT 13H AJMP IrqExt1 ;int1 CODE AT 1BH AJMP IrqTmr1 ;timer 1 CODE AT 23H AJMP IrqSPI ;spi CODE AT 30H ;external int0 IrqExt0: RETI ;timer 0 interrupt IrqTmr0: RETI ;external int1 IrqExt1: RETI ;timer 1 interrupt IrqTmr1: RETI ;spi interrupt IrqSPI: RETI ;------------------------------------------------ ; MAIN PROGRAM ; ; Note: this is a part of bigger program, which ; is working as a machine controller, so you ; have to change some of orders for your own ; application! ;------------------------------------------------ InitProc: MOV SP,#StackAddr ;stack pointer setting MOV P0,#11101110B ;initial value of each port MOV P1,#10000111B MOV P2,#0FFH ;P2 is used for LCD data line (8 bits) CALL InitLCD ;lcd init - 8 bit interface CALL DefChars ;lcd special chacters def. MOV R7,#80 ;black lcd at the start of the program BlackLoop: MOV A,#0FFH CALL OutLCD ;OUTLCD outputs value from ACC to LCD video ram DJNZ R7,BlackLoop CALL LPause ;a little break (about 0.8 sec) CALL WriteVersion ;write start information (about version etc) CALL LongPause ;a few seconds of delay CALL ClearLCD ;clear lcd's screen ;example of WriteCString using MOV R1,#0 ;row no.0 MOV R2,#0 ;column no.0 MOV DPTR,#ConvDesc ;address of string from rom in dptr CALL WriteCString ;example of hex to dec converting MOV R5,#0 MOV R6,#1EH MOV R7,#87H CALL Hex3DecConv ;result in r5,6,7 CALL Dec2AsciiConv ;result in lcd_1 (ram memory buffer) ;display the result of conversion (example of WriteAString using) MOV R1,#1 ;row no.1 MOV R2,#0 ;column no.0 MOV R0,#LCD_1 ;r0 contains address of ram buffer CALL WriteAString AJMP $ ;here stops the program ;Out data to status control register (of LCD) ;status control register is using to input control codes for lcd controller OutStatRegLCD: CLR lcdreg ;choose status register CLR lcdread ;& write mode NOP SETB lcdenable MOV P2,A ;move acc.content to P2 CLR lcdenable ;data latched by enable signal CALL CheckBusyFlag RET ;Display char at cursor position ;this routine outputs char contained in acc. to video ram of lcd OutLCD: SETB lcdreg ;choose data register CLR lcdread ;& write mode NOP SETB lcdenable MOV P2,A ;move acc.content to P2 CLR lcdenable ;data latched by enable signal CALL CheckBusyFlag RET ;Delay instead of busy line checking ;if you want, you can check the value of P0.7 (d7 of lcd) ;logic H on this line is for BUSY state of lcd controller CheckBusyFlag: MOV R6,#3 CBF_0: MOV R5,#0FFH CBF_1: DJNZ R5,CBF_1 DJNZ R6,CBF_0 RET ;Initializing of lcd (8 bitów) InitLCD: CALL LPause CLR lcdreg CLR lcdread CLR lcdenable SETB lcdenable ;enable H, then L MOV P2,#30H CLR lcdenable CALL Pause SETB lcdenable ;enable H, then L MOV P2,#30H CLR lcdenable CALL Pause SETB lcdenable ;enable H, then L MOV P2,#30H CLR lcdenable CALL Pause MOV A,#3CH CALL OutStatRegLCD MOV A,#08H CALL OutStatRegLCD MOV A,#01H CALL OutStatRegLCD MOV A,#06H CALL OutStatRegLCD MOV A,#0CH ;lcd "on display" CALL OutStatRegLCD RET ;Own char definitioning - definitions are in CHAR table at the ROM memory (program segment) ;at the end of the table you have to put byte 0 - this is the end of definition table ;at this version of lcd display you can define 10 your own characters ;please read the lcd's programming manual for details. DefChars: CLR A ;start address of CGRAM ORL A,#40H ;cgram definition mode (b6=1) CALL OutStatRegLCD MOV DPTR,#Char ;start address of definition to dptr DefChars1: CLR A MOVC A,@A+DPTR ;byte from def.table to acc. CJNE A,#0,DefCharsSkip1 ;is it the end of table? JMP DefCharsSkip2 DefCharsSkip1: CALL OutLCD ;send a byte INC DPTR ;next position JMP DefChars1 DefCharsSkip2: MOV A,#80H ;display mode CALL OutStatRegLCD RET ;Delays ;very short delay (about 2 ms) Pause: MOV R7,#10H MOV R6,#0FFH Pause1: DJNZ R6,Pause1 DJNZ R7,Pause1 RET ;about a few seconds LongPause: MOV R5,#0FFH LongPause1: CALL Pause DJNZ R5,LongPause1 RET ;about one second LPause: MOV R5,#21 LPause1: CALL Pause DJNZ R5,LPause1 RET ;Clear screen ClearLCD: MOV A,#ClrScr ;"clear screen" code CALL OutStatRegLCD RET ;display char on lcd ;R1 <- row number (0 - n) ;R2 <- column number (0 - n) ;R3 <- ascii char code (code of character from rom char.generator of lcd) PutCharOnLCD: PUSH ACC MOV A,R1 ;save r1 MOV R7,A CJNE R1,#1,PutCharOn1 ;is row=1? MOV A,#64 ;yes,ddram start position=64 JMP PutCharOffset PutCharOn1: CJNE R1,#2,PutCharOn2 ;is row=2? MOV A,#20 ;yes,ddram start pos.=20 JMP PutCharOffset PutCharOn2: CJNE R1,#3,PutCharOn3 ;is row=3? MOV A,#84 ;yes,ddram start pos.=84 AJMP PutCharOffset PutCharOn3: CLR A ;if row=0 then ddram start pos.=0 PutCharOffset: ADD A,R2 ;offset for x coordin. ORL A,#SetDDRam ;set ddram CALL OutStatRegLCD PutCharOffSkip: MOV A,R3 CALL OutLCD ;Out char on screen MOV A,R7 ;R1 recall MOV R1,A POP ACC RET ;write a string from rom memory ;r1= row number ;r2=column number ;dptr=string address WriteCString: CLR A MOVC A,@A+DPTR ;chacter code from rom to acc. CJNE A,#0,WriteCSkip1 ;is it the end of string RET WriteCSkip1: MOV R3,A CALL PutCharOnLCD ;put char on lcd INC R2 ;next column CJNE R2,#LCDLineLength,CStringSkip2 ;is it max column? MOV R2,#0 ;yes,clear column number INC R1 ;next row CJNE A,#LCDRowsNum,CStringSkip2 ;is max row number? MOV R1,#0 ;yes-clear row number MOV R2,#0 ;&column,start from home pos. CStringSkip2: INC DPTR ;next chacter AJMP WriteCString ;write a string from ram memory ;R0=address of string in ram memory ;R1=row number ;R2=column number WriteAString: MOV A,@R0 ;first char from ram position to acc. CJNE A,#0,WriteASkip1 ;is it the end code? RET WriteASkip1: MOV R3,A MOV A,R0 ;ro save PUSH ACC CALL PutCharOnLCD ;display char. POP ACC ;r0 restore MOV R0,A INC R2 ;next column CJNE R2,#LCDLineLength,AStringSkip2 ;is it max number of column? MOV R2,#0 ;yes,clear column number INC R1 ;and go to the next row CJNE A,#LCDRowsNum,AStringSkip2 ;is it the max number of row? MOV R1,#0 ;yes,clear row number and MOV R2,#0 ;go to the first row AStringSkip2: INC R0 ;increment pointer address JMP WriteAString ;3 bytes of hex number to decimal convertion routine ;number in r5,r6,r7 (r5-msb,..,r7-lsb), result in r4,r5,r6,r7 ;the routine counts, how many times you can subtract the 1000000 from numer, then 100000,10000,1000,100,10,1 ;each counter equals position of decimal number f.e.: ; 1E74 hex - you can subtract 1000 seven (7) times, 100 seven (7) times, 10 nine (9) times and the rest ;is six (6), so your result of conversion is 7796 (equals 1E74) Hex3DecConv: CLR C MOV R4,#0 ;milion counter clear Hex3DecLoop1: MOV A,R7 ;how many time we can subtract 10000000 without carry (989680H) SUBB A,#80H MOV R7,A MOV A,R6 SUBB A,#96H MOV R6,A MOV A,R5 SUBB A,#98H MOV R5,A JC Hex3DecSkip1 INC R4 JMP Hex3DecLoop1 Hex3DecSkip1: MOV A,R4 PUSH ACC ;push counter onto stack MOV A,R7 ADD A,#80H MOV R7,A MOV A,R6 ADDC A,#96H MOV R6,A MOV A,R5 ADDC A,#98H MOV R5,A CLR C MOV R4,#0 Hex3DecLoop2: MOV A,R7 ;how many times we can subtract 1000000 (F4240H) without carry SUBB A,#40H MOV R7,A MOV A,R6 SUBB A,#42H MOV R6,A MOV A,R5 SUBB A,#0FH MOV R5,A JC Hex3DecSkip2 INC R4 JMP Hex3DecLoop2 Hex3DecSkip2: MOV A,R4 PUSH ACC ;push counter onto stack MOV A,R7 ADD A,#40H MOV R7,A MOV A,R6 ADDC A,#42H MOV R6,A MOV A,R5 ADDC A,#0FH MOV R5,A CLR C MOV R4,#0 Hex3DecLoop3: MOV A,R7 ;100000 (186A0H)? SUBB A,#0A0H MOV R7,A MOV A,R6 SUBB A,#86H MOV R6,A MOV A,R5 SUBB A,#01H MOV R5,A JC Hex3DecSkip3 INC R4 JMP Hex3DecLoop3 Hex3DecSkip3: MOV A,R4 PUSH ACC ;onto stack MOV A,R7 ADD A,#0A0H MOV R7,A MOV A,R6 ADDC A,#86H MOV R6,A MOV A,R5 ADDC A,#01H MOV R5,A Hex2DecConv: MOV R4,#0 CLR C Hex2DecLoop1: MOV A,R7 ;10000 (2710h)? SUBB A,#010H MOV R7,A MOV A,R6 SUBB A,#27H MOV R6,A MOV A,R5 SUBB A,#0 MOV R5,A JC Hex2DecSkip1 INC R4 JMP Hex2DecLoop1 Hex2DecSkip1: MOV A,R4 ;onto stack PUSH ACC MOV A,R7 ADD A,#010H MOV R7,A MOV A,R6 ADDC A,#27H MOV R6,A CLR C MOV R4,#0 Hex2DecLoop2: MOV A,R7 ;1000 (3E8h)? SUBB A,#0E8H MOV R7,A MOV A,R6 SUBB A,#03H MOV R6,A JC Hex2DecSkip2 INC R4 JMP Hex2DecLoop2 Hex2DecSkip2: MOV A,R4 ;onto satck PUSH ACC MOV A,R7 ADD A,#0E8H MOV R7,A MOV A,R6 ADDC A,#03H MOV R6,A CLR C MOV R4,#0 Hex2DecLoop3: MOV A,R7 ;100 (64h)? SUBB A,#064H MOV R7,A MOV A,R6 SUBB A,#0H MOV R6,A JC Hex2DecSkip3 INC R4 JMP Hex2DecLoop3 Hex2DecSkip3: MOV A,R4 ;onto stack PUSH ACC MOV A,R7 ADD A,#064H MOV R7,A MOV A,R6 ADDC A,#0H MOV R6,A CLR C MOV R4,#0 Hex2DecLoop4: MOV A,R7 ;10 (0Ah)? SUBB A,#0AH MOV R7,A JC Hex2DecSkip4 INC R4 JMP Hex2DecLoop4 Hex2DecSkip4: MOV A,R4 ;onto stack PUSH ACC ADD A,#0AH ;1 MOV A,R7 ;tens & ones in w R7 ADD A,#0AH MOV R7,A POP ACC SWAP A ADD A,R7 MOV R7,A POP ACC ;thousands & hundreds in R6 MOV R6,A POP ACC SWAP A ADD A,R6 MOV R6,A POP ACC ;tens thousands & hundreds thousands in R5 MOV R5,A POP ACC SWAP A ADD A,R5 MOV R5,A POP ACC ;milins & tens milions in R4 MOV R4,A POP ACC SWAP A ADD A,R4 MOV R4,A RET ;Decimal to ascii conversion ;decimal in r4(msb),r5,r6,r7(lsb),result in ram buffer LCD_1(0..7) ;note:numbers are in correct order after hex2dec conversion routine ;routine takes each of decimal number (4 bits of 8 bit register) and adds it to 0 ascii code character ;f.e. 15 => '0'+1 -> '1' , '0'+5 -> '5' Dec2AsciiConv: MOV A,#LCD_1 MOV R0,A ;pointer to lcd_1 MOV A,R4 ANL A,#0F0H SWAP A ADD A,#'0' MOV @R0,A INC R0 MOV A,R4 ANL A,#0FH ADD A,#'0' MOV @R0,A INC R0 MOV A,R5 ANL A,#0F0H SWAP A ADD A,#'0' MOV @R0,A INC R0 MOV A,R5 ANL A,#0FH ADD A,#'0' MOV @R0,A INC R0 MOV A,R6 ANL A,#0F0H SWAP A ADD A,#'0' MOV @R0,A INC R0 MOV A,R6 ANL A,#0FH ADD A,#'0' MOV @R0,A INC R0 MOV A,R7 ANL A,#0F0H SWAP A ADD A,#'0' MOV @R0,A INC R0 MOV A,R7 ANL A,#0FH ADD A,#'0' MOV @R0,A INC R0 ;put the end of string code MOV A,#0 MOV @R0,A RET ;write version procedure,example of writecstring using WriteVersion: CALL ClearLCD ;clear screen MOV R1,#0 ;first column & first row MOV R2,#0 MOV DPTR,#Copyright CALL WriteCString RET ;definicje znaków Char: DB 0AAH,055H,0AAH,055H,0AAH,055H,0AAH,055H ;# C1: DB 0C0H,0C0H,0FFH,0F1H,0F1H,0F1H,0FFH,0C0H ;blank quadrant C2: DB 0C0H,0C0H,0FFH,0FFH,0FFH,0FFH,0FFH,0C0H ;blak quadrant C3: DB 0E0H,0FFH,0FFH,0FFH,0E0H,0E0H,0E0H,0E0H ;near minus C4: DB 0FFH,0FFH,0F9H,0F3H,0E7H,0F3H,0F9H,0FFH ;Left C5: DB 0FFH,0FFH,0F3H,0F9H,0FCH,0F9H,0F3H,0FFH ;Right C6: DB 0FFH,0FFH,0FBH,0F1H,0E4H,0EEH,0FFH,0FFH ;Up C7: DB 0FFH,0FFH,0FFH,0EEH,0E4H,0F1H,0FBH,0FFH,0 ;Down Copyright: DB 'LCD 4x40 using example',0 ConvDesc: DB '1E87 hex to decimal=',0 END