;***************************************************************************
;
; RS232 Communication Test for PIC 16XXX
; ======================================
;
; written by Peter Luethi, 26.03.1999, Dietikon, Switzerland
; [url]https://www.electronic-engineering.ch[/url]
; last update: 11.04.2004
;
; V1.02: Fixed copy/paste issue of ISR context store/restore
; (nobody is perfect): Erroneously erased INTCON,INTF
; clearing, resulting in endless ISR calling...
; Re-structured entire ISR and RS232 echo sub-routines
; (11.04.2004)
; V1.01: ISR context restore improvements (30.12.2000)
; V1.00: Initial release (26.3.1999)
;
; This code and accompanying files may be distributed freely and
; modified, provided this header with my name and this notice remain
; intact. Ownership rights remain with me.
; You may not sell this software without my approval.
;
; This software comes with no guarantee or warranty except for my
; good intentions. By using this code you agree to indemnify me from
; any liability that might arise from its use.
;
;
; SPECIFICATIONS:
; ===============
; Processor: Microchip PIC 16F84
; Clock Frequency: 4.00 MHz XT
; Throughput: 1 MIPS
; Baud Rate: 9600 baud, 8 bit, no parity, 1 stopbit
; Code Size of entire Program: approx. 570 instruction words
; Required Hardware: MAX 232, dot matrix LCD display
;
;
; DESCRIPTION:
; ============
; Developed and tested on PIC 16F84, executeable on all interrupt
; featured PICs.
; Program handles all aspects of
; Transmission (Register TXD) and
; Reception (Register RXD) through interrupt.
; Display of received ASCII characters sent from RS232 host and
; their decimal representation on the dot matrix LCD display.
; The microcontroller sends feedback of received characters back to
; the terminal window.
;
;***************************************************************************
;***** COMPILATION MESSAGES & WARNINGS *****
ERRORLEVEL -207 ; found label after column 1
ERRORLEVEL -302 ; register in operand not in bank 0
;***** PROCESSOR DECLARATION & CONFIGURATION *****
PROCESSOR 16F84
#include "p16f84.inc"
; embed Configuration Data within .asm File
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
;***** MEMORY STRUCTURE *****
ORG 0x00 ; processor reset vector
goto MAIN ; main program
ORG 0x04 ; interrupt vector
goto ISR ; Interrupt Service Routine (ISR)
;***** PARAMETERIZATION *****
CONSTANT LCDWAIT = 0x02 ; LCD wait for initialization
CONSTANT LCDSPEED = 0x01 ; configure according to PIC clock
;***** PORT DECLARATION *****
#define TXport PORTA,0x00 ; RS232 output port, could be
#define TXtris TRISA,0x00 ; any active push/pull port
LCDtris equ TRISB
LCDport equ PORTB
;***** CONSTANT DECLARATION *****
CONSTANT BASE = 0x0C ; base address of user file registers
;***** REGISTER DECLARATION *****
TEMP1 set BASE+d'0' ; Universal temporary register
TEMP2 set BASE+d'1' ; ATTENTION !!!
TEMP3 set BASE+d'2' ; They are used by various modules.
TEMP4 set BASE+d'3' ; If you use them, make sure not to use
TEMP5 set BASE+d'4' ; them concurrently! No use in ISR!
LO equ BASE+d'5'
LO_TEMP equ BASE+d'6'
FLAGreg equ BASE+d'7'
#define RSflag FLAGreg,0x00 ; RS232 data reception flag
#define LCDbusy FLAGreg,0x01 ; LCD busy flag
#define LCDcflag FLAGreg,0x02 ; LCD command/data flag
#define BCflag FLAGreg,0x04 ; blank checker for preceeding zeros
TXD equ BASE+d'8' ; TX-Data register
RXD equ BASE+d'9' ; RX-Data register
W_TEMP equ BASE+d'10' ; context register (ISR)
STATUS_TEMP equ BASE+d'11' ; context register (ISR)
PCLATH_TEMP equ BASE+d'12' ; context register (ISR)
FSR_TEMP equ BASE+d'13' ; context register (ISR)
;***** INCLUDE FILES *****
#include "..\..\m_bank.asm"
#include "..\..\m_wait.asm"
#include "..\..\m_lcd_bf.asm"
#include "..\..\m_lcdv08.asm"
#include "..\..\m_rs096.asm" ; standard RS232 baud rate
;***** MACROS *****
;***** SUB-ROUTINES *****
RSservice
LCD_DDAdr 0x45
movfw RXD ; get received RS232 data
LCDw ; send to LCD display
LCD_DDAdr 0x4D
movfw RXD
movwf LO
LCDval_08 ; display decimal value
SEND TAB
SEND 'r'
SEND 'e'
SEND 'c'
SEND 'e'
SEND 'i'
SEND 'v'
SEND 'e'
SEND 'd'
SEND ' '
movfw RXD ; get received RS232 data
SENDw ; transmit across RS232
SEND ' '
SEND 'o'
SEND 'n'
SEND ' '
SEND 'M'
SEND 'i'
SEND 'c'
SEND 'r'
SEND 'o'
SEND 'c'
SEND 'h'
SEND 'i'
SEND 'p'
SEND ' '
SEND 'P'
SEND 'I'
SEND 'C'
SEND '1'
SEND '6'
SEND 'F'
SEND '8'
SEND '4'
SEND CR ; Carriage Return
SEND LF ; Line Feed
; end of RS232 service (echo & display)
bcf RSflag ; reset RS232 data reception flag
bsf INTCON,INTE ; re-enable RB0/INT interrupt
RETURN
;***** INTERRUPT SERVICE ROUTINE *****
ISR ;************************
;*** ISR CONTEXT SAVE ***
;************************
bcf INTCON,GIE ; disable all interrupts
btfsc INTCON,GIE ; assure interrupts are disabled
goto ISR
movwf W_TEMP ; context save: W
swapf STATUS,W ; context save: STATUS
movwf STATUS_TEMP ; context save
clrf STATUS ; bank 0, regardless of current bank
movfw PCLATH ; context save: PCLATH
movwf PCLATH_TEMP ; context save
clrf PCLATH ; page zero, regardless of current page
bcf STATUS,IRP ; return to bank 0
movfw FSR ; context save: FSR
movwf FSR_TEMP ; context save
;*** context save done ***
;**************************
;*** ISR MAIN EXECUTION ***
;**************************
;*** determine origin of interrupt ***
btfsc INTCON,INTF ; check for RB0/INT interrupt
goto _ISR_RS232 ; if set, there was a keypad stroke
; catch-all
goto ISRend ; unexpected IRQ, terminate execution of ISR
;******************************
;*** RS232 DATA ACQUISITION ***
;******************************
_ISR_RS232
; first, disable interrupt source
bcf INTCON,INTE ; disable RB0/INT interrupt
; second, acquire RS232 data
RECEIVE ; macro of RS232 software reception
bsf RSflag ; enable RS232 data reception flag
goto _ISR_RS232end ; terminate RS232 ISR properly
;***********************************
;*** CLEARING OF INTERRUPT FLAGS ***
;***********************************
; NOTE: Below, I only clear the interrupt flags! This does not
; necessarily mean, that the interrupts are already re-enabled.
; Basically, interrupt re-enabling is carried out at the end of
; the corresponding service routine in normal operation mode.
; The flag responsible for the current ISR call has to be cleared
; to prevent recursive ISR calls. Other interrupt flags, activated
; during execution of this ISR, will immediately be served upon
; termination of the current ISR run.
_ISR_RS232error
bsf INTCON,INTE ; after error, re-enable IRQ already here
_ISR_RS232end
bcf INTCON,INTF ; clear RB0/INT interrupt flag
;goto ISRend ; terminate execution of ISR
;*****************************************
;*** ISR TERMINATION (CONTEXT RESTORE) ***
;*****************************************
ISRend movfw FSR_TEMP ; context restore
movwf FSR ; context restore
movfw PCLATH_TEMP ; context restore
movwf PCLATH ; context restore
swapf STATUS_TEMP,W ; context restore
movwf STATUS ; context restore
swapf W_TEMP,F ; context restore
swapf W_TEMP,W ; context restore
RETFIE ; enable global interrupt (INTCON,GIE)
;***** END OF INTERRUPT SERVICE ROUTINE *****
;************** MAIN **************
MAIN LCDinit ; LCD Initialization
RS232init ; RS232 Initialization
clrf FLAGreg ; initialize all flags
;*** START-UP MESSAGE of LCD ***
LCDchar 'R'
LCDchar 'S'
LCDchar '2'
LCDchar '3'
LCDchar '2'
LCDchar ' '
LCDchar 'C'
LCDchar 'o'
LCDchar 'm'
LCDchar 'm'
LCDchar 'u'
LCDchar 'n'
LCDchar 'i'
LCDchar 'c'
LCDchar 'a'
LCDchar '-'
LCDline 2
LCDchar 't'
LCDchar 'i'
LCDchar 'o'
LCDchar 'n'
LCDchar ' '
LCDchar 'o'
LCDchar 'n'
LCDchar ' '
LCDchar 'P'
LCDchar 'I'
LCDchar 'C'
LCDchar '1'
LCDchar '6'
LCDchar 'F'
LCDchar '8'
LCDchar '4'
;*** START-UP MESSAGE to RS232 ***
; this is done by reading a look-up table
; define amount of table items for start-up message
#define tab_size4 d'48'
movlw tab_size4 ; store amount of table items in counter
movwf TEMP5
; transmit message
_ILOOP1 movlw HIGH WelcomeTable ; get correct page for PCLATH
movwf PCLATH ; prepare right page bits for table read
movfw TEMP5 ; get actual count-down value
sublw tab_size4 ; table offset: w = tab_size4 - TEMP6
call WelcomeTable ; call lookup table
SENDw ; RS232 output
decfsz TEMP5,f ; decrement counter
goto _ILOOP1
WAITX 0x1A, b'00000111' ; wait some time
; a little bit animation...
SEND 'a'
SEND 'n'
SEND 'i'
SEND 'm'
SEND 'a'
SEND 't'
SEND 'i'
SEND 'n'
SEND 'g'
SEND ' '
SEND 'L'
SEND 'C'
SEND 'D'
SEND '.'
SEND '.'
SEND '.'
SEND CR ; Carriage Return
SEND LF ; Line Feed
movlw d'16'
movwf TEMP5
_SHL1 LCDcmd LCDSL ; shift left LCD display content
WAIT 0xC0
decfsz TEMP5,f
goto _SHL1
; finally, reset/clear LCD
LCDcmd LCDCLR
LCDchar 'R'
LCDchar 'S'
LCDchar '2'
LCDchar '3'
LCDchar '2'
LCDchar ' '
LCDchar 'R'
LCDchar 'e'
LCDchar 'c'
LCDchar 'e'
LCDchar 'p'
LCDchar 't'
LCDchar 'i'
LCDchar 'o'
LCDchar 'n'
LCDchar ':'
LCDline 2
LCDchar 'C'
LCDchar 'h'
LCDchar 'a'
LCDchar 'r'
LCD_DDAdr 0x47
LCDchar 'V'
LCDchar 'a'
LCDchar 'l'
LCDchar 'u'
LCDchar 'e'
SEND 'r'
SEND 'e'
SEND 'a'
SEND 'd'
SEND 'y'
SEND '.'
SEND '.'
SEND '.'
SEND CR ; Carriage Return
SEND LF ; Line Feed
;******************************
LOOP btfsc RSflag ; check RS232 data reception flag
call RSservice ; if set, call RS232 echo & LCD display routine
goto LOOP
;******************************
;ORG 0x230 ; if necessary, move look-up tables
WelcomeTable
addwf PCL,F ; add offset to table base pointer
retlw CR
retlw LF
DT "Microchip PIC16F84 connected and stand-by..." ; create table
retlw CR
WTableEND retlw LF
IF (HIGH (WelcomeTable) != HIGH (WTableEND))
ERROR "WelcomeTable hits page boundary!"
ENDIF
END