;---------------------------------------; ; RC224ATF single chip modem interface ; ;---------------------------------------; ; First we need to initialize the 8051 ; ; Timer 0 will generate a 200mS (5Hz) internal interrupt ; to be used as a general timer for any purpose, ex: check ; and generate timeout for no modem answers, etc. ; ; Suppose we use a crystal 3.6864 MHz, so to calculate ; Timer 0 and Timer 1 (baud rate for serial port), we use ; the following formula for 2400 bps: ; ; Timer 1 baud rate: 100h - (Clock/16/12/Speed) ; 100h - 3686400/16/12/2400 ; 256 - 8 = 248 or 0F8h ; so, TH1 and TL1 = 0F8h ; ; Original Philips formula for mode1: ; ; 2 x Osc.Freq ; TH1 = 256 - --------------- ; 384 x baud rate ; ; or ; ; 2 x Osc.Freq ; baud rate = --------------------- ; 32 x 12 x (256 - TH1) ; ; ; *** for the formulas above we consider SMOD bit set at PCON. ; ; Timer 0 internal 200ms interrupt: ; 10000h - (Clock/12)/Rate ; 65536 - (3686400/12)/5Hz ; 65536 - 61440 = 4096 or (1000h) ; so, TH0 = 10h and TL0 = 00h ; ; ; Timer1 will work in 8+8 bit auto reload, ; so, TMOD ..1. ...1 bits must on ; so, TCON .1.1 ...1 bits must on ; so, SCON .1.1 ..1. bits must on ; ; At power on reset, all interrupts are off, so we need to activate ; Timer 0 interrupt for the 200ms internal clock with the command ; ; Setb ET0 ; Activate Timer0 Interrupt ; ; But to deal with this 200ms interrupt we need an interrupt ; routine at code address 000Bh, so we need to have this: ; ; ORG 000Bh ; Jmp Inter0 ; ; So, at every 200ms, this interrupt will launch the program ; counter to run at address 000B, and the Jump instruction will ; run the routine Inter0 that will ... ; ; When the RX pin receive a complete character it will fill the ; SBUF with that data, and it can generate an interrupt. ; If the interrupt for the serial port is active, the program ; counter will jump to the address 0023h, that is the serial ; interrupt address. At that address we will have another jump ; to our reception routine: ; ; ORG 0023h ; Jmp InterS ; ; So, the InterS routine will just get the byte from SBUF and ; reset the interrupt flag to be able to interrupt again at ; the next received byte. ; ; We will use this routine just for the first time we talk ; to the modem chip, after that, we will use "polling" to ; check if there is another received byte at SBUF. ; ; You can change this routine and receive everything based on ; interruptions. The reason why we need to use interrupt at ; the first received byte is that it can happens very fast ; and our polling routine would not be able to get it before ; arrives the second byte, so we lost the first one that its ; important. ; ; Well, let's start some code here: ; ES BIT 0ACh ; IE.4 Serial Port Interrupt Enable ; Your assembler can complain and ask you ; to remove the ES designation for bit, ; since it can be already defined. ORG 0000h ; Jmp Start ; ; ORG 000Bh ; Jmp Inter0 ; ; ORG 0023h ; Jmp InterS ; ; START: Mov SP,#050h ; Stack Pointer to 50h, or any other. ; Orl PCON,#80h ; Set SMOD bit, necessary to the baud rate formula ; Mov TH0,#010h ; timer0 for 200ms Mov TL0,#000h ; ; Mov TH1,#0F8h ; baud rate for serial port at 2400bps Mov TL1,#0F8h ; ; ; Defining Timer0 and Timer1 modes ; Mov TMOD,#021h ; Timer1 = 8 bits autoloader, Timer0 = 16 bits Mov TCON,#051h ; Run both timers 0 and 1 Mov SCON,#052h ; 8 bit uart (mode1), Enable RX, Set TX Int Flag CLR ET0 ; deactivate Timer0 interrupt CLR ET1 ; deactivate Timer1 interrupt CLR EX0 ; deactivate external T0 interrupt CLR EX1 ; deactivate external T1 interrupt Setb EA ; Set gate to All active Interrupts Setb ET0 ; Activate Timer0 Interrupt 200ms ; ; Wake up modem if not awake ; Mov R4,#0 ; R4 will be used at serial interrupt Setb ES ; Activate Serial Interrupt ; Mov Dptr,#ATH ; Send "+++" to modem to return to Call Code2Modem ; command mode, if in data mode. Call Tim200ms ; ; Mov Dptr,#ATZ ; Send "ATZ" to Software Reset Modem. Call Code2Modem ; Call Tim200ms ; ; Mov Dptr,#MdmInit ; Send "ATE0V0" to modem. Call Code2Modem ; Call Tim200ms ; ; Mov Dptr,#MdmInit1 ; Send "ATX4E0Q0V0S11.... to modem. Call Code2Modem ; Call Tim200ms ; ; Clr ES ; Deactivate Serial Interrupt Mov A,R4 ; Modem Should Answer letter "K" Cjne A,#'K',ModemError ; If R4 is not "K", modem did not ; answered the commands ATX4E0Q0.... ; and it must be dead. It should answer. ; In any case, check R4 contents. ; ModemError Routine needs to be done ; to signal modem error in some way. ; ; After this point, the modem will ; only answer numeric messages, ; and for every command you sent to ; the modem, if accepted and processed ; ok, it will answer "0" (30h). ; Mov Dptr,#DIALFONE ; Here Modem is Ok and will DIAL Call Code2Modem ; Send "ATDT....number" to modem ; ; Modem will dial and contact remote modem, they will do a ; handshake (noises) to stablish the communication speed ; between both modems. After they do that, your modem will ; answer a numeric byte to you know it, and both modems will ; switch do data mode, leaving command mode. ; ; In the data mode, everything you send to the modem, will ; be transmited to the other modem and it will deliver to ; the DTE (data terminal equipment) connected to that modem. ; ; If you need to send commands to your modem again, not data, ; you need to make your modem return to command mode again. ; ; To do that, wait at least 30ms, then send "+++" and wait ; again at least 30ms, it is almost sure that your modem ; will understand that and switch back to command mode, ; so you can send again AT commands to the modem again. ; ; This will be necessary when you want to disconnect your ; connection, modem release phone line, and so on. ; ; Call ModemIn ; Wait modem answer Cjne A,#'1',Start1 ; answer "1" (31h) = connected 2400bps ;.... ; show it in any way if necessary. Start1: Cjne A,#'5',Start2 ; answer "5" (35h) = connected 1200bps ;.... ; show it in any way if necessary. ; Start2: ;.... ; here your software goes transmitting ;.... ; and receiving data as required. ;.... ; ; Code2Modem: Clr A ; Movc A,@A+Dptr ; Get byte pointed by Dptr Inc Dptr ; point to next byte Jnz $+3 ; if not zero skip the Ret instruction Ret ; Return to Caller if byte = zero. Call ModemOut ; Send Data to Modem Jmp Code2Modem ; Go back for other bytes until zero. ; ModemOut: Jnb TI,$ ; Wait while TX buffer is not empty Clr TI ; Clear Flag for next time Mov SBUF,A ; Move data to be transmited immediately Ret ; Return to Caller ; ModemIn: Jnb RI,$ ; Wait until RX Data Available Mov A,SBUF ; Get received byte Clr RI ; Clear Data Available flag Ret ; Return to Caller ; InterS: Clr A ; Jnb RI,Inters9 ; If not data received, return A=0 Mov A,SBUF ; get received data Mov R4,A ; Save R4 with modem data Clr RI ; Clear Receive Interrupt Flag Inters9: Reti ; Return from Interrupt ; ; Inter0: Mov TH0,#010h ; Reload Timer0 Values Mov TL0,#000h ; Push Acc ; Inc R5 ; R5 is a 100ms counter ; Do any other function Reti ; Return from Interrupt ATH: db '++++',0 ATZ: db 'ATZ'13,,0 MDMINIT: db 'ATE0V0'13,,0 MDMINIT1: db 'ATX4E0Q0V0S11=40S12=0S7=15'13,0 DIALFONE: db 'ATDT 123 4567',13,0 ; <--- change number here ; Time routines. You can change R5, R6 and R7 by any other variables ; or addresses in the internal ram memory. ;--------------------------------------; Tim200ms: Mov R7,#20 ; R7 x 10ms = 200ms Jmp Tim10ms ; Call 10ms Routine & Return to Caller Tim1000ms: Mov R7,#100 ; Tim10ms: Mov R6,#216 ; Clock 3686400 generates this Tim10msA: Mov R5,#6 ; loop routine to waste aprox 10ms Tim10msB: Djnz R6,$ ; times the R7 contents. Djnz R5,Tim10msB ; Djnz R7,Tim10msA ; To wait 100ms, load R7 with 0Ah Ret ; and call this routine.