*/
If you have a PH account, you can customize your PH profile.
*/

View \DUPUART.ASM

A software duplex UART for 8xc751 & 8cc752

Submitted By: WEBMASTER
Rating: (Not rated) (Rate It)


;*******************************************************************************

;        Duplex UART Routines for the 8xC751 and 8xC752 Microcontrollers

;*******************************************************************************


; This is a demo program showing a way to perform simultaneous RS-232
; transmit and receive using only one hardware timer.

; The transmit and receive routines divide each bit time into 4 slices to
; allow synchronizing to incoming data that may be out of synch with outgoing
; data.

; The main program loop in this demo processes received data and sends it
; back to the transmitter in hexadecimal format. This insures that we can
; always fill up the receiver buffer (since the returned data is longer than
; the received data) for testing purposes. Example: if the letter "A" is
; received, we will echo "A41 ".

;*******************************************************************************


$Title(Duplex UART Routines for the 751/752)
$Date(8/20/92)
$MOD751


;*******************************************************************************
;                                   Definitions
;*******************************************************************************


; Miscellaneous

TxBitLen    EQU   -4 + 1                ; Timer slices per serial bit transmit.
RxBitLen    EQU   -4 + 1                ; Timer slices per serial bit receive.
RxHalfBit  EQU   (RxBitLen / 4) + 1    ; Timer slices for a partial bit time.
                                        ;   Used to adjust the input sampling
                                        ;   time point.

; Note:  TxBitLen and RxBitLen are kept separate in order to facilitate the
;   possibility of having different transmit and receive baud rates. The timer
;   would be set up to give four slices for the fastest baud rate, and the
;   BitLen for the slower channel would be set longer for the slower baud rate.
;   BitLen = -4 + 1 gives four timer interrupts per bit. BitLen = -8 + 1 would
;   give 8 slices, BitLen = -16 + 1 would give 16 slices, etc.

TxPin       BIT   P1.0                  ; RS-232 transmit pin (output).
RxPin       BIT   P1.5                  ; RS-232 receive pin (input).
RTS         BIT   P1.3                  ; RS-232 request to send pin (output).
CTS         BIT   P1.6                  ; RS-232 clear to send pin (input).
; Note: P1.1 and P1.2 are used to input the baud rate selection.


; RAM Locations

Flags       DATA  20h                   ; Miscellaneous bit flags (see below).
TxOn        BIT   Flags.0               ; Indicates transmitter is on (busy).
RxOn        BIT   Flags.1               ; Indicates receiver is on (busy).
TxFull      BIT   Flags.2               ; Transmit buffer (1 byte only) is full.
RxFull      BIT   Flags.3               ; Receiver buffer is full.
RxAvail     BIT   Flags.4               ; RX buffer is not empty.
OverrunErr  BIT   Flags.6               ; Overrun error flag.
FramingErr  BIT   Flags.7               ; Framing error flag.

BaudHigh    DATA  21h                   ; High byte timer value for baud rate.
BaudLow     DATA  22h                   ; Low byte timer value for baud rate.

TxCnt       DATA  23h                   ; RS-232 byte transmit bit counter.
TxTime      DATA  24h                   ; RS-232 transmit time slice count.
TxShift     DATA  25h                   ; Transmitter shift register.
TxDat       DATA  26h                   ; Transmitter holding register.

RxCnt       DATA  27h                   ; RS-232 byte receive bit counter.
RxTime      DATA  28h                   ; RS-232 receive time slice count.
RxShift     DATA  29h                   ; Receiver shift register.
RxDatCnt    DATA  2Ah                   ; Received byte count.
RxBuf       DATA  2Bh                   ; Receive buffer (3 bytes long).

Temp        DATA  2Fh                   ; Temporary holding register.


;*******************************************************************************
;                                Interrupt Vectors
;*******************************************************************************

            ORG   00h                   ; Reset vector.
            AJMP  RESET


            ORG   03h                   ; External interrupt 0
            AJMP  Intr0                 ; (received RS-232 start bit).


            ORG   0Bh                   ; Timer 0 overflow interrupt.
            AJMP  Timer0                ; (4X the RS-232 bit rate).
       
            ORG   13h                   ; External interrupt 1.
            RETI                        ; (not used).

            ORG   1Bh                   ; Timer I interrupt.
            RETI                        ; (not used).

            ORG   23h                   ; I2C interrupt.
            RETI                        ; (not used).


;*******************************************************************************
;                               Interrupt Handlers
;*******************************************************************************


; External Interrupt Int0.
;   RS-232 start bit transition.

Intr0:      PUSH  ACC                   ; Save accumulator,
            PUSH  PSW                   ;   and status.
            CLR   IE.0                  ; Disable more RX interrupts.

            SETB  RxOn                  ; Set receive active flag.
            MOV   RxCnt,#11h            ; Set bit counter to expect a start.
            MOV   RxTime,#RxHalfBit     ; First sample is at a partial bit time.
            JB    TxOn,I0TimerOn        ; If TX active then timer is on.

            MOV   RTH,BaudHigh          ; Set up timer for selected baud rate.
            MOV   RTL,BaudLow
            MOV   TH,BaudHigh
            MOV   TL,BaudLow
            SETB  TR                    ; Start timer 0.

I0TimerOn:  MOV   A,RxDatCnt            ; Check for buffer about to be full:
            CJNE  A,#2,Int0Ex           ;   one space left and a byte starting.
            SETB  RTS                   ; If so, tell whoever is on the
                                        ;   other end to wait.

Int0Ex:     POP   PSW                   ; Restore status,
            POP   ACC                   ;   and accumulator.
            RETI


; Timer 0 Interrupt
;   This is used to generate time slices for both serial transmit and receive
;   functions.

Timer0:     PUSH  ACC                   ; Save accumulator,
            PUSH  PSW                   ;   and status.
            JNB   TxTime.7,RS232TX      ; Is this an active time slice
                                        ;   for an RS-232 transmit?
            JNB   TxOn,CheckRx          ; If transmit is active,
            INC   TxTime                ;   increment the time slice count.
CheckRx:    JNB   RxTime.7,RS232RX      ; Is this an active time slice
                                        ;   for an RS-232 receive?
            JNB   RxOn,T0Ex             ; If receive is active, increment
            INC   RxTime                ;   the time slice count.

T0Ex:       POP   PSW                   ; Restore status,
            POP   ACC                   ;   and accumulator.

            MOV   P3,Flags              ; For demo purposes, output status
                                        ;   on an extra port.
            RETI



;*******************************************************************************
;                             RS-232 Transmit Routine
;*******************************************************************************


RS232TX:    JNB   TxCnt.4,TxData        ; Go if data bit.
            JNB   TxCnt.0,TxStop        ; Go if stop bit.


; Send start bit and do buffer housekeeping.

TxStart:    JB    CTS,TxEx1             ; Is CTS asserted (low) so can we send? 
                                        ;   If not, try again after 1 bit time.
            CLR   TxPin                 ; Set start bit.
            MOV   TxShift,TxDat         ; Get byte to transmit  from buffer.
            CLR   TxFull
            MOV   TxCnt,#08h            ; Init bit count for 8 bits of data.
                                        ;   (note: counts UP).

TxEx1:      MOV   TxTime,#TxBitLen      ; Reset time slice count.
            SJMP  CheckRx               ; Restore state and exit.


; Send Next Data Bit.

TxData:     MOV   A,TxShift             ; Get un-transmitted bits.
            RRC   A                     ; Shift next TX bit to carry.
            MOV   TxPin,C               ; Move carry out to the TXD pin.
            MOV   TxShift,A             ; Save bits still to be TX'd.

            INC   TxCnt                 ; Increment TX bit counter
            MOV   TxTime,#TxBitLen      ; Reset time slice count.
            SJMP  CheckRx               ; Restore state and exit.


; Send Stop Bit and Check for More to Send.

TxStop:     SETB  TxPin                 ; Send stop bit.
            JB    TxFull,TxEx2          ; More data to transmit?
            CLR   TxOn                  ; If not, turn off TX active flag, and
            CLR   RTS                   ;   make sure that whoever is on the
                                        ;   other end knows it's OK to send.

            JB    RxOn,TxEx2            ; If receive active, timer stays on,
            CLR   TR                    ;   otherwise turn off timer.

TxEx2:      MOV   TxCnt,#11h            ; Set TX bit counter for a start.
            MOV   TxTime,#TxBitLen-1    ; Reset time slice count, stop bit
                                        ;   > 1 bit time for synch.
            SJMP  CheckRx               ; Restore state and exit.



;*******************************************************************************
;                             RS-232 Receive Routine
;*******************************************************************************


RS232RX:    MOV   C,RxPin               ; Get current serial bit value.
            JNB   RxCnt.4,RxData        ; Go if data bit.
            JNB   RxCnt.0,RxStop        ; Go if stop bit.


