Home Products Prices Directory Order Contact New Books Files Links FAQ
DonTronics Home Page
Bottom of Page

Serin (receive data)

receives a byte or string of bytes serially at 300 to 2400 bps (4 MHz clock). Optionally filters incoming data to a particular range of ASCII characters, such as numbers.

Serin lets a PIC application receive data from another PIC or any computer equipped with an RS-232 serial port.

Before we go into the details of using Serin, let's define a term: Polarity is the sense of the serial input. Normally, a computer that sends data via RS-232 will output it to an inverting line driver. The computer will output +5 volts for 1 and 0 volts for 0. The line driver will invert this and increase the voltage swing so that +10 volts is 0 and -10 volts is 1.

When we say "true" polarity, we mean the computer output (+5V = 1). "Inverted" polarity is like the output of the line driver, but without the wide voltage swing (+5V = 0). When you want to connect the PC's serial output directly to a PIC without a line receiver, use inverted polarity and a series resistor of approximately 22k. Static-protection diodes inside the PIC will clip the input voltage to +5V and ground. The resistor will limit the current from the RS-232 line into the PIC to a safe level.

To use Serin, make the desired pin an input and set up the filter flag. With filtering on, Serin will ignore bytes that fall outside the range of ASCII values defined by filt_lo and filt_hi. In the demo program, these are set to accept only the characters representing numbers 0 through 9. You could set them to A and Z or any other contiguous range of ASCII character values. If you want numeric text converted to binary values--as shown in the next entry, Serin (convert # data)--turn filtering on, and leave t he range set for numbers. Specify the baud rate by moving one of the constants B300 through B2400 into the variable baud. Specify the sense by setting or clearing the polarity bit (0 = true, 1 = inverted). Put the number of characters you wish to receive into bytes.

Put the pin number into pin and the port number into port. Call Serin. The routine will automatically receive the specified number of bytes into a buffer at the end of memory. When Serin returns, the data will be stored starting at buffer-1 and the count (number of bytes received) will be in the location buffer.

The reason Serin records the number of bytes actually received is that it can differ from the value you requested with bytes. When the filter is on, Serin will reject bytes data outside the filter range. When it receives the first byte that meets the filter requirements, it sets a flag called filt_1st. Once this flag is set, Serin will continue to accept bytes until it either receives the number specified by bytes, or a character outside the filter range arrives. This allows Serin to receive variable-length numbers and reject text.

To receive a 16-bit number, you would turn on the filter and put 5 in bytes. Serin would receive from 1 to 5 characters representing numbers from 0 to 65535. Input values must not contain commas; 65,535 would be received as "65".

When the filter is off, the buffer will contain exactly the number of bytes you specified. Serin can receive serial data through any pin of any I/O port, and can change port and pin assignments while the program is running. In many applications, it's enough to assign one pin for serial input and leave it at that. The disk that accompanies this book contains stripped versions of Serin for such applications. The advantage is that these use much less program memory than the routine listed here. Check the files SERIN_2.SRC and SERIN_3.SRC on the accompanying disk.

Serin, like the other routines that accept pin and port arguments, requires the short table Pinz. Remember that tables and subroutines must be located in the first 256 words of a 512-word program memory page.

Demonstrating Serin.

To see Serin in operation, connect the circuit below to an erasable PIC or PIC emulator, such as the Parallax downloader. Assemble and run SERIN.SRC. Make sure to use a 4-MHz clock on the PIC or downloader. Load a terminal program on the PC connected to the PIC and set it for 2400 baud, no parity, 8 data bits, 1 stop bit (N81). Type a few characters and watch the LEDs display the binary equivalents of the received data. To check out the filtering capability, modify the program to set the filter bit, then reassemble and rerun it. Now the LEDs will respond only when you press the number keys 0 through 9.


;
; ***************************************************************************
; ***  Bubble Software Parallax to PIC Source Converter. Copyright 1999.  ***
; ***  http://www.picnpoke.com                 email: sales@picnpoke.com  ***
; ***************************************************************************
;
; SERIN port, pin, baud, polarity, bytes, filter
; Receives data serially at the specified rate and polarity via the specified 
; port pin. Stores the data as a counted string starting at buffer-1 (buffer is 
; the number of bytes in the string). An optional filter causes the routine to
; ignore data outside a range of ASCII character values set by filt_lo and 
; filt_hi. 

        P = pic16c55
        #include <16c55.inc>   ; processor assembler definitions
        _CONFIG _xt_osc & _wdt_off & _protect_off
reset start

buffer  equ     d'31'   ; String storage. 
B2400   equ     d'30'   ; Bit delay for 2400 baud. 
B1200   equ     d'62'   ; Bit delay for 1200 baud. 
B600    equ     d'126'  ; Bit delay for 600 baud. 
B300    equ     d'255'  ; Bit delay for 300 baud. 
filt_lo equ     '0'     ; Set filter for ASCII 
filt_hi equ     '9'     ; chars representing 0-9. 

 org 8
baud    Res     d'1'    ; Baud rate. 
pin     Res     d'1'    ; Pin number (0-7).
port    Res     d'1'    ; Port number (0-2).
bytes   Res     d'1'    ; Number of bytes to receive. 
temp1   Res     d'1'    ; Temporary counter for Serin.
temp2   Res     d'1'    ; Temporary counter for Serin. 
temp3   Res     d'1'    ; Temporary counter for delay.
ser_fl  Res     d'1'    ; Flags for serin switches. 

polarity equ    ser_fl.0        ; Polser_fl.0arity: 0=true, 1=inverted. 
filter  equ     ser_fl.1        ; Ranser_fl.1ge filter: 0=off, 1=on. 
filt_1st equ    ser_fl.2        ; 1stser_fl.2 filter byte passed?: 0=no, 1=yes. 
aux     equ     ser_fl.3        ; Temser_fl.3porary flag for filter comparisons. 

; Device data and reset vector
 org 0
; Table to convert pin number (0-7) into bit mask (00000001b to 10000000b). 
Pinz         ADDWF pcl                  
             RETLW d'1'                 
             RETLW d'2'
             RETLW d'4'
             RETLW d'8'
             RETLW d'16'
             RETLW d'32'
             RETLW d'64'
             RETLW d'128'
; Subroutine used by Serin to get a bit and delay for a number of loops
; set by temp3. Jumping into get_bit:loop provides the delay, but ignores the 
; input bit. 
get_bit      MOVF port,w                ; Point to port. 
             MOVWF fsr
             MOVF indirect,w            ; IF Polarity = 0 THEN w = Port 
             BTFSC ser_fl,d'0'          ; ELSE w = NOT Port
             COMF indirect,w            
             ANDWF pin,w                
             BTFSC status,z             ; IF w AND pin THEN carry = 1
             BCF status,c               ; ELSE carry = 0. 
             BTFSS status,z             
             BSF status,c               
             MOVF temp1,w               ; Point to buffer location. 
             MOVWF fsr
             RRF indirect               ; Rotate carry into msb of data byte.
get_bit_loop GOTO $+1                   ; Two-cycle nops. 
             GOTO $+1                   
             GOTO $+1                   
             GOTO $+1                   
             GOTO $+1                   
             DECFSZ temp3               
             GOTO get_bit_loop
             RETLW 0h                   

; Main program start. Receives a single byte of data, filtered for numeric 
; characters, and displays the data bits on LEDs connected to port RB. 
start        MOVLW d'15'                ; All inputs. 
             TRIS 5h
             MOVLW d'0'                 ; All outputs for LEDs.
             TRIS 6h
             CLRF 7h                    ; Clear the LEDs. 
             CLRF ser_fl                ; Clear serial flags.
             MOVLW d'1'                 ; Receive 1 byte 
             MOVWF bytes
             BCF ser_fl,d'1'            ; not filtered 
             BSF ser_fl,d'0'            ; inverted polarity
             MOVLW B2400                ; at 2400 baud 
             MOVWF baud
             MOVLW d'2'                 ; via pin 2 
             MOVWF pin
             MOVLW d'0'                 ; of port ra. 
             MOVWF port
             CALL Serin                 ; Receive the data. 
             MOVF buffer-1,w            ; Move byte to LEDs on RB. 
             MOVWF 6h
             GOTO start                 ; Endless loop

; Body of the Serin routine. Expects the baud constant in baud, number of
; bytes to receive in bytes, the I/O port (0-2 for RA through RC) in port, 
; the pin number (0-7) in pin, and the flag settings in ser_fl 
Serin        CLRF buffer                ; Clear buffer counter. 
             BCF ser_fl,d'2'            
             MOVLW 5h                   ; Add offset for port RA.
             ADDWF port
             MOVF pin,w                 
             CALL Pinz                  ; Get bit mask from the table. 
             MOVWF pin                  ; Put the mask into pin. 
             MOVLW buffer-1             ; Pointer for first data address. 
             MOVWF temp1
Serin_poll   MOVF port,w                
             MOVWF fsr
             MOVF indirect,w            ; IF Polarity = 0 THEN w = Port 
             BTFSC ser_fl,d'0'          ; ELSE w = NOT Port
             COMF indirect,w            
             ANDWF pin,w                ; IF pin = 0 THEN receive data
             BTFSS status,z             ; ELSE poll
             GOTO Serin_poll
             BCF status,c               
             RRF baud,w                 ; LET temp3 = baud/2
             MOVWF temp3                ; Set up 1/2 bit time delay. 
             CALL get_bit_loop          ; Jump into delay of get_bit.
             MOVF baud,w                ; Set up full bit time delay. 
             MOVWF temp3
             CALL get_bit_loop          ; Jump into delay of get_bit.
             MOVLW d'8'                 ; Eight data bits.      
             MOVWF temp2
Serin_rcv    MOVF baud,w                ; Set up bit delay.
             MOVWF temp3
             CALL get_bit               ; Get the next data bit.
             DECFSZ temp2               ; Eight bits received?
             GOTO Serin_rcv
Serin_done   MOVF baud,w                ; Set up bit delay.
             MOVWF temp3
             CALL get_bit_loop          ; Wait for stop bit.
             BTFSS ser_fl,d'1'          ; IF filter=0 (off) THEN :skip
             GOTO Serin_skip
             BCF ser_fl,d'3'            ; LET aux = 0. 
             MOVLW filt_lo              ; IF byte < filt_lo THEN aux=1
             SUBWF indirect,w
             BTFSS status,c
             BSF ser_fl,d'3'            
             MOVLW ~filt_hi             ; IF byte > filt_hi THEN aux=1
             ADDWF indirect,w
             BTFSC status,c
             BSF ser_fl,d'3'            
             BTFSS ser_fl,d'3'          ; If aux = 0 (byte is within 
             GOTO Serin_skip
             BTFSC ser_fl,d'2'          ; filter range) :skip. If byte is
             RETLW 0h                   ; out of range, but valid bytes have 
             GOTO Serin_poll            ; been received, return. Else poll. 
Serin_skip   BSF ser_fl,d'2'            
             DECF temp1                 ; Decrement buffer pointer. 
             INCF buffer                ; Increment buffer counter. 
             DECFSZ bytes               ; More bytes to receive: poll.
             GOTO Serin_poll
             RETLW 0h                   




; SERIN port, pin, baud, polarity, bytes, filter ; Receives data serially at the specified rate and polarity via the specified  ; port pin. Stores the data as a counted string starting at buffer-1 (buffer is  ; the number of bytes in the string). An optional filter causes the routine to ; ignore data outside a range of ASCII character values set by filt_lo and  ; filt_hi.  buffer  =       31      ; String storage.  B2400   =       30      ; Bit delay for 2400 baud.  B1200   =       62      ; Bit delay for 1200 baud.  B600    =       126     ; Bit delay for 600 baud.  B300    =       255     ; Bit delay for 300 baud.  filt_lo =       '0'     ; Set filter for ASCII  filt_hi =       '9'     ; chars representing 0-9.          org     8 baud    ds      1       ; Baud rate.  pin     ds      1       ; Pin number (0-7). port    ds      1       ; Port number (0-2). bytes   ds      1       ; Number of bytes to receive.  temp1   ds      1       ; Temporary counter for Serin. temp2   ds      1       ; Temporary counter for Serin.  temp3   ds      1       ; Temporary counter for delay. ser_fl  ds      1       ; Flags for serin switches.  polarity        =       ser_fl.0        ; Polarity: 0=true, 1=inverted.  filter          =       ser_fl.1        ; Range filter: 0=off, 1=on.  filt_1st        =       ser_fl.2        ; 1st filter byte passed?: 0=no, 1=yes.  aux             =       ser_fl.3        ; Temporary flag for filter comparisons.  ; Device data and reset vector         device  pic16c55,xt_osc,wdt_off,protect_off         reset   start         org     0 ; Table to convert pin number (0-7) into bit mask (00000001b to 10000000b).  Pinz    jmp     pc+w         retw    1,2,4,8,16,32,64,128 ; Subroutine used by Serin to get a bit and delay for a number of loops ; set by temp3. Jumping into get_bit:loop provides the delay, but ignores the  ; input bit.  get_bit mov     fsr,port        ; Point to port.          mov     w,indirect      ; IF Polarity = 0 THEN w = Port          snb     Polarity        ; ELSE w = NOT Port         mov     w,/indirect         AND     w,pin            snz                     ; IF w AND pin THEN carry = 1         clc                     ; ELSE carry = 0.          sz         stc         mov     fsr,temp1       ; Point to buffer location.          rr      indirect        ; Rotate carry into msb of data byte. :loop   jmp     $+1             ; Two-cycle nops.          jmp     $+1         jmp     $+1         jmp     $+1         jmp     $+1         djnz    temp3,:loop         ret ; Main program start. Receives a single byte of data, filtered for numeric  ; characters, and displays the data bits on LEDs connected to port RB.  start   mov     !ra, #15        ; All inputs.          mov     !rb,#0          ; All outputs for LEDs.         clr     rc              ; Clear the LEDs.          clr     ser_fl          ; Clear serial flags.         mov     bytes,#1        ; Receive 1 byte          clrb    filter          ; not filtered          setb    polarity        ; inverted polarity         mov     baud,#B2400     ; at 2400 baud          mov     pin,#2          ; via pin 2          mov     port,#0         ; of port ra.          call    Serin           ; Receive the data.          mov     rb,buffer-1     ; Move byte to LEDs on RB.          jmp     start           ; Endless loop ; Body of the Serin routine. Expects the baud constant in baud, number of ; bytes to receive in bytes, the I/O port (0-2 for RA through RC) in port,  ; the pin number (0-7) in pin, and the flag settings in ser_fl  Serin   clr     buffer  ; Clear buffer counter.          clrb    filt_1st         ADD     port,#RA        ; Add offset for port RA.         mov     w,pin         call    Pinz            ; Get bit mask from the table.          mov     pin,w           ; Put the mask into pin.          mov     temp1,#buffer-1 ; Pointer for first data address.  :poll   mov     fsr,port         mov     w,indirect      ; IF Polarity = 0 THEN w = Port          snb     Polarity        ; ELSE w = NOT Port         mov     w,/indirect         AND     w,pin           ; IF pin = 0 THEN receive data         jnz     :poll           ; ELSE poll         clc         mov     w,>>baud        ; LET temp3 = baud/2         mov     temp3,w         ; Set up 1/2 bit time delay.          call    get_bit:loop    ; Jump into delay of get_bit.         mov     temp3,baud      ; Set up full bit time delay.          call    get_bit:loop    ; Jump into delay of get_bit.         mov     temp2,#8        ; Eight data bits.       :rcv    mov     temp3,baud      ; Set up bit delay.         call    get_bit         ; Get the next data bit.         djnz    temp2,:rcv      ; Eight bits received? :done   mov     temp3,baud      ; Set up bit delay.         call    get_bit:loop    ; Wait for stop bit.         jnb     filter,:skip    ; IF filter=0 (off) THEN :skip         clrb    aux             ; LET aux = 0.          csae    indirect,#filt_lo       ; IF byte < filt_lo THEN aux=1         setb    aux         csbe    indirect,#filt_hi       ; IF byte > filt_hi THEN aux=1         setb    aux         jnb     aux,:skip       ; If aux = 0 (byte is within          snb     filt_1st        ; filter range) :skip. If byte is         ret                     ; out of range, but valid bytes have          jmp     :poll           ; been received, return. Else poll.  :skip   setb    filt_1st         dec     temp1           ; Decrement buffer pointer.          inc     buffer          ; Increment buffer counter.          djnz    bytes,:poll     ; More bytes to receive: poll.         ret
See also:
http://www.piclist.com/techref/microchip/rs232.htm
http://www.piclist.com/techref/microchip/rangechk.htm
 
 
Home Products Prices Directory Order Contact New Books Files Links FAQ

DonTronics Home Page

Send us a message
Copyright © 1996-2001 DonTronics
Top of Page