;********************************************************************** ;********************************************************************** ; ; Copyright Tech Systems, 2001 ; ; Set your editor for 3 space tabs for the best viewing of this file. ; ;********************************************************************** ;********************************************************************** ; ; THIS SOFTWARE IS PROVIDED "AS IS". THERE ARE NO WARRANTIES THAT APPLY ; TO THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, ; BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ; FOR A PARTICULAR PURPOSE . THE COMPANY, OR THE SOFTWARE'S AUTHOR, ; SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, CONSEQUENTIAL ; OR INCIDENTAL DAMAGES, FOR ANY REASON. ; ;********************************************************************** ;********************************************************************** ; ; This program uses the template 658temp.asm to poll the serial port ; in the 2 millisecond routine. The USART is set up for 9600 Baud, ; 8 data bits, one stop bit, no parity, and no hardware handshaking. ; The ASCII character that is received is incremented and sent back ; through the serial port. Thus, 'f' received will reply 'g' back. ; ; Certain bits of port G are toggled in this program to examine timing ; with an oscilloscope. ; These are: ; ; - G0 is toggled during the timer 0 interrupt to examine the interrupt ; timing caused by timer 0 overflow. A flag is set in this interrupt ; by which the 2 millisecond routine is engaged in the main loop by ; polling. ; ; - G1 is toggled during the 2 millisecond routine. This can be com- ; pared to the timer 0 interrupt (G0) to examine any polling lat- ; encies caused by tasks being performed in other routines in the ; main loop, or caused by other interrupt latencies. ; ; - G2 is toggled during the 100 millisecond routine to examine its ; timing. ; ; - G3 is toggled during the 1 second routine to examine its timing. ; G3 is wired to the green LED on the High End PIC Proto board, so ; you should be able to see it toggled at a 1 Hz rate when running ; this program. ; ; File: Serial.asm ; ; Company: Tech Systems ; Author: Tim Hawkins ; Date: 08/26/01 ; Revision: ; ; E-mail: tim@techsystemsembedded.com ; Web: www.techsystemsembedded.com ; ;********************************************************************** ;********************************************************************** list P=PIC18C658, F=INHX32; list directive to define processor #include ; processor specific variable definitions ;********************************************************************** ;******* CONFIGURATION BITS ********************************* ;********************************************************************** ; ; The lines of code below assign address values to all the ; configuration registers _CONFIG0 EQU H'300000' _CONFIG1 EQU H'300001' _CONFIG2 EQU H'300002' _CONFIG3 EQU H'300003' _CONFIG4 EQU H'300004' _CONFIG5 EQU H'300005' _CONFIG6 EQU H'300006' _CONFIG7 EQU H'300007' _DEVID1 EQU H'3FFFFE' _DEVID2 EQU H'3FFFFF' _IDLOC0 EQU H'200000' _IDLOC1 EQU H'200001' _IDLOC2 EQU H'200002' _IDLOC3 EQU H'200003' _IDLOC4 EQU H'200004' _IDLOC5 EQU H'200005' _IDLOC6 EQU H'200006' _IDLOC7 EQU H'200007' ; Set the configuration registers with the following lines of code. ; Consult P18C658.inc, towards the end of the file, for descriptions ; of the various configuration values. By doing this you will not ; have to manually set the configuration bits when using a programmer ; such as PICSTART PLUS. __CONFIG _CONFIG0, _CP_OFF_0 __CONFIG _CONFIG1, _OSCS_OFF_1 & _EC_OSC_1 __CONFIG _CONFIG2, _BOR_ON_2 & _BORV_25_2 & _PWRT_OFF_2 __CONFIG _CONFIG3, _WDT_OFF_3 __CONFIG _CONFIG5, 0xFE __CONFIG _CONFIG6, _STVR_ON_6 ;********************************************************************** ;******* RAM VARIABLES ****************************************** ;********************************************************************** cblock 0x000060 ; Bank 0, just above Access Bank Low TEM_STATUS TEM_WREG TEM_BSR INTERRUPT_COUNT HUN_MILLI_COUNT ONE_SEC_COUNT DATA_LOW BYTE_FLAGS1 endc TWO_MILLI_FLAG EQU 0x01 ;********************************************************************** ;******* VECTORS ********************************************* ;********************************************************************** ORG 0x000000 goto Start ;******* HIGH PRIORITY INTERRUPT ******* ORG 0x000008 ; Timer 0 is the only high priority interrupt set here, so we assume ; it is the only one causing the high priority interrupt. Otherwise ; if we set other high interrupt sources to high priority, we would ; have to poll to find the correct interrupt source. ; TMR0 = 0xFFFF - (Fos/4)/IntRateDesired, ; for timer in 16-bit mode, IntRateDesired must be ; greater than or equal to 125 Hz movlw 0xC0 ; Load timer 0 with 0xC000 movwf TMR0H clrf TMR0L btg PORTG, 0x00 ; Toggle port G, bit 0 to ; check interrupt timing bsf BYTE_FLAGS1, TWO_MILLI_FLAG ; Set 2 ms routine flag decf INTERRUPT_COUNT ; Decrement count bcf INTCON, TMR0IF ; Clear TMR0 interrupt flag retfie 0x01 ; Return from interrupt ; WREG, BSR, & STATUS will ; be saved on fast stack ; and restored ;******* LOW PRIORITY INTERRUPT ******* ORG 0x000018 movwf TEM_WREG ; save W movff STATUS, TEM_STATUS movff BSR, TEM_BSR ; Low priority interrupts go here movff TEM_BSR, BSR movf TEM_WREG, W movff STATUS, TEM_STATUS retfie 0x00 ; Return from interrupt ;*********************************************************************** ;******* TABLES ************************************************** ;*********************************************************************** ; No tables used in this program ;*********************************************************************** ;******* MAIN PROGRAM ******************************************** ;*********************************************************************** Start rcall Init ; Initializations clrf ONE_SEC_COUNT ; clear 1 sec count movlw 0x32 ; reset count for creating 100 ms routine movwf INTERRUPT_COUNT movlw 0x0A ; reset count for creating 1 sec routines movwf HUN_MILLI_COUNT movlw 0xC0 ; Load timer 0 with 0xC000 movwf TMR0H clrf TMR0L bsf T0CON, TMR0ON ; Turn on timer 0 bsf PORTG, 0x03 ; Turn on LED MainLoop ; Main loop btfss BYTE_FLAGS1, TWO_MILLI_FLAG ; See if ready for 2 ms ; routine goto Continue0 ; if not continue rcall TWO_MILLI_ROUTINE ; if so go to 2 ms routine Continue0 movf INTERRUPT_COUNT,1,1 ; Copy int_count to itself btfss STATUS, Z ; see if it is zero goto Continue1 ; if not continue movlw 0x32 ; if so load it with 50 movwf INTERRUPT_COUNT decfsz HUN_MILLI_COUNT,1,1 ; decrement 100 ms count goto Resume ; do not reset 100 ms count movlw 0x0A ; reset 100 ms count if it movwf HUN_MILLI_COUNT ; is 0 rcall ONE_SEC_ROUTINE ; go to 1 sec routine Resume rcall HUN_MILLI_ROUTINE ; and go to 100 ms routine Continue1 goto MainLoop ;*********************************************************************** ;******* SUBROUTINES ********************************************* ;*********************************************************************** ;******* INITIALIZATIONS ******* Init clrf PORTG ; Clear port G data latch movlw 0x00 ; Value for data direction movwf TRISG ; Set port G as all outputs bsf RCON, IPEN ; Enable interrupt priority ; Timer 1 not used in this program bcf IPR1, TMR1IP ; Set Timer 1 to low priority interrupt bcf PIR1, TMR1IF ; Clear timer 1 overflow flag movlw 0x84 ; 7-1 RD16, Enable TMR1 R/W in one 16 bit operation ; 6-0 Unimplemented ; 5-0 T1CKPS1 ; 4-0 T1CKPS1, No Prescale ; 3-0 T1OSCEN, Disable TMR1 oscillator ; 2-1 /T1SYNC, Do not sync external clock input ; 1-0 TMR1CS, TMR1 uses internal clock, Fosc/4 movwf T1CON ; 0-0 TMR1ON, Turn off timer 1 ; Timer 0 used to create 2 ms interrupt bsf INTCON2, TMR0IP; Set Timer0 to high priority interrupt movlw 0x08 ; 7-0 TMR0ON, Turn off timer 0 ; 6-0 T08BIT, TMR0 configured as a 16 bit timer ; 5-0 T0CS, TMR0 uses internal clock, Fosc/4 ; 4-0 T0SE, external clock edge select ; 3-1 PSA, prescaler assignment; not assigned ; 2-0 T0PS2, prescaler selects ; 1-0 T0PS1 movwf T0CON ; 0-0 T0PS0 movlw 0xA0 ; 7-1 GIE/GIEH, Enable high priority interrupts ; 6-0 PEIE/GIEL, Disable low priority interrupts ; 5-1 TMR0IE, Enable TMR0 overflow interrupt ; 4-0 INT0IE, Disable INT0 external interrupt ; 3-0 RBIE, Disable RB port change interrupt ; 2-0 TMR0IF, Clear TMR0 overflow flag ; 1-0 INT0IF, Clear INT0 external interrupt flag movwf INTCON ; 0-0 RBIF, Clear RB7:RB4 change-state flag movlw 0x01 ; 7-0 Disable parallel slave port R/W interrupt ; 6-0 Disable A/D interrupt ; 5-0 Disable USART receive interrupt ; 4-0 Disable USART transmit interrupt ; 3-0 Disable Sync serial port interrupt ; 2-0 Disable CCP1 interrupt ; 1-0 Disable TMR2 to PR2 match interrupt movwf PIE1 ; 0-1 Enable TMR1 overflow interrupt movlw 0x00 ; 7-0 Unimplemented ; 6-0 Disable Comparator interrupt ; 5-0 Unimplemented ; 4-0 Unimplemented ; 3-0 Disable Bus collision interrupt ; 2-0 Disable Low voltage detect interrupt ; 1-0 Disable TMR3 overflow interrupt movwf PIE2 ; 0-0 Disable CCP2 interrupt movlw 0x00 ; 7-0 Disable invalid CAN message interrupt ; 6-0 Disable Bus activity wake-up interrupt ; 5-0 Disable CAN bus error interrupt ; 4-0 Disable Transmit buffer 2 interrupt ; 3-0 Disable Transmit buffer 1 interrupt ; 2-0 Disable Transmit buffer 0 interrupt ; 1-0 Disable Receive buffer 1 interrupt movwf PIE3 ; 0-0 Disable Receive buffer 0 interrupt ; Configure Serial Port ; SPBRG = ((FOSC/baud)/64 - 1) if BRGH = 0 ; SPBRG = ((FOSC/baud)/16 - 1) if BRGH = 1 bsf TXSTA, BRGH ; Use second equation above movlw 0xD4 ; to get 9600 Baud @ 32.768 MHz movwf SPBRG bsf TXSTA, TXEN ; Enable transmission bsf RCSTA, SPEN ; Enable Serial port bsf RCSTA, CREN ; Enable continuous reception bcf PIR1, RCIF ; Clear Interrupt flag bcf PIE1, RCIE ; Disable USART interrupt return ;******* 2 MILLISECOND ROUTINE, 500 Hz ******* TWO_MILLI_ROUTINE btg PORTG, 0x01 ; Toggle G1 bit to compare 2 ms interrupt ; timing to 2 ms routine timing btfss PIR1, RCIF ; See if serial byte came in goto FINISH_TWO_MILLI ; if not, finish up movf RCREG, W ; if so, get data, movwf DATA_LOW incf DATA_LOW, 0 ; increment data and store in W, rcall SEND_CHAR ; send data back movlw 0x0A rcall SEND_CHAR ; send LF movlw 0x0D rcall SEND_CHAR ; send CR FINISH_TWO_MILLI bcf BYTE_FLAGS1, TWO_MILLI_FLAG ; Clear 2 ms routine flag return ;******* 100 MILLISECOND ROUTINE, 10 Hz ******* HUN_MILLI_ROUTINE btg PORTG, 0x02 ; Toggle G2 bit to check 100 ms timing FINISH_HUN_MILLI return ;******* 1 SECOND ROUTINE, 1 Hz ******* ONE_SEC_ROUTINE btg PORTG, 0x03 ; Toggle G3 (LED) bit to check 1 sec timing incf ONE_SEC_COUNT ; Increment 1 sec count return SEND_CHAR btfss TXSTA, TRMT ; check if trans buffer is clear goto SEND_CHAR ; if not, try again movwf TXREG ; send data return ;*********************************************************************** ;*********************************************************************** END ; required directive ;*********************************************************************** ;***********************************************************************