;*************************************************************************** ; ; RS232 Communication Test for PIC 16XXX V1.03 ; ============================================ ; ; written by Peter Luethi, 26.03.1999, Dietikon, Switzerland ; http://www.electronic-engineering.ch ; last update: 31.12.2004 ; ; V1.03: Added transmission of status message ('@') every 2.75 s ; when PIC terminal is idle. Used therefore 24 bit counter. ; (31.12.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.03.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 ; RS232 Baud Rate: 9600 baud, 8 bit, no parity, 1 stopbit ; Required Hardware: MAX 232, dot matrix LCD display ; Code Size of entire Program: approx. 566 instruction words ; Acquisition Methodology: Interrupt-based RS232 data acquisition, ; with LCD display output and RS232 echo ; during normal operation ; ; ; DESCRIPTION: ; ============ ; Developed and tested on PIC 16F84, executeable on all interrupt ; featured PICs. ; This program handles all aspects of ; Transmission (register TXD) and ; Reception (register RXD) through interrupts (PortB0 IRQ). ; 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 RS232 characters back ; to the terminal window. When the PIC terminal is idle, it sends a ; status message '@' to the PC every 2.75 seconds. ; ; Shows the implementation and function of the modules m_wait.asm, ; m_lcd.asm, m_lcdv08.asm, and m_rs096.asm on the PIC16F84. ; ; ; IMPLEMENTED FEATURES: ; ===================== ; - Bi-directional communication between microcontroller application ; and remote RS232 client by software-based RS232 transmission. ; - Display of received character on dot matrix LCD. ; ;*************************************************************************** ;***** 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,0x03 ; 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) LOcnt equ BASE+d'14' ; low byte of 24 bit counter MEDcnt equ BASE+d'15' ; medium byte of 24 bit counter HIcnt equ BASE+d'16' ; high byte of 24 bit counter ;***** INCLUDE FILES ***** #include "..\..\m_bank.asm" #include "..\..\m_wait.asm" #include "..\..\m_lcd.asm" ; standard version (fixed delay) ;#include "..\..\m_lcd_bf.asm" ; fast, bi-directional version #include "..\..\m_lcdv08.asm" #include "..\..\m_rs096.asm" ; standard RS232 baud rate ;***** MACROS ***** ;***** SUB-ROUTINES ***** COUNTERinit ; *** Initialize 24 bit counter for status message wait interval *** clrf LOcnt ; init counter clrf MEDcnt ; init counter movlw d'6' movwf HIcnt ; init counter RETURN RSservice ; *** RS232 echo & LCD display routine for received RS232 characters *** 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 call COUNTERinit ; initialize 24 bit counter ;****************************** _MLOOP btfsc RSflag ; check RS232 data reception flag call COUNTERinit ; reset 24 bit counter btfsc RSflag ; check RS232 data reception flag call RSservice ; if set, call RS232 echo & LCD display routine ; status message wait counter decfsz LOcnt,f ; decrement low byte of 24 bit counter goto _MLOOP ; loop decfsz MEDcnt,f ; decrement medium byte of 24 bit counter goto _MLOOP ; loop decfsz HIcnt,f ; decrement high byte of 24 bit counter goto _MLOOP ; loop ; now, all bytes of 24 bit counter are zero, transmit status message... ; send status message every 2.75 s SEND '@' SEND CR SEND LF call COUNTERinit ; initialize 24 bit counter goto _MLOOP ; loop forever ;****************************** ;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