.DEVICE AT90S2313 .def ELNPos =r10 .def CNTR =r11 .def RDLCD =r12 .def EEPos =r18 .def NibblePos =r19 .def DTMF =r20 .def LCDPOS =r21 .def SCLPos =r22 .def PNTR =r23 .CSEG .ORG $000 rjmp Reset .ORG $002 rjmp DTMF .ORG $010 ;Ends up being at $20 .DW $44,$54,$4D,$46,$20,$44,$65,$63,$6F,$64,$65,$72,$20,$62,$79,$20,$00 ;DTMF Decoder by .ORG $021 ;Ends up being at $42 .DW $77,$77,$77,$2E,$69,$6E,$66,$69,$64,$69,$67,$6D,$2E,$6E,$65,$74,$00 ;www.infidigm.net .ORG $032 ;Ends up being at $64 .DW $45,$6E,$64,$00 ;End Reset: ldi r16,0 out $17,r16 ;HiZ Port B ldi r16,$70 out $11,r16 ;Setup DDRD cbi $12,4 ;Disable DTMF Decoder's Output ldi r16,$DF out 0x3D,R16 ;Setup StackPointer ldi r16,22 out $09,r16 ;Set BAUD rate = 9600 ldi r16,8 out $0A,r16 ;Enable TX in UART ldi r16,$2C out $35,r16 ;Set Sleep Mode, Set INT1 to Rising Edge ldi r16,$80 out $3B,r16 ;Enable INT1 Interrupt ldi r16,$C0 out $3A,r16 ;Clear INT Flags rcall CLRLCD rcall MSG rcall CRDT rcall FindE rcall DUMP rcall SPC ldi LCDPOS,64 ;Set inturnal LCD position ldi r26,$60 ;Setup X pointer ldi r27,$00 ldi r16,1 mov RDLCD,r16 ;Set LCD Refresh Flag mov ELNPos,EEPos ;Remember EEPos @ End of LCD Line mov SCLPos,EEPos ;Remember EEPos for Scrolling UP / Down ldi r16,128 add SCLPos,r16 sei UF: sbic $10,0 rjmp DF UFN: sbis $10,0 rjmp UFN rcall DOWN DF: sbic $10,2 rjmp UF DFN: sbis $10,2 rjmp DFN rcall UP rjmp UF ;** CLRLCD --> Inits LCD, Clears LCD, homes cursor, uses ;** r16 (General) ;** ;** WRTCN --> LCD Write Strobe (Control) CLRLCD: ldi r16,$01 ;Clear LCD, move home rcall WRTCN ldi r16,$02 ;Home Cursor rcall WRTCN ldi r16,$38 ;Set 8-bit interface rcall WRTCN ldi r16,$0C ;No cursor, display visable rcall WRTCN ldi r16,$06 ;Increment display address rcall WRTCN ret ;** MSG --> Sends Credit (DTMF Decoder....) to LCD, uses ;** Z = r30,r31 ;** r0 (lpm data) ;** r16 (General) ;** WRTCN --> LCD Write Strobe (Control) ;** WDAT --> LCD Write Strobe (Data) MSG: ldi r31,0 ;Load Z Pointer to First Line ldi r30,$020 GOM1: lpm ;Load text mov r16,r0 cpi r16,0 ;Test for end of Text breq M2 rcall WDAT ;Send Data to LCD inc r30 inc r30 rjmp GOM1 M2: ldi r16,$C0 ;Second Line Address rcall WRTCN ldi r31,0 ;Load Z Pointer to Second Line ldi r30,$042 GOM2: lpm ;Load text mov r16,r0 cpi r16,0 ;Test for end of Text breq M3 rcall WDAT ;Send Data to LCD inc r30 inc r30 rjmp GOM2 M3: ret ;** WDAT & WRTCN --> Srobes LCD Write for a Control or Data Byte, uses ;** r16 (General) ;** r17 (General) ;** DLY1 --> ~250 uS Delay WDAT: sbi $12,5 ;Set RS = Data Register rjmp FINSTB WRTCN: cbi $12,5 ;Set RS = Control Register FINSTB: ldi r17,255 ;Set PortB to Output out $17,r17 out $18,r16 ;Present Control Data to LCD rcall DLY1 sbi $12,6 ;Set EN = HI rcall DLY1 cbi $12,6 ;Clear EN = LOW ldi r16,16 ; 16*250 uS = 4 mS delay WDLY: rcall DLY1 dec r16 cpi r16,0 brne WDLY ldi r16,0 ;Set PortB to Input out $17,r16 out $18,r16 ret DLY1: ldi r17,179 ; ~250 uS Delay LPO: nop dec r17 cpi r17,0 brne LPO ret ;** CRDT --> Sends CREDIT out the UART, uses ;** Z = r30,r31 ;** r16 (General) ;** r0 (lpm data) CRDT: rcall SPC ldi r31,0 ;Load Z Pointer to First Line ldi r30,$020 GO1: lpm ;Load text mov r16,r0 cpi r16,0 ;Test for end of Text breq P2 out $0C,r16 ;Send to TX Data register rcall TXC ;Strobe TX and wait for EOT inc r30 inc r30 rjmp GO1 P2: ldi r31,0 ;Load Z Pointer to Second Line ldi r30,$042 GO2: lpm ;Load text mov r16,r0 cpi r16,0 ;Test for end of Text breq P3 out $0C,r16 ;Send to TX Data register rcall TXC ;Strobe TX and wait for EOT inc r30 inc r30 rjmp GO2 P3: rcall SPC ret SPC: ldi r16,$0A ;Send Line Feed out $0C,r16 rcall TXC ldi r16,$0A ;Send Line Feed out $0C,r16 rcall TXC ldi r16,$0D ;Send Carrage Return out $0C,r16 rcall TXC ret ;** DUMP --> Dumps EEPROM out the UART, uses ;** EEPos ;** r16 (General) ;** r17 (General) DUMP: mov r17,EEPos ;Get EEPos = Flag position inc r17 GOTX: out $1e,r17 ;Get EEPROM at next address sbi $1C,0 in r16,$1D lsr r16 ;Modify for MSN lsr r16 lsr r16 lsr r16 rcall FLTR ;Filter data out $0C,r16 ;TX MSN out of UART rcall TXC in r16,$1D andi r16,$0F ;Modify for LSB rcall FLTR ;Filter data out $0C,r16 ;TX LSN out of UART rcall TXC ldi r16,127 ;Test for complete cycle through EEPROM add r16,EEPos cp r17,r16 brsh DEND inc r17 rjmp GOTX DEND: ret TXC: sbis $0B,6 ;Test TXC Flag rjmp TXC sbi $0B,6 ;Clear TXC Flag ret FLTR: cpi r16,$0E ;Test for "$E" = Null brne DOK clr r16 ;If "$E" then clear data ret DOK: ori r16,$30 ;If valid data convert to ASCII ret ;** FindE --> Finds last place written to in EEPROM before power down, uses ;** EEPos ;** NibblePos ;** r16 (General) FindE: clr EEPos FrstN: out $1E,EEPos ;Loops until r16=$F0 or r16=$0F sbi $1C,0 ;Init EEPROM Read ldi NibblePos,1 in r16,$1D ;Checks MS Nibble for $F andi r16,$F0 cpi r16,$F0 brne ScndN ret ScndN: clr NibblePos in r16,$1D ;Checks LS Nibble for $F andi r16,$0F cpi r16,$0F brne NextN ret NextN: inc EEPos ;Increment EEROM Address rjmp FrstN ;** DTMF --> DTMF Decoder Interrupt Handle, uses ;** DTMF ;** LCDPOS ;** X = r26,r27 (Memory Address Pointer) ;** r16 (General) DTMF: cli ldi r16,0 out $17,r16 ;Set PortB as Input sbi $12,4 ;Enable DTMF Decoder's output nop in DTMF,$16 ;Read PortB --> DTMF Decoder's output cbi $12,4 ;Disable DTMF Decoder's output --> HiZ andi DTMF,$0F ;Drop MSB Nibble cpi DTMF,10 ;test for '0' Digit Dialled brne NONZ clr DTMF ;Change read 10 --> 0 NONZ: ldi r16,$30 add DTMF,r16 ;Change DTMF number to ASCII Character Code cpi LCDPOS,80 ;Test for END of Second line on LCD brlo RFSH rcall ShftLn ;If end of second line call Line Shifting Sub rjmp PLC RFSH: mov r16,RDLCD cpi r16,1 ;Test Refresh Flag brne PLC rcall RSTLCD ;If LCD not ready for DTMF PLC: st X+,DTMF ;Store DTMF Digit in RAM and increment pointer (Used by ShftLn) mov r16,DTMF rcall WDAT ;Write DTMF to LCD inc LCDPOS ;Increment LCD Line Position pointer out $0C,DTMF ;TX DTMF out of UART rcall TXC rcall EEWRT ;Store DTMF in EEPROM mov SCLPos,ELNPos ;Set Scrolling Position ldi r16,128 add SCLPos,r16 sei reti ;** ShftLn --> Moves contents of second line to first, uses ;** X = r26,r27 (Memory Address Pointer) ;** r16 (General) ShftLn: ldi r16,$01 ;Clear & Home position LCD Code rcall WRTCN ldi r26,$60 ;Set memory pointer to Home Bld: ld r16,X+ ;Send DTMF digit from RAM to first line on LCD rcall WDAT cpi r26,$70 brlo Bld ;Test for end of line ldi r26,$60 ;Set memory pointer to Home ldi LCDPOS,64 ;Set LCD Line Position pointer to first place on second line mov ELNPos,EEPos ;Remember EEPos @ End of LCD Line ldi r16,$C0 ;Set LCD to SECOND line rcall WRTCN clr RDLCD ;Clear LCD Refresh Flag ret ;** EEWRT --> Writes DTMF Digit to EEPROM and compresses, uses ;** DTMF = r ;** EEPos = r ;** NibblePos = r ;** r16 (General) EEWRT: andi DTMF,$0F ;Strip MSN cpi NibblePos,0 ;Test if last stored data was at MSN or LSN brne N1 ;If MSB goto N1 (LSN Write) out $1E,EEPos ;EEPROM Address sbi $1C,0 ;Init EEPROM Read in r16,$1D ; (Last Digit Written) MSN | LSN ($F) andi r16,$F0 ; (Last Digit Written) MSN | LSN (Erase) or r16,DTMF ; (Last Digit Written) MSN | LSN (DTMF Digit) out $1D,r16 ; Store Modified EEPROM Address rcall EWS ;Init EEPROM Write inc EEPos ;Increment EEPROM Address Position out $1E,EEPos ;EEPROM Address sbi $1C,0 ;Init EEPROM Read in r16,$1D ; (Oldest DTMF Digit) MSN | LSN (Second Oldest DTMF Digit) ori r16,$F0 ; ($F) MSN | LSN (Now Oldest DTMF Digit) out $1D,r16 ; Store Modified EEPROM Address rcall EWS ;Init EEPROM Write ldi NibblePos,1 ;Indicate EEPROM Endmarker in MSN ret N1: mov r16,DTMF swap r16 ori r16,$0F ;(Digit Digit) MSN | LSN ($F) out $1E,EEPos out $1D,r16 ; Store Modified EEPROM Address rcall EWS ;Init EEPROM Write clr NibblePos ;Indicate EEPROM Endmarker in LSN ret EWS: ldi r16,4 out $1C,r16 sbi $1C,1 ;Stobe EEPROM Write ldi r16,255 DE: cpi r16,0 breq WRTDN dec r16 nop nop rjmp DE WRTDN: sbic $1C,1 ;Test for Write Finished rjmp WRTDN ret ;** RSTLCD --> Restores the LCD contents from scroll for next DTMF, uses ;** ELNPos = r10 ;** CNTR = r11 ;** r16 (General) ;** r17 (General) RSTLCD: push ELNPos ldi r16,$01 ;Clear LCD & Home cursor rcall WRTCN clr CNTR ;Reset Row Counter ldi r16,8 sub ELNPos,r16 out $1e,ELNPos ;Get EEPROM at address sbi $1C,0 cpi NibblePos,1 brne RN0 RN1: out $1e,ELNPos ;Get EEPROM at next address sbi $1C,0 in r16,$1D lsr r16 ;Modify for MSN lsr r16 lsr r16 lsr r16 ldi r17,$30 add r16,r17 rcall WDAT ;Send EEPROM Digit to LCD inc CNTR RN0: in r16,$1D andi r16,$0F ;Modify for LSB ldi r17,$30 add r16,r17 rcall WDAT ;Send EEPROM Digit to LCD inc CNTR inc ELNPos mov r16,CNTR cpi r16,16 brlo RN1 ;Test if First Line Restored pop ELNPos ldi r16,$C0 ;Second Line Address rcall WRTCN ldi r26,$60 ;Set memory pointer Send line Row 1 SNL: mov r16,r26 subi r16,32 cp r16,LCDPOS breq DSNL ;Test for end of line ld r16,X+ ;Send DTMF digit from RAM to second line on LCD rcall WDAT rjmp SNL DSNL: ldi r16,$80 add r16,LCDPOS ;Set LCD Row Position rcall WRTCN clr RDLCD ;Clear LCD Refresh Flag ret ;** DOWN --> DOWN LCD Scroll, uses ;** r16 (General) ;** r17 (General) ;** X = r26,r27 (Memory Address Pointer) ;** ELNPos ;** SCLPos ;** LCDPos ;** RDLCD ;** CNTR ;** PNTR ;** WRTCN --> LCD Write Strobe (Control) ;** WDAT --> LCD Write Strobe (Data) ;** PNT --> Move section of EEProm to LCD according to SCLPos DOWN: mov r16,ELNPos ;Test for End of Scroll DOWN ldi r17,128 ;" add r16,r17 ;" mov r17,SCLPos ;" cp r17,r16 ;" brlo DNT ret DNT: ldi r16,$01 ;Clear LCD & Home cursor rcall WRTCN mov PNTR,SCLPos ;Setup pointer for TOP LCD line rcall PNT ;" ldi r16,$C0 ;Second Line Address rcall WRTCN mov r16,ELNPos ;Test to Rebuild First Line ldi r17,120 ;" add r16,r17 ;" mov r17,SCLPos ;" cp r17,r16 ;" brlo DNB ldi r26,$60 ;Rebuild First Line AA: mov r16,r26 ;Set memory pointer Send line Row 1 subi r16,32 cp r16,LCDPOS breq BB ;Test for end of line ld r16,X+ ;Send DTMF digit from RAM to second line on LCD rcall WDAT rjmp AA BB: ldi r16,$80 ;Set LCD Row Position add r16,LCDPOS ;" rcall WRTCN clr RDLCD ;Clear LCD Refresh Flag rjmp DNEND DNB: mov PNTR,SCLPos ;Setup pointer for BOTTOM LCD line ldi r16,8 ;" add PNTR,r16 ;" rcall PNT ldi r16,1 ;Set LCD Refresh Flag mov RDLCD,r16 ;" DNEND: ldi r16,8 add SCLPos,r16 ret ;** UP --> UP LCD Scroll, uses ;** r16 (General) ;** r17 (General) ;** Z = r30,r31 ;** r0 (lpm data) ;** ELNPos ;** SCLPos ;** RDLCD ;** CNTR ;** PNTR ;** WRTCN --> LCD Write Strobe (Control) ;** WDAT --> LCD Write Strobe (Data) ;** PNT --> Move section of EEProm to LCD according to SCLPos UP: mov r16,ELNPos ;Test for End of Scroll UP ldi r17,1 ;" add r16,r17 ;" mov r17,SCLPos ;" cp r17,r16 ;" brsh UPE ret UPE: ldi r16,$01 ;Clear LCD & Home cursor rcall WRTCN mov r16,ELNPos ;Test to Display "End" ldi r17,9 ;" add r16,r17 ;" mov r17,SCLPos ;" cp r17,r16 ;" brsh UPT ldi r31,0 ;Place "End" on LCD ldi r30,$064 ;Load Z Pointer to First Line UPL: lpm ;Load text mov r16,r0 cpi r16,0 ;Test for end of Text breq UPB rcall WDAT ;Send Data to LCD inc r30 inc r30 rjmp UPL UPT: mov PNTR,SCLPos ;Setup pointer for TOP LCD line ldi r16,16 ;" sub PNTR,r16 ;" rcall PNT UPB: ldi r16,$C0 ;Second Line Address rcall WRTCN mov PNTR,SCLPos ;Setup pointer for BOTTOM LCD line ldi r16,8 ;" sub PNTR,r16 ;" rcall PNT ldi r16,1 ;Set LCD Refresh Flag mov RDLCD,r16 ;" subi SCLPos,8 ;Decrement LCD Scroll Position ret ;** PNT --> Move section of EEProm to LCD according to SCLPos, uses ;** r16 (General) ;** r17 (General) ;** PNTR ;** CNTR ;** WDAT --> LCD Write Strobe (Data) PNT: clr CNTR ;Reset Row Counter out $1e,PNTR ;Get EEPROM at address sbi $1C,0 cpi NibblePos,1 brne PNT0 PNT1: out $1e,PNTR ;Get EEPROM at next address sbi $1C,0 in r16,$1D lsr r16 ;Modify for MSN lsr r16 lsr r16 lsr r16 ldi r17,$30 add r16,r17 rcall WDAT ;Send EEPROM Digit to LCD inc CNTR PNT0: in r16,$1D andi r16,$0F ;Modify for LSB ldi r17,$30 add r16,r17 rcall WDAT ;Send EEPROM Digit to LCD inc CNTR inc PNTR mov r16,CNTR cpi r16,16 brlo PNT1 ;Test if Line Restored ret