; IntSer - Macros for Setting up an Interrupt Based NRZ Serial Interface ; for the PICMicro. ; ; NRZSerialInit Speed, Rate, Polarity, TXPort, TXPin, RXPort, RXPin, TXBufferSend, RXBufferSave, OtherInt ; - Contains Interrupt Handler as well as Timer and Interrupt Controller Set up ; Where: ; Speed - Processor Execution Speed ; Rate - Data Rate ; Polarity - "1" for Positive, "-1" for Negative ; TXPort, TXPin - Port, Pin for Data Transmit ; RXPort, RXPin - Port, Pin for Data Receive ; TXBufferSend - Non-Zero Address Called when character has been sent (to pick up next) ; RXBufferSave - Non-Zero Address Called when a character has been received (to save in a Buffer) ; OtherInt - If an Interrupt Other than the Timer Interrupt is requested, then this Non-Zero ; Address Jumped to ; ; NRZSerialRoutines ; - Contains the subroutines used to send and receive Serial Data ; NRZSend - Send the Value in "w" out ; NRZReceive - Wait for a character to come in. No Timeout, instead ; Polling of "RXCount" = 2 should be used. ; ; This Macro will ONLY work on Mid-Range Devices ; ; Dependencies: ; Vars.inc - Myke Predko's Variable Declaration Macro ; ; 99.07.29 - Updated to Eliminate two cycles in the TX Operation ; ; 99.07.24 - Updated to Include "OtherInt" after RX/TX operations ; ; Myke Predko ; 99.06.25 ; NRZSerialInit macro Speed, Rate, Polarity, TXPort, TXPin, RXPort, RXPin, TXBufferSend, RXBufferSave, OtherInt #define NRZSerialInitializied VarAdd _w, 1 VarAdd _status, 1 VarAdd RTC, 2 VarAdd TXCount, 1 VarAdd TXByte, 1 VarAdd RXCount, 1 VarAdd RXByte, 1 if (Polarity < 0) #define DataPolarity endif if ($ != 0) error "'TMR0SerialInt' Macro MUST Start at Address 0) endif variable TMRDlay, TMRReset, PreScaler, PreScalerDlay, Temp, TMRActual, RTCActual, TMRError TMRDlay = Speed / (Rate * 3 * 4) TMRDlay = TMRDlay - 9 Temp = TMRDlay / 512 PreScalerDlay = 0 PreScaler = 2 while (Temp != 0) Temp = Temp / 2 PreScalerDlay = PreScalerDlay + 1 PreScaler = PreScaler * 2 endw TMRReset = TMRDlay / PreScaler TMRActual = TMRReset * PreScaler if (TMRActual > TMRDlay) TMRError = ((TMRActual - TMRDlay) * 100) / TMRDlay else TMRError = ((TMRDlay - TMRActual) * 100) / TMRDlay endif if (TMRError > 2) error "Timer Actual Poll to Expected is different by more than 2%" endif RTCActual = TMRActual + 9 RTCActual = ((RTCActual * 100000) / (Speed / 4)) * 10 ; #### - This is the Number of usecs Between RTC Increments goto _AfterInt ; 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 incf RTC, f ; Increment the Real Time Clock btfsc STATUS, Z incf RTC + 1, f 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 if (Polarity < 0) ; Load Carry with the Bit bcf STATUS, C else bsf STATUS, C endif rrf TXByte, f movf TXPort, w ; Send Next Bit andlw 0x0FF ^ (1 << TXPin) btfsc STATUS, C iorlw 1 << TXPin movwf TXPort ; Cycle 12 is the Bit Send goto _TXCompletedGoOn ; TX Takes 14 Cycles _TXSendDlayCheck ; Don't Send Bit, Check for Start Bit btfss TXCount, 0 ; Bit Zero Set (Byte to Send)? goto _TXNothingtoCheck movlw 0x004 ; Setup the Timer to Increment 3x movwf TXCount movf TXPort, w ; Output Start Bit if (Polarity < 0) iorlw 1 << TXPin else andlw 0x0FF ^ (1 << TXPin) endif movwf TXPort goto _TXCompletedGotOn ; TX First Bit Takes 14 Cycles _TXNothingtoCheck ; Nothing Being Sent? movf TXCount, w xorlw 0x004 ; Zero (Originally) TXCount? btfss STATUS, Z xorlw 0x004 ^ 0x09C btfsc STATUS, Z clrf TXCount _TXCompletedGoOn ; Finished with TX, Do RX ; #### - 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 ; Everything Read Through? xorlw 0x091 btfsc STATUS, Z goto _RXAtEnd ; Yes, Check for Stop Bit bcf STATUS, C ; Read the Current State if (Polarity < 0) btfss RXPort, RXPin else btfsc RXPort, RXPin endif bsf STATUS, C rrf RXByte, f bsf RXCount, 2 ; Start Counting from 4 goto _RXEnd ; Finished REceiving Byte _RXAtEnd ; Check Last Bit if (Polarity < 0) btfsc RXPort, RXPin ; Check for Valid else btfss RXPort, RXPin endif goto _RXOverrun ; Not Valid - Error movlw 2 ; Valid - Save Value movwf RXCount if (RXBufferSave != 0) ; Save the Character? call RXBufferSave endif goto _RXEnd _RXNo ; No Bit to Receive btfsc RXCount, 0 ; Something Running? goto _RXEnd ; - Yes, Skip Over btfss RXCount, 3 ; Checking Start Bits? goto _RXStart if (Polarity < 0) btfss RXPort, RXPin else btfsc RXPort, RXPin endif bcf RXCount, 3 ; Nothing - Keep Waiting bsf RXCount, 0 ; Mark it has Started btfss RXCount, 1 ; Something Already Saved? goto _RXEnd _RXOverrun ; Error - Mark the Overrun movlw 0x003 movwf RXCount goto _RXEnd _RXStart ; Check for Low if (Polarity < 0) btfss RXPort, RXPin else btfsc RXPort, RXPin endif bcf RXCount, 2 ; Don't Have a "Start" Bit goto _RXEnd ; #### - Finished with the Receive Interrupt Code _RXEnd if (TXBufferSend != 0) ; Sending String Information? movf TXCount, f btfsc STATUS, Z ; If TXCount == 0 then Look for New Byte to Send call TXBufferSend endif if (OtherInt != 0) ; Call Any other Operations call OtherInt endif movf _status, w ; Restore the Context Registers movwf STATUS swapf _w, f swapf _w, w retfie _AfterInt 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 clrf TXCount ; Make Sure Nothing is Happening clrf RXCount ; On Boot movlw 256 - TMRReset ; Start the Timer Going movwf TMR0 bsf INTCON, T0IE ; Initialize the Interrupt Handler bsf INTCON, GIE endm NRZSerialRoutines macro ifndef NRZSerialInitializied error "Serial I/O Port Declarations Not Made" endif 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 ifdef DataPolarity ; Invert Data if Required comf TXByte endif 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 endm