Home

News

Design Info

Code

Links

RS-232 communications between PC and 16F73/74/76/77/873/874/876/877

The links to the following two webpages were the basis for getting RS-232 serial communication working between the pic16F73 and a PC. In fact, the code below was taking 95% from examples on those websites. This code is for a mid-range pic microcontroller with a built in USART. The 16f73, 16f74, 16f76, 16f77, 16f873, 16f874, 16f876, 16f877 all have a built in USART, so this code should apply to all of them, although some tweaking may be needed. For example, the f73/f76/f873/f876 are all 28-pin devices, the others are 40-pin devices and have 2 more ports (D and E).

Bente Petersen's 9600baud 16F628 UART test circuit and program
Tony Nixon's UART test program

A key element to interfacing a PIC to a PC is adjusting the voltage levels correctly. RS-232, which is what a PC serial port uses, uses +3V to +25V to indicate a logic 0 and -3V to -25V to indicate a logic 1. However a PIC uses TTL/CMOS level signaling where a logic 0 is about 0V to .8V and a logic 1 about 2V to Vdd. In order to make this work, a Texas Instruments MAX232 RS-232 transceiver was used. It will convert between the two signal levels and includes a capacitive generator to supply the RS-232 voltage levels from a single 5V supply. It does require several external capacitors. See the schematic at the bottom of this page.

RS-232 defines several signals, but only three are required for our simple asynchronous serial communication: the TXD, RXD and GND signal. To communicate with the PIC, the Hyperterminal program in Windows was used. For the example code listed, Hyperterminal was configured for 19200 baud, 8 data bits, no parity, 1 stop bit and no flow control.

echo2.asm - This just echos characters from a PC terminal program back to the screen via the PIC (this is the same as the code below).
int_echo_876.asm - Here is a program that functions almost identically to echo2.asm, but it is interrupt driven (it's also for the 16F876 and uses a 20MHz clock, but that's irrelevant)

bb_echo.asm - This program is a bit more complex than the other two above. It does rs-232 communications without using the internal UART. It's all done through bit-banging (ie software). It performs the same function as the two pieces of code above; prints a hello message and then echos everything that is sent to it. It is hardcoded for 9600 8-N-1 using a 20MHz oscillator. As is, the code just loops, waiting for a start bit, reading a byte and then sending the byte back. The problem with this is that if the bytes it receives are too close together, it will miss some because when it calls the transmit routine, that takes time where we could be missing an incoming byte. This problem can be seen if carriage return & line feeds are sent by the enter key in Hyperterminal. Because they are sent back to back, only the carriage return is actually read and echoed back. The line feed is missed. This program is setup to easily be interrupt driven as well, by uncommenting the "ENABLE_IRQ" line and commenting out the "call BBRX" and "call BBTX" lines in the main loop. In either case, the program is setup to transmit on RB1 and receive on RB0, otherwise it is connected exactly the same as the diagram below.

        Title "Your Program"
;
        list P = 16F73
;
        include "P16f73.inc"
;
; ------------------
; CONFIGURATION FUSE
; ------------------
;  Code protection/watchdog timer off, enable power up timer and brown out detection
;  Using a 4MHz ceramic resonator, so set to XT mode
        __CONFIG _CP_OFF & _XT_OSC & _WDT_OFF & _PWRTE_ON & _BODEN_ON
;
; CRYSTAL SPEED = 4000000Hz
;

; Define user registers in this block
        CBLOCK 0x20
dataL
        ENDC
;
; -------------
; PROGRAM START
; -------------
;
        org 0x0000              ; startup = 0000h
;
Start   movlw 0x00              ; setup ports
        movwf PORTA
        movlw 0x00
        movwf PORTB
        movlw 0x40
        movwf PORTC
        bsf STATUS,RP0          ; RAM Page 1
        movlw 0x00
        movwf TRISA
        movlw 0x00
        movwf TRISB
        movlw 0x80
        movwf TRISC

;
; -------------------------
; SET ANALOG/DIGITAL INPUTS
; -------------------------
;
        movlw 0x06              ; all digital
        movwf ADCON1
;
; ------------------------------------
; SET BAUD RATE TO COMMUNICATE WITH PC
; ------------------------------------
; Boot Baud Rate = 19200, No Parity, 1 Stop Bit
;
        movlw 0x0C              ; 19200 baud
        movwf SPBRG
        movlw b'00100100'       ; brgh = high (2)
        movwf TXSTA             ; enable Async Transmission, set brgh
        movlw b'10010000'       ; enable Async Reception
        bcf STATUS,RP0          ; RAM Page 0
        movwf RCSTA
;
; ------------------------------------
; PROVIDE A SETTLING TIME FOR START UP
; ------------------------------------
;
        clrf dataL
settle  decfsz dataL,F
        goto settle
;
        movf RCREG,W
        movf RCREG,W
        movf RCREG,W            ; flush receive buffer

        call message

Loop    call Receive            ; wait for a char
        movwf TXREG             ; echo data back to sender
        goto Loop
;
; ----------------------------
; RECEIVE CHARACTER FROM RS232
; ----------------------------
; This routine does not return until a character is received.
;
Receive btfss PIR1,RCIF         ; (5) check for received data
        goto Receive
;
        movf RCREG,W
        return

;
; -------------------------------------------------------------
; SEND CHARACTER IN W VIA RS232 AND WAIT UNTIL FINISHED SENDING
; -------------------------------------------------------------
;
send    movwf TXREG             ; send data in W

TransWt bsf STATUS,RP0          ; RAM PAGE 1
WtHere  btfss TXSTA,TRMT        ; (1) transmission is complete if hi
        goto WtHere

        bcf STATUS,RP0          ; RAM PAGE 0
        return 

;
; -------
; MESSAGE
; ------- 
;
message movlw  '1'
        call send
        movlw  '6'
        call send
        movlw  'F'
        call send
        movlw  '7'
        call send
        movlw  '3'
        call send
        movlw  ' '
        call send
        movlw  'a'
        call send
        movlw  'l'
        call send
        movlw  'i'
        call send
        movlw  'v'
        call send
        movlw  'e'
        call send
        movlw  0x0D ; CR
        call send
        movlw  0x0A ; LF
        call send
        return

        end