PIC Tutorial Seven - RS232
For these tutorials you require the Main Board, Main Board 2, LCD Board, Serial Board, LED Board and switch board. Download zipped tutorial files, a number of examples for the 16F876 based Main Board 2 are provided, these have an 'a' at the end of the filename - the rest are left for the user to convert as an exercise.
RS232 is an asynchronous serial communications protocol, widely used on computers. Asynchronous means it doesn't have any separate synchronising clock signal, so it has to synchronise itself to the incoming data - it does this by the use of 'START' and 'STOP' pulses. The signal itself is slightly unusual for computers, as rather than the normal 0V to 5V range, it uses +12V to -12V - this is done to improve reliability, and greatly increases the available range it can work over - it isn't necessary to provide this exact voltage swing, and you can actually use the PIC's 0V to 5V voltage swing with a couple of resistors to make a simple RS232 interface which will usually work well, but isn't guaranteed to work with all serial ports. For this reason I've designed the Serial Board to use the MAX232 chip, this is a chip specially designed to interface between 5V logic levels and the +12V/-12V of RS232 - it generates the +12V/-12V internally using capacitor charge pumps, and includes four converters, two transmit and two receive, the Serial Board only makes use of one of each - the other two are clearly marked on the circuit, and can be used for something else if required.
There are various data types and speeds used for RS232, I'm going to concentrate on the most common type in use, known as 8N1 - the 8 signifies '8 Data Bits', the N signifies 'No Parity' (can also be E 'Even Parity' or O 'Odd Parity'), the final 1 signifies '1 Stop Bit'. The total data sent consists of 1 start bit, 8 data bits, and 1 stop bit - giving a total of 10 bits. For the speed, I'm going to concentrate on 9600BPS (Bits Per Second), as each byte sent has 10 bits this means we can transfer a maximum of 960 bytes of data per second - this is fairly fast, but pretty easy to do in software, it's easily modified if you need faster or slower speeds, all you need to do is alter the delay timings - but I find 9600BPS is a pretty good speed to use.
We now know that we will be sending or receiving 960 ten bit data bytes per second, from that it's simple to calculate how long each bit is - simply divide 1 second by 9600 - this gives 104uS per bit. This value is crucial to successful RS232 communication, it doesn't have to be exact as the stop pulse allows resynchronisation after each data byte, but it must be accurate enough to maintain reading in the correct bit throughout each byte. The data is sent low bit first, so the example in the diagrams below is sending '01001011 Binary', '4B Hex', '75 Decimal'.
OK, now we know all the details of the protocol we are using, I'll explain how we transmit a byte:
To receive a data byte is pretty straightforward as well:
Here are the actual serial routines we will be using, they consist of a number of small subroutines, and require four data registers allocating:
The routines themselves consist of three subroutines that are called, and two internal subroutines, not normally called from elsewhere:
;Serial routines Xmit_Byte Equ 0x20 ;holds byte to xmit Rcv_Byte Equ 0x21 ;holds received byte Bit_Cntr Equ 0x22 ;bit counter for RS232 Delay_Count Equ 0x23 ;delay loop counter SER_INIT BSF STATUS, RP0 ;select bank 1 BCF TRISB, 6 ;set B6 as an output BSF TRISB, 7 ;set B7 as an input BCF STATUS, RP0 ;select bank 0 BSF PORTB, 6 ;set B6 high RETURN XMIT_RS232 MOVWF Xmit_Byte ;move W to Xmit_Byte MOVLW 0x08 ;set 8 bits out MOVWF Bit_Cntr BCF PORTB, 6 CALL Bit_Delay Ser_Loop RRF Xmit_Byte , f ;send one bit BTFSS STATUS , C BCF PORTB, 6 BTFSC STATUS , C BSF PORTB, 6 CALL Bit_Delay DECFSZ Bit_Cntr , f ;test if all done GOTO Ser_Loop BSF PORTB, 6 CALL Bit_Delay RETURN Rcv_RS232 BTFSC PORTB, 7 ;wait for start bit GOTO Rcv_RS232 CALL Start_Delay ;do half bit time delay BTFSC PORTB, 7 ;check still in start bit GOTO Rcv_RS232 MOVLW 0x08 ;set up to read 8 bits MOVWF Bit_Cntr CLRF Rcv_Byte Next_RcvBit CALL Bit_Delay BTFSS PORTB, 7 BCF STATUS , C BTFSC PORTB, 7 BSF STATUS , C RRF Rcv_Byte , f DECFSZ Bit_Cntr , f ;test if all done GOTO Next_RcvBit CALL Bit_Delay MOVF Rcv_Byte, W RETURN Start_Delay MOVLW 0x0C MOVWF Delay_Count Start_Wait NOP DECFSZ Delay_Count , f GOTO Start_Wait RETURN Bit_Delay MOVLW 0x18 MOVWF Delay_Count Bit_Wait NOP DECFSZ Delay_Count , f GOTO Bit_Wait RETURN
The routines presented here use PortB pin 6 as the output, and PortB pin 7 as the input, they are based on a 4MHz clock frequency. As it's all done in software you can easily change the port and pin designations, and simply alter the delay timings for different clock speeds or baud rates.
Tutorial 7.1 - required hardware, Main Board and Serial Board.
This first sample program simply transmits a few ASCII characters out of the serial board, it displays 'RS232'. In this example each character is individually loaded in to the W register and the XMIT_RS232 subroutine is called.
Tutorial 7.2 - required hardware, Main Board and Serial Board.
This second sample program transmits two lines of text, the text is stored as a string (terminated by '0x00') in the top page of memory, the two characters '0x0A' and '0x0D' in the string are LF and CR to move the cursor to the start of the next line. The XMIT_RS232 subroutine is called repeatedly in the loop which reads the string.
Tutorial 7.3 - required hardware, Main Board, LCD Board and Serial Board.
This third sample program receives data one character at a time and displays it on the LCD module. Please note that both this, and the next tutorial, can only handle one character at a time - as there's no handshaking involved the routine on the PIC must finish whatever it has to before the next character arrives - if a continuous stream of data is incoming it only has 52uS before the next byte arrives, and this is too fast for the LCD to have finished displaying the previous character. There are various ways of overcoming this - firstly, as long as you are typing the characters on the keyboard there won't be a problem (you can't type fast enough), secondly you could arrange for the transmitted protocol to have more than one stop bit (two stop bits would give three times as long to display the characters, three stop bits would give five times as long, and so on). Or you could buffer the characters in PIC data registers, this still wouldn't allow a continuous data stream, but would probably do all that's required. (For a further possibility see Tutorial 7.7a)
Tutorial 7.4 - required hardware, Main Board, LCD Board and Serial Board.
This fourth sample program receives data one character at a time, displays it on the LCD module (as in 7.3) and then echo's the character back to the PC screen.
Tutorial 7.5 - required hardware, Main Board, LED Board and Serial Board.
This fifth sample program receives data one character at a time, displays it on the LED board and then echo's the character back to the PC screen, the ports have been swapped around (PortA now connects to the serial board, and PortB connects to the LED board, because pin A4 is an open-collector output). This would make a nice simple way of providing eight switched outputs controlled from a serial port.
Tutorial 7.6 - required hardware, Main Board, Switch Board and Serial Board.
This sixth sample program receives one data byte from the PC (any byte - just to initiate a read), reads the switches connected to PortB, and sends the result back to the PC as a string of eight 1's and 0's - B0 first, and B7 last - followed by CRLF. If you examine the code, the routine for sending the PortB reading as a series of ASCII 1's and 0's is based on the XMIT_RS232 code, it reads the bits in turn in exactly the same way, only the action taken for each bit is different. As the previous example makes a nice easy way of writing eight bits, this one makes a nice easy way of reading eight bits.
Tutorial 7.7a - required hardware, Main Board 2, LCD Board and Serial Board.
This seventh sample program works exactly like Tutorial 7.4, but is based on the 16F876 at 20MHz, and uses the hardware USART rather than software emulation. As it uses hardware to receive the serial data, this gives a lot more time for processing and displaying characters, around 1mS or so. There isn't a 16F628 version of this tutorial yet as I have to change the serial board connections over, as soon as this is done I'll post a 16F628 version as well - if you want to do it, the values for the USART are SPBRG=25 and BRGH=1.