; File: X_Baud_R.A51 Date: 11/18/92 ; ; /* (c) Copyright BLUE EARTH RESEARCH, MANKATO, MN 1992 */ ; /* All rights reserved. */ $ ERRORPRINT PAGELENGTH (60) PAGEWIDTH (110) ; Assembler controls $ XREF TITLE (Serial Port Baud Rate Converter) $ DATE (11/18/92) NOGEN ; ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» ; º º ; º INTERRUPT DRIVEN BIDIRECTIONAL SERIAL COMMUNICATIONS º ; º º ; ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ; ----------------------------------------------------------------------------- ; Written by Tom Bachmann, Blue Earth Research, Mankato, MN 56001 ; ----------------------------------------------------------------------------- ; This program combines the main function of the Serial Input Buffer program ; BUFFER.A51 with the option of using Timer1 to clock the transmitted bytes to ; provide a means of implementing a baud rate converter. The program assumes ; that the primary serial port is properly set up for receiving characters and ; the transmit baud rate is initialized like the BASIC program shown below. ; IMPORTANT NOTE: If characters are being received at 2400 Baud and then ; transmitted at 4800 Baud, the 256-byte circular receive buffer will never ; overflow. However, if characters are received at 9600 and transmitted at ; 2400, it is possible for the buffer to overflow, resulting in the loss of ; 256 received characters. Note that overflow is only possible when characters ; are being received more than 25% of the time. ; For more details on how the Serial Input Buffer works, refer to the source ; file mentioned above. ; Also note that this program utilizes Timer1, so that the PWM, PRINT#, and ; LIST# Statements may not be used within BASIC. $ EJECT ; ------------------------- BASIC LANGUAGE PROGRAM ---------------------------- ; The following is an example of how to invoke the baud rate converter program. ; Note that CALLing 7F00H will set up the primary serial port receive buffer ; and transmit echo function. CALLing 7F02H will set only up the serial port ; for different baud rates. ; 2 REM Baud Rate Converter ; ; REM DEFINE THE SYSTEM'S SECOND SERIAL PORT BAUD RATE ; REM AND CALCULATE TIMING PARAMETERS ; 20 BPS=4800 : RELOAD=256-((2*12E+6)/(32*12*BPS)) ; 30 DBY(18H)=INT(RELOAD+0.5) ; ; 50 CALL 7F00H ; ------------------------ ASSEMBLY LANGUAGE PROGRAM -------------------------- ; If the serial port is set up for non-buffered operation, the assembly ; language routine only needs to be called once (CALL 7F02H). No further ; assembly language program or interrupt routine needs to be executed. If the ; serial buffer is implemented (CALL 7F00H), The assembly language routine ; continues to operate as follows: ; For each serial character received, the Buffer "Head" address pointer is ; bumped and the received character stored into that location. Reading the ; buffer is accomplished by bumping the Buffer "Tail" address pointer and then ; reading that location into the accumulator. If the Head & Tail pointers are ; equal, then the Buffer is considered empty. Trying to read an empty Buffer ; will produce a NULL code (0) in the accumulator and will not advance the ; Tail pointer. $ EJECT ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ SYMBOL DEFINITIONS ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; ----------------------------- EQUATE TABLE ---------------------------------- TCLK BIT 0CCH SerAddress EQU 4023H ; Serial Interrupt Vector CodeAddr EQU 7F00H ; Locate this program at top of ; write protectable memory space ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ INTERNAL DATA SEGMENT ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ DSEG AT 18H TimerHold: DS 1 ; Hold timing byte for Transmit Head: DS 1 ; Pointer to last character stuffed Tail: DS 1 ; Pointer to last character read ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ INTERNAL BIT SEGMENT ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ BSEG AT 0 NextReady: DBIT 1 ; Set when a character is received ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ EXTERNAL DATA SEGMENT ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ XSEG AT 5000H Buffer: DS 256 ; Where circular receive Buffer starts $ EJECT CSEG AT CodeAddr ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ SET UP BIDIRECTIONAL SERIAL PORT WITH BUFFER ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ SJMP StartSerial ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ SET UP SERIAL PORT ONLY - NO BUFFER ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; ÚÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄ¿ ; T2CON = ³ TF2 ³ EXF2 ³ RCLK ³ TCLK ³EXEN2 ³ TR2 ³ C/T2 ³CP/RL2³ ; ÀÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÙ ; 0 0 1 0 0 1 0 0 NoBuffer: CLR TCLK ; Use Timer1 for Transmit ; Timer 1 Timer 0 ; ÚÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÅÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄ¿ ; TMOD = ³ GAT ³ C/T ³ M1 ³ M0 ³ GAT ³ C/T ³ M1 ³ M0 ³ ; ÀÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÙ ; 0 0 1 0 0 0 0 0 MOV TMOD,#20H ; TIMER/CNTR MODE CTRL REGISTER MOV TH1,TimerHold MOV TL1,TimerHold ; ÚÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄ¿ ; PCON = ³SMOD1 ³SMOD0 ³ -- ³ POF ³ GF1 ³ GF0 ³ PD ³ IDL ³ ; ÀÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÙ ; 1 0 0 0 0 0 0 0 ORL PCON,#1000$0000B ; Double Baud Rate ; ÚÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄ¿ ; TCON = ³ TF1 ³ TR1 ³ TF0 ³ TR0 ³ IE1 ³ IT1 ³ IE0 ³ IT0 ³ ; ÀÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÙ ; 0 1 0 0 0 0 0 0 SETB TR1 ; Start Timer RET $ EJECT ; ------------------------INITIALIZE SERIAL INTERRUPT ------------------------- StartSerial: MOV DPTR,#SerAddress ; Write LJMP code to serial MOV A,#2 ; interrupt vector location. MOVX @DPTR,A INC DPTR MOV A,#HIGH SerialInt MOVX @DPTR,A INC DPTR MOV A,#LOW SerialInt MOVX @DPTR,A ; Now initialize Head and Tail pointers so that the first byte received is ; stored in (and read from) location 0 (the pointers are incremented BEFORE ; the byte is stored or read). MOV Head,#0FFH ; Initialize Buffer pointers MOV Tail,#0FFH CLR NextReady ; No characters received yet ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ INITIALIZE CPU FUNCTIONS ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ; ÚÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄ¿ ; IE = ³ EA ³ EC ³ ET2 ³ ES ³ ET1 ³ EX1 ³ ET0 ³ EX0 ³ ; ÀÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÙ ; 1 0 0 1 0 0 0 0 MOV IE,#090H ACALL NoBuffer ; Set up the rest of the Serial Port ClearTI: JNB TI,$ ; Normally set by BASIC. CLR TI ; We want it cleared. $ EJECT ; ----------------------------- MAIN PROGRAM ---------------------------------- Loop: JNB NextReady,Loop ; No characters received yet CLR NextReady ; ---------------------- READ CHARACTER FROM BUFFER --------------------------- MoreChars: MOV A,Head ; If Head & Tail are the same, XRL A,Tail ; the Buffer is considered empty. JZ Loop GetChar: INC Tail MOV DPH,#HIGH Buffer MOV DPL,Tail MOVX A,@DPTR ; Read the Buffer ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ SET UP TO TRANSMIT A CHARACTER ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ SendChar: MOV SBUF,A ; Load SBUF with data byte JNB TI,$ ; Wait until character is transmitted CLR TI ; We want it cleared. SJMP MoreChars ; Since this program only echos characters, it will stay here forever. RET ; Back to BASIC?? NO!! ; ------------------------- DISABLE SERIAL INTERRUPT -------------------------- ; May want to load SBUF with 1st character of an output string instead of a ; NULL and let BASIC take care of sending the rest of them. StopSerial: CLR ES ; Disable serial interrupt WriteCR: MOV SBUF,#0DH ; Write to set TI bit RET Write??: MOV SBUF,A RET $ EJECT ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ SERIAL INTERRUPT ROUTINE ³ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ SerialInt: JNB RI,NotRecv ; Not a receive interrupt ? PUSH PSW ; Save registers PUSH ACC PUSH DPH PUSH DPL SETB NextReady ; Set Next Character Ready flag INC Head ; Point to next storage location MOV DPH,#HIGH Buffer ; Page pointer always the same. MOV DPL,Head MOV A,SBUF ; Get serial input character CLR RI ; and reenable interrupt. MOVX @DPTR,A ; Store character in Buffer POP DPL ; Restore registers POP DPH POP ACC POP PSW NotRecv: RETI END ; Following is the HEX file derived from the assembled source ; file. This can be used for directly loading the program via ; MONITOR-51 and almost any terminal program. :107F00008011C2CC75892085188D85188B43878098 :107F1000D28E229040237402F0A3747FF0A3745A8F :107F2000F07519FF751AFFC20075A890F10230991B :107F3000FDC2993000FDC200E519651A60F5051A09 :107F4000758350851A82E0F5993099FDC29980E8D1 :107F500022C2AC75990D22F5992230981FC0D0C06D :107F6000E0C083C082D2000519758350851982E56F :0D7F700099C298F0D082D083D0E0D0D032FA :00000001FF