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.
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.
; 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