;Verify start bit.

RxStart:    JC    RxErr                 ; If bit=1, then not a valid start.
            MOV   RxCnt,#08h            ; Init counter to expect data.
            MOV   RxTime,#RxBitLen      ; Reset time slice count.
            SJMP  T0Ex                  ; Restore state and exit.


; Get Next Data Bit.

RxData:     MOV   A,RxShift             ; Get partial received byte.
            RRC   A                     ; Shift in new received bit.
            MOV   RxShift,A             ; Store partial result in buffer.
            INC   RxCnt                 ; Increment received bit count.
            MOV   RxTime,#RxBitLen      ; Reset time slice count.
            SJMP  T0Ex                  ; Restore state and exit.


; Store Data Byte, "push"ing it into the FIFO buffer.

RxStop:     CLR   EA                    ; Don't interrupt the following.
            MOV   A,RxBuf               ; "PUSH" the receive buffer.
            XCH   A,RxBuf+1
            XCH   A,RxBuf+2
            MOV   RxBuf,RxShift         ; Add just completed data to buffer.
            INC   RxDatCnt              ; Increment the received byte count.
            SETB  EA                    ; Re-enable interrupts.

            SETB  RxAvail               ; There is data in the RX buffer.
            PUSH  PSW                   ; Save Carry (received bit)for later.
            MOV   A,RxDatCnt            ; Check receiver buffer status.
            CJNE  A,#4,RxChk1           ; Is RX buffer overrun?
            SETB  OverrunErr            ; Set status reg overrun error flag.
            MOV   RxDatCnt,#3           ; Re-set buffer counter to "full".

RxChk1:     CJNE  A,#3,RxChk2           ; Is RX buffer full?
            SETB  RxFull                ; Set buffer full status.

RxChk2:     POP   PSW                   ; Retrieve last received bit in Carry.
            JC    RxEx                  ; If bit=0, then not a valid stop.
RxErr:      SETB  FramingErr            ; Remember bad start or stop status.

RxEx:       JB    TxOn,RxTimerOn        ; If transmit active, timer stays on,
            CLR   TR                    ;   otherwise turn timer off.
RxTimerOn:  CLR   RxOn                  ; Turn off receive active.
            SETB  RxTime.7              ; Set bit for no service to
                                        ;   RX Time Slice Branches.
            SETB  IE.0                  ; Re-enable RS-232 receive interrupts.
            AJMP  T0Ex                  ; Restore state and exit.


;*******************************************************************************
;                                  Subroutines
;*******************************************************************************


; BaudRate - Determine and set the baud rate from switches.
;   Note: if the baud rate is altered, the actual change will only occur when
;   a transmit or receive is begun while the timer was not already running
;   (i.e.: not already busy transmitting or receiving).

BaudRate:   MOV   DPTR,#BaudTable       ; Set pointer to baud rate table.
            ANL   A,#03h                ; Limit displacement for lookup.
            RL    A                     ; Double the table index since these
                                        ;   are 2 byte entries.
            PUSH  ACC                   ; Save the table index for second byte.
            MOVC  A,@A+DPTR             ; Get first byte, and save as the high
            MOV   BaudHigh,A            ;    byte of the baud rate timer value.
            POP   ACC                   ; Get back the table index.
            INC   A                     ; Advance to next table entry.
            MOVC  A,@A+DPTR             ; Get second byte, and save as the low
            MOV   BaudLow,A             ;    byte of the baud rate timer value.
            RET


; Entries in BaudTable are for a timer setting of 1/4 of a bit time at the given
;   baud rate. The two values per entry are the high and low bytes of the value
;   respectively.

; Values are calculated as follows:
;                                             Osc Frequency
;   1/4 Bit cell time (in machine cycles) = -----------------
;                                            Baud Rate * 48

; Example for 9600 baud with a 16MHz crystal:
;    16,000,000 / 9600 * 48 = 34.7222... machine cycles per quarter bit time.
;    Rounded, this is 35. The hexadecimal value for 35 is 23.
;    10000 hex - 23 hex (truncated to 16 bits) = FFDD. Thus, the BaudTable entry
;    for 9600 baud is FF, DD hex.

BaudTable:  DB    0FEh,0EAh             ; 1200 baud.
            DB    0FFh,75h              ; 2400 baud.
            DB    0FFh,0BBh             ; 4800 baud.
            DB    0FFh,0DDh             ; 9600 baud.


