;********************************************************************** ;********************************************************************** ; ; Copyright Tech Systems, 2002 ; ; 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 877temp.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 B are toggled in this program to examine timing ; with an oscilloscope. ; These are: ; ; - B2 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. ; ; - B4 is toggled during the 2 millisecond routine. This can be com- ; pared to the timer 1 interrupt (B2) to examine any polling lat- ; encies caused by tasks being performed in other routines in the ; main loop, or caused by other interrupt latencies. ; ; - B3 is toggled during the 100 millisecond routine to examine its ; timing. ; ; - B1 is toggled during the 1 second routine to examine its timing. ; B1 is wired to the green LED on the Flash PIC Proto board, so ; you should be able to see it toggled at a 1 Hz rate when running ; this program. ; ; File: 877Serial1.asm ; ; Company: Tech Systems ; Author: Tim Hawkins ; Date: 02/19/02 ; Revision: ; ; E-mail: tim@techsystemsembedded.com ; Web: www.techsystemsembedded.com ; ;********************************************************************** ;********************************************************************** list P=PIC16F877, F=INHX32; list directive to define processor #include ; processor specific variable definitions ;********************************************************************** ;******* CONFIGURATION BITS ********************************* ;********************************************************************** ; ; Set the configuration registers with the following lines of code. ; Consult P16F877.inc, towards the end of the file, for options ; 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 _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_ON & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC ; ;********************************************************************** ;******* RAM VARIABLES ****************************************** ;********************************************************************** cblock 0x000020 ; Bank 0, 96 bytes TEM_STATUS TEM_WREG TEM_PCLATH INTERRUPT_COUNT HUN_MILLI_COUNT ONE_SEC_COUNT BYTE_FLAGS1 DATA_LOW endc TWO_MILLI_FLAG EQU 0x01 ;********************************************************************** ;******* VECTORS ********************************************* ;********************************************************************** ORG 0x000000 goto Start ;******* INTERRUPT ******* ORG 0x000004 movwf TEM_WREG ; save W movf STATUS, W ; save STATUS movwf TEM_STATUS movf PCLATH, W ; save PCLATH movwf TEM_PCLATH IntPoll ; Poll to find the interrupt source btfsc PIR1, TMR1IF ; Check for Timer 1 interrupt goto Timer1Int movf TEM_PCLATH, W movwf PCLATH movf STATUS, W movwf STATUS movf TEM_WREG, W Finish_Int retfie ; Return from interrupt ;******* INTERRUPT HANDLERS ******* Timer1Int ; TMR1 = 0xFFFF - (Fos/4)/IntRateDesired, bcf T1CON, TMR1ON ; Turn off timer 1 ; movlw 0xFE ; Load timer 1 with 0xFEF0 movlw 0xD8 ; Load timer 1 with 0xD8F0 movwf TMR1H movlw 0xF0 movwf TMR1L bsf T1CON, TMR1ON ; Turn on timer 1 btfsc PORTB, 0x02 ; Toggle port B, bit 2 to goto ClearB2 ; check interrupt timing bsf PORTB, 0x02 goto FinishB2Tog ClearB2 bcf PORTB, 0x02 FinishB2Tog bsf BYTE_FLAGS1, TWO_MILLI_FLAG ; Set 2 ms routine flag decf INTERRUPT_COUNT, 1 ; Decrement count bcf PIR1, TMR1IF ; Clear TMR1 interrupt flag goto IntPoll ; Before leaving, check other sources ; goto Finish_Int ; Finish up interrupt ;*********************************************************************** ;******* TABLES ************************************************** ;*********************************************************************** ; No tables used in this program ;*********************************************************************** ;******* MAIN PROGRAM ******************************************** ;*********************************************************************** Start call 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 0xFF ; Load timer 1 with 0xFFF0 movlw 0xD8 ; Load timer 1 with 0xD8F0 movwf TMR1H movlw 0xF0 movwf TMR1L bsf T1CON, TMR1ON ; Turn on timer 1 bcf PORTB, 0x01 ; Turn on LED MainLoop ; Main loop btfss BYTE_FLAGS1, TWO_MILLI_FLAG ; See if ready for 2 ms ; routine goto Continue0 ; if not continue call TWO_MILLI_ROUTINE ; if so go to 2 ms routine Continue0 movf INTERRUPT_COUNT,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 ; 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 call ONE_SEC_ROUTINE ; go to 1 sec routine Resume call HUN_MILLI_ROUTINE ; and go to 100 ms routine Continue1 goto MainLoop ;*********************************************************************** ;******* SUBROUTINES ********************************************* ;*********************************************************************** ;******* INITIALIZATIONS ******* Init clrf PORTB ; Clear port B data latch bcf STATUS, RP1 ; Select bank 1 bsf STATUS, RP0 movlw 0x00 ; Value for data direction movwf TRISB ; Set port B as all outputs bcf STATUS, RP1 ; Select bank 0 bcf STATUS, RP0 movlw 0xC0 ; 7-1 GIE, Enable interrupts ; 6-1 PEIE, Enable Peripheral interrupts ; 5-0 T0IE, Disable TMR0 overflow interrupt ; 4-0 INTE, Disable RB0/INT external interrupt ; 3-0 RBIE, Disable RB port change interrupt ; 2-0 T0IF, Clear TMR0 overflow flag ; 1-0 INT0IF, Clear RB0/INT interrupt flag movwf INTCON ; 0-0 RBIF, Clear RB7:RB4 change-state flag bcf STATUS, RP1 ; Select bank 1 bsf STATUS, RP0 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 Reserved, should always be clear ; 5-0 Unimplemented ; 4-0 EEIE, EEPROM Write int disabled ; 3-0 Disable Bus collision interrupt ; 2-0 Unimplemented ; 1-0 Unimplemented movwf PIE2 ; 0-0 Disable CCP2 interrupt ; Timer 1 used in this program for 2ms intterrupt bcf STATUS, RP1 ; Select bank 0 bcf STATUS, RP0 bcf PIR1, TMR1IF ; Clear timer 1 overflow flag bcf PIR1, RCIF ; Clear Interrupt flag bcf PIR1, TXIF ; Clear Interrupt flag ; Configure Serial Port ; SPBRG = ((FOSC/baud)/64 - 1) if BRGH = 0 ; SPBRG = ((FOSC/baud)/16 - 1) if BRGH = 1 bcf STATUS, RP1 ; Select bank 1 bsf STATUS, RP0 bsf TXSTA, BRGH ; Use second equation above movlw 0x81 ; to get 9600 Baud @ 20.0 MHz movwf SPBRG bcf TXSTA, TX9 ; Use 8-bit transmission bsf TXSTA, TXEN ; Enable transmission bcf TXSTA, SYNC ; Use Asynchronous mode bcf STATUS, RP1 ; Select bank 0 bcf STATUS, RP0 bsf RCSTA, SPEN ; Enable Serial port bcf RCSTA, TX9 ; Use 8-bit reception bsf RCSTA, CREN ; Enable continuous reception return ;******* 2 MILLISECOND ROUTINE, 500 Hz ******* TWO_MILLI_ROUTINE btfsc PORTB, 0x04 ; Toggle G1 bit to compare 2 ms interrupt goto ClearB4 ; timing to 2 ms routine timing bsf PORTB, 0x04 goto FinishB4Tog ClearB4 bcf PORTB, 0x04 FinishB4Tog bcf BYTE_FLAGS1, TWO_MILLI_FLAG ; Clear 2 ms routine flag btfss PIR1, RCIF ; See if serial byte came in goto FINISH_HUN_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, call SEND_CHAR ; send data back return ;******* 100 MILLISECOND ROUTINE, 10 Hz ******* HUN_MILLI_ROUTINE btfsc PORTB, 0x03 ; Toggle B3 bit to check 100 ms timing goto ClearB3 bsf PORTB, 0x03 goto FinishB3Tog ClearB3 bcf PORTB, 0x03 FinishB3Tog FINISH_HUN_MILLI return ;******* 1 SECOND ROUTINE, 1 Hz ******* ONE_SEC_ROUTINE btfsc PORTB, 0x01 ; Toggle port B, bit 1 (LED) to goto ClearB1 ; check 1 sec timing bsf PORTB, 0x01 goto FinishB1Tog ClearB1 bcf PORTB, 0x01 FinishB1Tog incf ONE_SEC_COUNT, 1 ; Increment 1 sec count return ;******* Serial Transmission ******* SEND_CHAR bcf STATUS, RP1 ; Select bank 0 bcf STATUS, RP0 movwf TXREG ; send data return ;*********************************************************************** ;*********************************************************************** END ; required directive ;*********************************************************************** ;***********************************************************************