; serial.asm ; half-duplex software UART (hopefully) ; Adapted from Microchip App note AN555 ; start out making serial output work ; then do serial input ; then do control ; Include the header file for our target chip #include "p16f84.inc" ; First line, declare that we want a 16F84 PIC ; and that our numbers will be in Hexadecimal ; unless otherwise noted LIST P=16f84, R=HEX ; Tell the programmer what options we want to use ; In this case: ; _WDT_OFF -- Watchdog Timer Off ; _XT_OSC -- Crystal Oscillator ; _CP_OFF -- Code Protect Off __CONFIG _WDT_OFF & _XT_OSC & _CP_OFF ; Let PORTA be for serial XMT/RCV ; and also control ; PORTB will be our 8-bit I/O ; Serial port at 4800baud = 208uS period ; Variables RxBits equ 10h ; state of output port TxBits equ 11h ; state of input port TxData equ 12h ; byte to output, destroyed in process RxData equ 13h WRegSave equ 14h ; place to store W in interrupt StatusSave equ 15h ; stores STATUS in interrupt PortStatus equ 16h ; serial port control flags index equ 0Ch delay1 equ 0Dh #define RxInProgress PortStatus, 0 #define TxInProgress PortStatus, 1 #define TxStopBit PortStatus, 2 #define RxError PortStatus, 3 #define RxDone PortStatus, 4 #define CycleOffset h'0e' ; fudge factor in interrupt timing #define BitPeriod d'208' ; 208 us = 208 instructions w/4MHz crystal #define DataBits d'8' ; 8 bits #define TX PORTA, 0 #define RX PORTA, 4 org 0 goto Main org 4 goto Interrupt Interrupt: btfss INTCON, T0IF ; test for other interrupts retfie ; and return on them movwf WRegSave ; save accumulator swapf STATUS, w ; operation doesn't affect status bits movwf StatusSave ; save (nibble-flipped) status reg btfsc TxInProgress ; check to see if we're transmitting goto TransmitNextBit ; handle it btfsc RxInProgress ; check to see if we're receiving goto ReceiveNextBit ; handle it goto RxStartBit ; otherwise, it must be a start bit interrupt ; restore status, w and return from interrupt EndOfInterrupt: swapf StatusSave, w ; unflip and restore status reg movwf STATUS swapf WRegSave, f ; restore W reg without affecting status reg swapf WRegSave, w bcf INTCON, T0IF ; reset TMR0 interrupt flag retfie TransmitNextBit: bcf STATUS, RP0 ; make sure we're in bank 0 movlw -BitPeriod + CycleOffset ; load TMR0 to send next bit movwf TMR0 movf TxBits, f ; check to see if transmission is over btfsc STATUS, Z goto TransmitFinished ; if it is, send a stop bit decf TxBits, f goto TransmitDataBit TransmitFinished: btfsc TxStopBit ; need to make sure we spend enough time sending goto StopBitDone ; a stop bit, so spend another 208us transmitting bsf TX ; stop bit is high bsf TxStopBit goto EndOfInterrupt StopBitDone: bcf TxStopBit bcf INTCON, T0IE ; disable interrupt bcf TxInProgress ; stop transmission goto EndOfInterrupt TransmitDataBit: rrf TxData, f btfss STATUS, C bcf TX btfsc STATUS, C bsf TX goto EndOfInterrupt TransmitStartBit: bsf STATUS, RP0 bcf OPTION_REG, T0CS bsf INTCON, T0IE bsf INTCON, GIE bcf STATUS, RP0 bcf TX ; start bit = low movlw -BitPeriod movwf TMR0 return ; --------------------------------------------- ; SendByte ; sends a byte in W out over the serial port ; --------------------------------------------- SendByte: bsf TxInProgress movwf TxData movlw DataBits movwf TxBits call TransmitStartBit retfie ReceiveNextBit: ; bsf STATUS, RP0 ; bank 1 ; bsf OPTION, T0CS bcf STATUS, RP0 movlw -BitPeriod + CycleOffset ; load TMR0 to send next bit movwf TMR0 movf RxBits, f ; check to see if transmission is over btfsc STATUS, Z goto ReceiveFinished ; if it is, send a stop bit decf RxBits, f goto ReceiveDataBit ReceiveFinished: btfss RX bcf RxError ; stop bit is high bcf RxInProgress bsf RxDone bcf INTCON, T0IE ; disable interrupt goto EndOfInterrupt ReceiveDataBit: bcf STATUS, C btfsc RX bsf STATUS, C rrf RxData, f goto EndOfInterrupt RxStartBit: bsf STATUS, RP0 bcf OPTION_REG, T0CS bsf INTCON, T0IE bcf STATUS, RP0 bsf RxInProgress movlw -BitPeriod movwf TMR0 goto EndOfInterrupt GetByte: movlw DataBits movwf RxBits bcf RxDone bsf STATUS, RP0 bsf OPTION_REG, T0CS bsf OPTION_REG, T0SE bsf INTCON, T0IE bsf INTCON, GIE bcf STATUS, RP0 movlw h'FF' movwf TMR0 btfss RxDone goto $-1 movf RxData, w return Main: bsf STATUS, RP0 movlw b'00010000' movwf TRISA bcf STATUS, RP0 clrf index clrf PortStatus bsf TX loop: movf index, w call GetByte call SendByte ; call Delay btfsc TxInProgress goto $-1 incf index, f goto loop Delay: clrf delay1 Delay1: decfsz delay1, f goto Delay1 return end