; TxSend - Initiate RS-232 Transmit.

TxSend:     JB    TxFull,$              ; Make sure TX buffer is free.
            SETB  TxFull                ; Reserve the buffer for our use.
            MOV   TxDat,A               ; Put character in buffer.
            JB    TxOn,TSTimerOn        ; Exit if transmitter already running.

            SETB  TxOn                  ; Transmit active flag set.
            MOV   TxCnt,#11h            ; Init bit counter to expect a start.
            MOV   TxTime,#TxBitLen      ; Reset time slice count.
            JB    RxOn,TSTimerOn        ; Exit if receiver already active.

            MOV   RTH,BaudHigh          ; Set up timer for selected baud rate.
            MOV   RTL,BaudLow
            MOV   TH,BaudHigh
            MOV   TL,BaudLow
            SETB  TR                    ; Start up the bit timer.
TSTimerOn:  RET


; PrByte - Output a byte as ASCII hexadecimal format.

PrByte:     PUSH  ACC                   ; Print ACC contents as ASCII hex.
            SWAP  A
            ACALL  HexAsc               ; Print upper nibble.
            ACALL  TxSend
            POP   ACC
            ACALL  HexAsc               ; Print lower nibble.
            ACALL  TxSend
            RET


; HexAsc - Convert a hexadecimal nibble to its ASCII character equivalent.

HexAsc:     ANL   A,#0Fh                ; Make sure we're working with only
                                        ;   one nibble.
            CJNE  A,#0Ah,HA1            ; Test value range.
HA1:        JC    HAVal09               ; Value is 0 to 9.
            ADD   A,#7                  ; Value is A to F, needs pre-adjustment.
HAVal09:    ADD   A,#'0'                ; Adjust value to ASCII hex.
            RET


; GetRx - Retrieve a byte from the receive buffer, and return it in A.

GetRx:      CLR   EA                    ; Make sure this isn't interrupted.
            DEC   RxDatCnt              ; Decrement the buffer count.
            MOV   A,RxDatCnt            ; Get buffer count.
            JNZ   GRX1                  ; Test for empty receive buffer.
            CLR   RxAvail               ; If empty, clear data available status.
GRX1:       ADD   A,#RxBuf              ; Create a pointer to end of buffer.
            MOV   Temp,R0               ; Save R0.
            MOV   R0,A                  ; Put pointer where we can indirect.
            MOV   A,@R0                 ; Get last buffer data.
            MOV   R0,Temp               ; Restore R0.
            CLR   RxFull                ; Buffer can't be full anymore.
            SETB  EA                    ; Re-enable interrupts.
            RET


;*******************************************************************************
;                                      Reset
;*******************************************************************************

Reset:      MOV   SP,#2Fh               ; Initialize stack start.
            MOV   TCON,#0               ; Set timer off, INT0 to level trigger.
            MOV   P3,#0                 ; Turn off all status outputs.

; For this demo, we only set up the baud rate once at reset:

            MOV   A, P1                 ; Read baudrate bits from P1.
            RR    A                     ; The switches are on bits 2 and 1.
            ACALL BaudRate              ; Set up the selected baud rate.

            MOV   FLAGS,#0              ; Init all status flags.
            MOV   RxDatCnt,#0           ; Clear buffer count.
            MOV   IE,#93h               ; Turn on timer 0 interrupt and
                                        ;   external interrupt 0.
            CLR   RTS                   ; Assert RTS so we can receive.


; The main program loop processes received data and sends it back to the
;   transmitter in hexadecimal format. This insures that we can always fill
;   up the receiver buffer (since the returned data is longer than the
;   received data) for testing purposes. Example: if the letter "A" is
;   received, we will echo "A41 ".

MainLoop:   JNB   RxAvail,$             ; Make sure an input byte is available.
            ACALL GetRx                 ; Get data from the receiver buffer.
            ACALL TxSend                ; Echo original character.
            ACALL PrByte                ; Output the char in hexadecimal format,
            MOV   A,#20h                ;   followed by a space.
            ACALL TxSend
            SJMP  MainLoop              ; Repeat.

            END

corner
© 1996-2008 CommunityHeaven LLC. All rights reserved. Reproduction in whole or in part, in any form or medium without express written permission is prohibited.
Violators of this policy may be subject to legal action. Please read our Terms Of Use and Privacy Statement for more information.
North American business development: Nicolai Wadstrom. Publisher: Lars Hagelin.