transmits a byte or string of bytes serially at 300 to 2400 bps (4 MHz clock).
Serout lets a PIC application transmit data to another PIC or any computer equipped with an RS-232 serial port.
If you have not already done so, please read the discussion in paragraph two of the first Serin entry (page 74) on the meaning of "polarity" as it applies to these serial routines.
When you want to connect the PIC's serial output directly to a computer without a line driver, use inverted polarity. Even though the voltage swing isn't legal RS-232, this will generally work, provided cables are kept short.
To use Serout, put the desired pin into the stop-bit state (0 for inverted output, 1 for true) and make the pin an output. This will prevent sending a false start bit to the receiver.
Next, create a string of the bytes you want to transmit at the location labeled buffer. Store the number of bytes at buffer, the first byte at buffer-1, the second byte at buffer-2, and so on.
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 pin number into pin and the port number into port. Call Serout. The routine will automatically send each byte of the string.
When Serout returns, the data starting at buffer-1 will be intact, but the count (at buffer) will have been cleared to 0.
Note that Serout permits your program to make a serious mistake; If the count at buffer is 0 when Serout is called, the routine will attempt to send 256 bytes of data. It will alter ports and control registers in the lower seven or eight bytes of RAM. Make sure that buffer contains the correct count before calling Serout.
If your application requires sending a number out the serial port as a text string, see the next entry, Serout (format # data). It converts a 16-bit value into a Serout string with an optional fixed decimal point.
Note that this version of Serout does not support the open-drain/open-source capabilities of the PBASIC version. Those require manipulation of the TRIS register, which we've avoided in this series of subroutines.
Serout can transmit 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 output and leave it at that. The disk that accompanies this book contains stripped versions of Serout for such applications. The advantage is that they use less program memory than the routine listed here. Check the files SEROUT_2.SRC and SEROUT_3.SRC on the accompanying disk.
Serout, 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 Serout in operation, connect the circuit below to an erasable PIC or PIC emulator, such as the Parallax downloader. Assemble and run SEROUT.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). When you apply power to the PIC or reset the downloader, the letters "OK" will appear on the PC screen.
; ; *************************************************************************** ; *** Bubble Software Parallax to PIC Source Converter. Copyright 1999. *** ; *** http://www.bubblesoftonline.com email: sales@picnpoke.com *** ; *************************************************************************** ; ; SEROUT port (in w), pin, baud, polarity, data ; Transmits data serially at the specified rate and polarity out the specified port ; pin. Data bytes to be transmitted must be arranged in memory starting at the ; address "buffer-1" and working downward (e.g., 30,29,28...). The number of ; bytes to transmit must be stored at the address labeled "buffer." A companion ; routine, BIN_ASC, converts 16-bit numbers to this form, optionally adding a ; decimal point. See the listing for Serout ...(format # data). ; Serout uses the common data format of no parity, 8 data ; bits, 1 stop bit (N81). ; Device data and reset vector P = pic16c55 #include <16c55.inc> ; processor assembler definitions _CONFIG _xt_osc & _wdt_off & _protect_off reset start buffer equ d'31' ; String storage at end of memory. B2400 equ d'30' ; Bit delay for 2400 baud at 4MHz. B1200 equ d'62' ; Bit delay for 1200 baud at 4MHz. B600 equ d'126' ; Bit delay for 600 baud at 4MHz. B300 equ d'254' ; Bit delay for 300 baud at 4MHz. org 8 baud Res d'1' ; Baud rate. pin Res d'1' ; Pin number (0-7). port Res d'1' ; Port number (0-2). temp1 Res d'1' ; Temporary counter for Serout. temp2 Res d'1' ; Temporary counter for Serout. temp3 Res d'1' ; Temporary counter for delay. polarity equ PA2 ; Polarity: 0=true, 1=inverted. ; Note that the polarity flag is the unused page-address bit of the PIC 16C5x ; series. If you port this program to another type of PIC, or another routine uses ; this bit, you may have to reassign it. 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 Serout to send a bit with the specified polarity (true or ; inverted) and timing (300, 600, 1200, or 2400 bps). emitBit MOVF port,w ; Point to the output port. MOVWF fsr MOVF baud,w ; Load baud rate into temp counter. MOVWF temp3 MOVF status,w ; Copy carry bit (data bit) into w. BTFSC status,pa2 ; If polarity = 1 then invert w.0. XORLW d'1' ANDLW d'1' ; Copy w.0 back to carry bit. BCF status,c ; (This roundabout method of inverting BTFSC status,z ; carry is needed since "XOR status,w" BSF status,c ; doesn't work properly.) ; This loop deserves some explanation. The first time through, it sets or clears ; the serial output bit. Thereafter, it's just a delay loop. emitBit_loop MOVF pin,w ; Get the pin mask. BTFSS status,c ; Data in carry bit. IORWF indirect ; If carry = 0 then set bit. COMF pin,w BTFSC status,c ANDWF indirect ; Else if carry = 1 then clear bit. GOTO $+1 ; Two-cycle nops for time delay. GOTO $+1 DECFSZ temp3 ; Number of trips through loop GOTO emitBit_loop RETLW 0h ; set by baud rate in temp3. ; Start of demo program. Upon power up or reset, the PIC transmits the string ; "OK" via pin 2 of port ra at 2400 baud, inverted polarity start CLRF 5h ; High is a start bit, so hold ra low. MOVLW d'0' ; All outputs. TRIS 5h MOVLW d'2' ; Put test string "OK" MOVWF buffer MOVLW 'O' ; into the buffer, starting with the MOVWF buffer-1 MOVLW 'K' ; number of characters. MOVWF buffer-2 BSF status,pa2 ; Inverted for direct connection. MOVLW B2400 ; 2400 baud. MOVWF baud MOVLW d'2' ; Pin 2. MOVWF pin MOVLW d'0' ; of port ra. MOVWF port CALL Serout ; Send the data. GOTO $ ; Endless loop ; Upon entry, the desired pin must already be set up as an output. ; The w register contains a number representing the output port (0-2) for ; RA through RC. Variable "pin" contains the pin number (0-7). The ; variable baud must contain a number representing the baud rate. ; The polarity flag must be set (1) for true, or cleared (0) for inverted ; output. A data string consisting of the number of bytes, followed by the ; bytes arranged downward in memory, must be at the location "buffer." ; Upon return, the data in the buffer will be unchanged, but the 0th entry ; (representing the string length) will have been decremented to 0. Serout 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 ; Point to first data address. MOVWF temp1 Serout_xmit BCF status,c ; Start bit into carry CALL emitBit ; Send start bit. MOVLW d'8' ; Send 8 data bits. MOVWF temp2 Serout_bits MOVF temp1,w ; Point to data byte. MOVWF fsr RRF indirect ; Rotate bit 0 into carry. CALL emitBit ; Send the data bit. DECFSZ temp2 ; All 8 bits sent? No: send more bits. GOTO Serout_bits MOVF temp1,w ; Point to the data byte. MOVWF fsr RRF indirect ; Rotate it back into original position. BTFSS status,pa2 ; If it was inverted, invert it again to COMF indirect ; restore original. BSF status,c ; Move stop bit into carry CALL emitBit ; Send the stop bit. DECF temp1 ; Point to next data byte. DECFSZ buffer ; All bytes sent? No: send more bytes. GOTO Serout_xmit RETLW 0h ; Yes: return. end
; SEROUT port (in w), pin, baud, polarity, data ; Transmits data serially at the specified rate and polarity out the specified port ; pin. Data bytes to be transmitted must be arranged in memory starting at the ; address "buffer-1" and working downward (e.g., 30,29,28...). The number of ; bytes to transmit must be stored at the address labeled "buffer." A companion ; routine, BIN_ASC, converts 16-bit numbers to this form, optionally adding a ; decimal point. See the listing for Serout ...(format # data). ; Serout uses the common data format of no parity, 8 data ; bits, 1 stop bit (N81). buffer = 31 ; String storage at end of memory. B2400 = 30 ; Bit delay for 2400 baud at 4MHz. B1200 = 62 ; Bit delay for 1200 baud at 4MHz. B600 = 126 ; Bit delay for 600 baud at 4MHz. B300 = 254 ; Bit delay for 300 baud at 4MHz. org 8 baud ds 1 ; Baud rate. pin ds 1 ; Pin number (0-7). port ds 1 ; Port number (0-2). temp1 ds 1 ; Temporary counter for Serout. temp2 ds 1 ; Temporary counter for Serout. temp3 ds 1 ; Temporary counter for delay. polarity = PA2 ; Polarity: 0=true, 1=inverted. ; Note that the polarity flag is the unused page-address bit of the PIC 16C5x ; series. If you port this program to another type of PIC, or another routine uses ; this bit, you may have to reassign it. ; 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 Serout to send a bit with the specified polarity (true or ; inverted) and timing (300, 600, 1200, or 2400 bps). emitBit mov fsr,port ; Point to the output port. mov temp3,baud ; Load baud rate into temp counter. mov w,status ; Copy carry bit (data bit) into w. snb polarity ; If polarity = 1 then invert w.0. XOR w,#1 AND w,#1 ; Copy w.0 back to carry bit. clc ; (This roundabout method of inverting snz ; carry is needed since "XOR status,w" stc ; doesn't work properly.) ; This loop deserves some explanation. The first time through, it sets or clears ; the serial output bit. Thereafter, it's just a delay loop. :loop mov w,pin ; Get the pin mask. sc ; Data in carry bit. OR indirect,w ; If carry = 0 then set bit. mov w,/pin snc AND indirect,w ; Else if carry = 1 then clear bit. jmp $+1 ; Two-cycle nops for time delay. jmp $+1 djnz temp3,:loop ; Number of trips through loop ret ; set by baud rate in temp3. ; Start of demo program. Upon power up or reset, the PIC transmits the string ; "OK" via pin 2 of port ra at 2400 baud, inverted polarity start clr ra ; High is a start bit, so hold ra low. mov !ra, #0 ; All outputs. mov buffer,#2 ; Put test string "OK" mov buffer-1,#'O' ; into the buffer, starting with the mov buffer-2,#'K' ; number of characters. setb polarity ; Inverted for direct connection. mov baud,#B2400 ; 2400 baud. mov pin,#2 ; Pin 2. mov port,#0 ; of port ra. call Serout ; Send the data. jmp $ ; Endless loop ; Upon entry, the desired pin must already be set up as an output. ; The w register contains a number representing the output port (0-2) for ; RA through RC. Variable "pin" contains the pin number (0-7). The ; variable baud must contain a number representing the baud rate. ; The polarity flag must be set (1) for true, or cleared (0) for inverted ; output. A data string consisting of the number of bytes, followed by the ; bytes arranged downward in memory, must be at the location "buffer." ; Upon return, the data in the buffer will be unchanged, but the 0th entry ; (representing the string length) will have been decremented to 0. Serout 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 ; Point to first data address. :xmit clc ; Start bit into carry call emitBit ; Send start bit. mov temp2,#8 ; Send 8 data bits. :bits mov fsr,temp1 ; Point to data byte. rr indirect ; Rotate bit 0 into carry. call emitBit ; Send the data bit. djnz temp2,:bits ; All 8 bits sent? No: send more bits. mov fsr,temp1 ; Point to the data byte. rr indirect ; Rotate it back into original position. sb polarity ; If it was inverted, invert it again to NOT indirect ; restore original. stc ; Move stop bit into carry call emitBit ; Send the stop bit. dec temp1 ; Point to next data byte. djnz buffer,:xmit ; All bytes sent? No: send more bytes. ret ; Yes: return.
See also: