Myke's Home Page

Book CD-ROM Home

File Copying/Harddrive Setup

Development Tools

Experiments

Projects

Useful Code Snippets and Macros

Introduction to Electronics

Introduction to Programming

Datasheets

PCBs

Links

McGraw-Hill Professional Publishing

"BasicRS" Experiment

The second RS-232 interface application uses a PICmicro device which does not have a built in RS-232 port and does not use a negative voltage generator (the MAX232 in TrueRS). This experiment is really more typical of the kind of PICmicro applications you will be working with.

This experiment uses the circuit shown below:

The parts needed for this experiment are listed in the table:

Part Description Required for the YAP-II?
PICmicro® MCU PIC16F84-04/P
PIC16F877-04/P
In Socket
Vdd/Vss Decoupling Capacitor 0.1 uF (Any Type) No
_MCLR Pull Up Resistor 10K, 1/4 Watt No
4 MHz Ceramic Resonator Three Leaded Ceramic Resonator with Built in 27-33pF Capacitors No
DS275/DS1275 Dallas Semiconductor DS275 or DS1275 in 8-pin "DIP" Package No
9-Pin Female "D-Shell" Connector Modified and wired to the PC as discussed in the Book No
Breadboard Any Type No
+5 Volt "Vcc" Power Supply Any Type No

Using a breadboard, the experiment is wired using the guide:

The circuit can also be built on a YAP-II using the guide:

The source code listed below can be accessed from the CD-ROM by clicking Here. Note that the code uses the "Macro Calculator" to find constant values instead of having the application author doing the work.

 title  "BasicRS - Simple 3-Wire RS-232 Application"
;
;  This Application Implements a simple "3 Wire" RS-232 Link
;   to another Computer.  A Interrupt Based Bit Banging 
;   Routine is used instead of a USART.   
;
;
;  Hardware Notes:
;   PIC16F84 Running at 4 MHz
;   _MCLR is Pulled Up
;   RC7 - Serial Receive Pin
;   RC6 - Serial Transmit Pin
;
;  Myke Predko
;  99.12.31
;
  LIST R=DEC
 ifdef __16F84
  INCLUDE "p16f84.inc"
 else
 ifdef __16F877
  INCLUDE "p16f877.inc"
 endif

;  Registers
 CBLOCK 0x020
Dlay:2
_w, _status
TXCount, TXByte
RXCount, RXByte
 ENDC

#define TX PORTB, 4
#define RX PORTB, 3


 PAGE
 ifdef __16F84
 __CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _PWRTE_ON
 else
 __CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _PWRTE_ON & _DEBUG_OFF & _LVP_OFF & _BODEN_OFF
 endif

;  Mainline of TrueRS
  org    0

  nop

 variable TMRDlay, TMRReset, PreScaler, PreScalerDlay, TMRActual, RTCActual, TMRError

TMRDlay = 4000000 / (1200 * 3 * 4)
TMRDlay = TMRDlay - 8
PreScalerDlay = 0
PreScaler = 2
                        
TMRReset = TMRDlay / PreScaler
TMRActual = TMRReset * PreScaler
TMRError = ((TMRDlay - TMRActual) * 100) / TMRDlay
RTCActual = TMRActual + 9
RTCActual = ((RTCActual * 100000) / (4000000 / 4)) * 10

  goto   Mainline		;  Jump Past the Interrupt Handler

 org     4
Int				;  PICmicro Interrupt Handler

  movwf  _w			;  Save the Context Registers
  movf   STATUS, w
  movwf  _status

  bcf    INTCON, T0IF	;  Reset the Timer Overflow Interrupt

  movlw  256 - TMRReset ;  Reset the Timer
  movwf  TMR0

  movf   TXCount, f	;  If Transmitting, Can't Receive
  btfsc  STATUS, Z
   goto  _DoRX

  movlw  0x004		;  Interrupt Transmit Increment Value
  addwf  TXCount, f
  btfss  STATUS, DC	;  Send the Next Byte?
   goto  _TXSendDlayCheck

  bsf    TXCount, 2	;  Want to Increment 3x not Four for each byte

  bsf    STATUS, C
  rrf    TXByte, f

  movf   PORTB,  w	;  Send Next Bit
  andlw  0x0FF ^ (1 << 4)
  btfsc  STATUS, C
   iorlw 1 << 4
  movwf  PORTB		;  Cycle 12 is the Bit Send

  goto   _IntEnd

_TXSendDlayCheck		;  Don't Send Bit, Check for Start Bit

  btfss  TXCount, 0	;  Bit Zero Set (Byte to Send)?
   goto  _TXNothingtoCheck

  goto   $ + 1		;  Send Bit at Start of Cycle 12

  movlw  0x004		;  Setup the Timer to Increment 3x
  movwf  TXCount

  bcf    TX			;  Output the Start Bit

  goto   _IntEnd

_TXNothingtoCheck		;  Nothing Being Sent?

  movf   TXCount, w
  xorlw  0x004		;  Zero (Originally) TXCount?
  btfsc  STATUS, Z
   clrf  TXCount

  movf   TXCount, w	;  Sent 10 Bits?
  xorlw  0x09C
  btfsc  STATUS, Z             
   clrf  TXCount		;  Yes, Clear "TXCount" for Next Byte

  goto   _IntEnd

_DoRX
;  #### - Put in Receive Interrupt Code
;
;  RXCount Bit 1  Bit 0
;              0      0  - Waiting for Character to Come In
;              0      1  - Receiving Character
;              1      0  - Have Received Valid Character
;              1      1  - Error Receiving, Clear Buffer/RXCount
;

  movlw  0x004		;  Check for Bit?
  addwf  RXCount, f
  btfss  STATUS, DC
   goto  _RXNo		;  Nothing to Check for (Yet)

  movf   RXCount, w	;  At the End?  
  xorlw  0x091		
  btfsc  STATUS, Z
   goto  _RXNo

  bcf    STATUS, C 	;  Read the Current Bit
  btfsc  RX
   bsf   STATUS, C
  rrf    RXByte, f

  bsf    RXCount, 2     ;  Start Counting from 4

  goto   _IntEnd		;  Finished Receiving Byte

_RXAtEnd			;  Check Last Bit
  btfss  RX                      
   goto  _RXOverrun	;  Not Valid - Error

  movlw  2			;  Valid - Save Value
  movwf  RXCount

  goto   _IntEnd

_RXNo				;  No Bit to Receive

  movf   RXCount, w
  xorlw  0x09D		;  Read with Stop Bit?
  btfsc  STATUS, Z
   goto  _RXAtEnd

  btfsc  RXCount, 0	;  Something Running?
   goto  _IntEnd		;   - Yes, Skip Over

  btfss  RXCount, 3	;  Checking Start Bits?
   goto  _RXStart

  btfsc  PORTB,  3
   bcf   RXCount, 3	;  Nothing - Keep Waiting

  bsf    RXCount, 0	;  Mark it has Started

  btfss  RXCount, 1	;  Something Already Saved?
   goto  _IntEnd

_RXOverrun			; Error - Mark the Overrun

  movlw  0x003
  movwf  RXCount

  goto   _IntEnd

_RXStart			;  Check for Low

  btfsc  PORTB,  3
   bcf   RXCount, 2	;  Don't Have a "Start" Bit

;  #### - Finished with the Receive Interrupt Code

_IntEnd

  movf   _status, w	;  Restore the Context Registers
  movwf  STATUS
  swapf  _w, f
  swapf  _w, w

  retfie

Mainline

  bsf    TX			;  Initialize the Output Port
  bsf    STATUS, RP0
  bcf    TX
  movlw  0x0D0 + PreScalerDlay  ;  Set up the Timer
  movwf  OPTION_REG ^ 0x080
  bcf    STATUS, RP0

  call   Delay		;  Delay 200 msecs before Sending

  clrf   TXCount		;  Make Sure Nothing is Happening
  clrf   RXCount		;   On Boot

  bsf    INTCON, T0IE	;  Initialize the Interrupt Handler
  bsf    INTCON, GIE

  movlw  256 - TMRReset ;  Start the Timer Going
  movwf  TMR0

  movlw  "*"		;  Send out a Start Character
  call   NRZSend

Loop

  call   NRZReceive	;  Wait for a Serial Byte to be Received

  addlw  255 - 'z'	;  Get the High limit
  addlw  'z' - 'a' + 1	;  Add Lower Limit to Set Carry
  btfss  STATUS, C	;  If Carry Set, then Lower Case
  addlw  h'20'		;   Carry NOT Set, Restore Character
  addlw  'A'		;  Add 'A' to restore the Character

  call   NRZSend

  goto   Loop


NRZSend			;  Send the Value in "w" Serially
  movf   TXCount, f	;  Wait for Previous Data Sent
  btfss  STATUS, Z
   goto  $ - 2		;  Counter = 0 when Sent
  movwf  TXByte
  bsf    TXCount, 0	;  Indicate there is Data to Send
  return

NRZReceive			;  Wait for a New Character to be Received
  btfss  RXCount, 1	;  Bit 0 Set when Data Received
   goto  $ - 1
  movf   RXByte, w	;  Get the Received Byte
  clrf   RXCount
  bcf    STATUS, C	;  Carry Reset - No Error
  return

Delay

  clrf   Dlay
  clrf   Dlay + 1
  decfsz Dlay, f
   goto  $ - 1
  decfsz Dlay + 1, f
   goto  $ - 3

  return


 end
              

Click Here to look at the forty third experiment - SimpRS