;************************************************************************ ;* matt, this is the file!!!! ;* Teletypesetting GPS, Inc. 2002 * ;* Version: 0.1000 * ;* Filename: * ;* p16demo.asm (main routine) * ;* Dependents: * ;* p16lcd.asm * ;* p16math.asm * ;* 16f877.lkr * ;* **** 07/02/ * ;* Designed to run at 4MHz * ;* **** 08/12/ * ;* Added support for the second gen. hardware. HR input is Port B0, * ;* which will be switched to interrupt as soon as I figure out how. * ;* ;* Simple initial application to run the heart rate demonstration. ;* Also does a good job of turning extraneous hardware off when not ;* in use. Does not implement an interrupt architecture. ;* ;************************************************************************ ; Matt 8/19/03 - ; ; Please note: Started to implement interrupts Below ; Heres my thinking: ; ; Program is just a loop with a no op command for the time being, which just waits for interrupts ; Currently only things that will cause this interrupt are: ; 1) Timer Overflowing - If this is the case, a second has passed, and its time to write to serial ; 2) Heart-rate moniter- If this is the case, time to get the info passed to the heartrate. ; ; ;************************************************************************** list p=16F877 #include p16F877.inc __CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _LVP_OFF & _BODEN_OFF #define hr_dir PORTB,0 #define hr_in PORTB,0 ;Heartrate monitor input on PCB. #define LED_on bsf PORTB,4 ;turn on LED #define LED_off bcf PORTB,4 ;turn off LED EXTERN UMUL0808L, UDIV1608L, AARGB0, AARGB1, BARGB0 ; math variables UDATA 0x30 ptr_pos RES 1 ptr_count RES 1 W_SAVE RES 1 ;; Used to save S_SAVE RES 1 ;; W and STATUS Variables temp_1 RES 1 ;; Unused at this time temp_2 RES 1 temp_3 RES 1 cmd_byte RES 1 temperature RES 1 LSD RES 1 MsD RES 1 MSD RES 1 NumH RES 1 NumL RES 1 TenK RES 1 Thou RES 1 Hund RES 1 Tens RES 1 Ones RES 1 hr_h RES 1 hr_l RES 1 tim_h RES 1 tim_l RES 1 NMEA_csum RES 1 tmp_w RES 1 temp_wr RES 1 ;********************************************************************** ; return from interrupt STARTUP CODE ; NOP goto start ; NOP ; NOP ; NOP ;PROG1 CODE stan_t CODE 0x100 ;start standard table at ROM 0x100 stan_table ;table for standard code addwf PCL,f ; "XXXXXXXXXXXXXXXX" ; ptr: dt " Voltmeter " ;0 dt " " ;16 dt " Temperature " ;32 dt " Clock " ;48 dt "RA4=Next RB0=Now" ;64 dt " Teletype GPS " ;80 dt "Heartrate v. 0.2" ;96 dt " Pulse Lo " ;112 dt "RA4= --> RBO= ++" ;128 dt " RB0 = Exit " ;144 dt "Volts = " ;160 dt "Prd.=128 DC=128 " ;176 dt " Heartrate " ;192 dt " Time = " ;208 dt " Cycles " ;224 start banksel T1CON ;Configure Timer1 for real time clock movlw 0x3F ; start here for timer "warm-up" movwf T1CON movlw B'10100100' ;Master mode, 8-bit, Async, High speed banksel TXSTA ;initialize USART movwf TXSTA banksel SPBRG movlw .25 ;9.6Kbaud @ 4MHz movwf SPBRG banksel RCSTA movlw B'10010000' movwf RCSTA banksel TRISC ;configure CCP1 module for buzzer bcf TRISC,2 banksel T2CON ;bank 0 movlw 0x05 ;postscale 1:1, prescaler 4, Timer2 ON movwf T2CON ;;--------Matt Additions ------- banksel T1CON ;; Begin Timer1 Configuration movlw B'00000101' ;; Configures timer to be On (Bit 0) and To run in Asynchrouncous Mode (Bit 2) movlw T1CON ;; Loads it into T1CON banksel INTCON movlw B'11000000' ;; Enables Global Interrupt and PEIE (Peripheral Interrupt) bsf TMR1IE,1 ;; Enables TMR1 Overflow Interrupt ;;------- End Matt Additions ---- banksel TRISB ; bank 1 clrf TRISB ; make all port b pins output banksel TRISB bsf TRISB,0 ; make port b pin 0 an Input (HR Monitor) banksel PORTB ; bank 0 ;bsf PORTB,2 ; RS-232 /SHDN to HI (don't shut down) bsf PORTB,3 ; RS-232 EN to HI (do enable) ; initialize LED to on. bcf PORTB,5 LED_on; ;**************** STANDARD CODE MENU SELECTION ******************* ;Introduction banksel ptr_pos movlw .80 ;send "Microchip" to LCD movwf ptr_pos call stan_char_1 movlw .96 ;send "PICDEM 2 PLUS" to LCD movwf ptr_pos call stan_char_2 menu ;;-------------- Begin Main Program Routine ----------------- mloop NOP call INT_SERV NOP goto mloop ;;--------------- End Main Program Routine ------------------- ;************* STANDARD USER CODE ********************************** ;------------- Heartrate Monitor ----------------------------------- ; Wait for the heartrate ; insert heartrate code here. banksel T1CON movlw 0x3F ;intitialize TIMER1: 8:1, ext. clk. movwf T1CON banksel ptr_pos movlw .112 ; pulse lo movwf ptr_pos call stan_char_1 banksel PORTB btfss hr_in ;wait for RB1 to go hi goto $-1 banksel ptr_pos movlw .224 ;cycles movwf ptr_pos call stan_char_1 banksel ptr_pos movlw .16 ; blank line movwf ptr_pos call stan_char_2 call timer_read ; read current value of timer 1 into tim_h, tim_l banksel tim_l movf tim_l,W ; store result into hr_l, hr_w banksel hr_l movwf hr_l banksel tim_h movf tim_h,W banksel hr_h movwf hr_h hr_next_value LED_off banksel PORTB btfsc hr_in ;wait for RB1 to go lo goto $-1 ;sleep ; bamber: test sleep mode. btfss hr_in ;wait for RB1 to go hi goto $-1 LED_on call timer_read ; read current value of timer 1 into tim_h, tim_l banksel tim_h movf tim_h,W ; subtract hi byte banksel NumH movwf NumH banksel hr_h movf hr_h,W banksel NumH subwf NumH,W banksel NumH movwf NumH banksel tim_l movf tim_l,W ; subtract lo byte banksel NumL movwf NumL banksel hr_l movf hr_l,W banksel NumL subwf NumL,W banksel NumL movwf NumL banksel STATUS btfsc STATUS,C goto $+3 banksel NumH decf NumH ; output heart rate message getdata call NMEA_start banksel NMEA_csum movlw "H" ;move data into TXREG xorwf NMEA_csum movwf temp_wr call d_write banksel NMEA_csum movlw "R" ;move data into TXREG xorwf NMEA_csum movwf temp_wr call d_write banksel NMEA_csum movlw "T" ;move data into TXREG xorwf NMEA_csum movwf temp_wr call d_write banksel NMEA_csum movlw "," ;move data into TXREG xorwf NMEA_csum movwf temp_wr call d_write call bin16_bcd movf TenK,W call bin_bcd movf LSD,W movwf temp_wr banksel NMEA_csum xorwf NMEA_csum call d_write movf Thou,W call bin_bcd movf LSD,W movwf temp_wr banksel NMEA_csum xorwf NMEA_csum call d_write movf Hund,W call bin_bcd movf LSD,W movwf temp_wr banksel NMEA_csum xorwf NMEA_csum call d_write movf Tens,W call bin_bcd movf LSD,W movwf temp_wr banksel NMEA_csum xorwf NMEA_csum call d_write movf Ones,W call bin_bcd movf LSD,W movwf temp_wr banksel NMEA_csum xorwf NMEA_csum call d_write call NMEA_end banksel tim_h movf tim_h,W ; store latest timer value movwf hr_h banksel tim_l movf tim_l,W ; store latest timer value movwf hr_l call voltmeter ;; goto hr_next_value ;;commented out for test ;------------- Power Level ----------------------------------------- ; Read power level on A/D number AN0 and output the voltage using ; the VLT message. ;------------- Voltmeter-------------------------------------------- voltmeter banksel ADCON0 ;movlw B'00000001' ;configure A/D converter movlw B'00000001' ;configure A/D converter movwf ADCON0 ;turn A/D on banksel ADCON1 ;movlw b'00001110' ;RA0 = analog input movlw b'00001111' ;RA0,1,3 = analog input/ movwf ADCON1 volts_again banksel ADCON0 bsf ADCON0,GO ;start conversion btfsc ADCON0,GO goto $-1 ;; movf ADRESH,w ;; movwf BARGB0 ;move adresh into BARGB0 ;;----------------BEGIN MATT CODE --------------- ;;------ Below Gets Ready For Multiply ------------ ;; Multiples 254 * Value at ADRESH (Voltage Number) ;; Voltage In is = (ADRESH * 254) / 52 <== Crazy Formula From DC movf ADRESH,w ;; Gets Voltage Pin movwf AARGB0 ;; Loads Voltage Pin into argument for MULTIPLY movlw B'00000000' ;turn off A/D movwf ADCON0 movlw 0xFE ;; Loads 254 into w for movement into BARGBO movwf BARGB0 ;; Moves 254 into second argument for MULTIPLY bcf PCLATH,4 ;; I think I need this to access math library???? Am I wrong? bsf PCLATH,3 ;; If you Can, Id love an explanation of How this memory page stuff works... call UMUL0808L ;; Calls MULTIPLY clrf PCLATH ;; Not Sure if I need this either, playing safe in theory should alreayd be cleared. ;;------ Below Gets Ready For Divide -------------- movlw 0x34 ;; Loads "52" into movwf BARGB0 ;; Sets 52 into divisor bcf PCLATH,4 ;page 1 bsf PCLATH,3 call UDIV1608L ;; Does the actual Division clrf PCLATH ;; Result From Division Should will be stored into high and low accordingly, in the below code. ;; div function movf AARGB0,w ;prepare for 16-bit binary to BCD movwf NumH movf AARGB1,w movwf NumL call bin16_bcd ;get volts ready for LCD ;;----------------END MATT CODE --------------- ;;insert NMEA header here call NMEA_start banksel NMEA_csum movlw "V" ;move data into TXREG xorwf NMEA_csum movwf temp_wr call d_write banksel NMEA_csum movlw "L" ;move data into TXREG xorwf NMEA_csum movwf temp_wr call d_write banksel NMEA_csum movlw "T" ;move data into TXREG xorwf NMEA_csum movwf temp_wr call d_write banksel NMEA_csum movlw "," ;move data into TXREG xorwf NMEA_csum movwf temp_wr call d_write ;; end inserted code. banksel Hund movf Hund,w ;get hunds call bin_bcd movf LSD,w ;send high digit from the LSD #.xx movwf temp_wr xorwf NMEA_csum call d_write movlw A'.' ;send decimal point "." movwf temp_wr xorwf NMEA_csum call d_write movf Tens,w ;get tens call bin_bcd movf LSD,w ;send low digit x.#x movwf temp_wr xorwf NMEA_csum call d_write movf Ones,w ;get ones call bin_bcd movf LSD,w ;send low digit x.x# movwf temp_wr xorwf NMEA_csum call d_write movlw A'V' ;send "V" unit movwf temp_wr xorwf NMEA_csum call d_write call NMEA_end return ;************************** ROUTINES ****************************** ;****************************************************************** ;****************************************************************** ;************************ Below Is Interrupt Service Request Thingy **************************** ;;; INT_SERV MOVWF W_SAVE ;; Saves the W register on Interrupt, so we dont lose any data. SWAPF STATUS, F ;; SWAPF STATUS, W ;; MOVWF S_SAVE ;; This and the two lines above copy the S register to memory so its not lost. ;---------- Insert Main Interrupt Here-------------- ;;Determine if Timer went off call hr_next_value;getdata ;;If it did, we want to write to do output ;---------- End Main Interrupt Here-------------- ;; Goes and Cleans Up Saved Registers SWAPF S_SAVE, F ; restore STATUS SWAPF S_SAVE, W MOVWF STATUS SWAPF W_SAVE, F ; restore W SWAPF W_SAVE, W ;;I need to Restore W Value and Status Value RETFIE ;; Returns From an Interrupt ;;********************* ENDS INTERRUPT SERVICE CODE ******************************************* ;----Output start of the NMEA message. NMEA_start call SIO_on banksel NMEA_csum clrf NMEA_csum ; clear the NMEA checksum movlw "$" ;move data into TXREG movwf temp_wr call d_write banksel NMEA_csum movlw "T" ;move data into TXREG xorwf NMEA_csum movwf temp_wr call d_write banksel NMEA_csum movlw "T" ;move data into TXREG xorwf NMEA_csum movwf temp_wr call d_write return ;----Output end of the NMEA message. NMEA_end banksel TXREG movlw "*" ;move data into TXREG movwf temp_wr call d_write ; checksum goes here when I implement it banksel NMEA_csum swapf NMEA_csum,W andlw 0x0f ; W has hi nibble movwf tmp_w call output_hex banksel NMEA_csum movf NMEA_csum,W andlw 0x0f ; W has lo nibble movwf tmp_w call output_hex movlw "\n" ;move data into TXREG movwf temp_wr call d_write movlw "\r" ;move data into TXREG movwf temp_wr call d_write call SIO_off return output_hex ; W has nibble to be translated to hex and spit out serial. movwf temp_1 movwf tmp_w sublw .9 movwf tmp_w btfss STATUS,C goto hex_letter ; W is greater than or equal to 10 hex_number ; W is 0 to 9 movf temp_1,W movwf tmp_w addlw .48 ; 48, ASCII value for '0' movwf tmp_w movwf temp_wr call d_write return hex_letter ; W is 10 to 15 movf temp_1,W movwf tmp_w addlw .55 ; 65 - 10, ASCII value for 'A' movwf tmp_w movwf temp_wr call d_write return ;----Standard code, Place characters on line-1-------------------------- stan_char_1 banksel ptr_count movlw .16 ;1-full line of LCD movwf ptr_count stan_next_char_1 call SIO_on ; turn on the RS-232 chip. movlw HIGH stan_table movwf PCLATH movf ptr_pos,w ;character table location call stan_table ;retrieve 1 character movwf temp_wr call d_write ;send character to LCD banksel ptr_pos ;get next character for LCD incf ptr_pos,f decfsz ptr_count,f ;move pointer to next char goto stan_next_char_1 movlw "\n" ;next line movwf temp_wr call d_write movlw "\r" ;carriage return movwf temp_wr call d_write call SIO_off ; turn off the RS-232 chip. return ;----Standard code, Place characters on line-2-------------------------- stan_char_2 banksel ptr_count movlw .16 ;1-full line of LCD movwf ptr_count stan_next_char_2 call SIO_on ; turn on the RS-232 chip. movlw HIGH stan_table movwf PCLATH movf ptr_pos,w ;character table location call stan_table ;retrieve 1 character movwf temp_wr call d_write ;send character to LCD banksel ptr_pos ;get next character for lCD incf ptr_pos,f decfsz ptr_count,f ;move pointer to next char goto stan_next_char_2 movlw "\n" ;next line movwf temp_wr call d_write movlw "\r" ;carriage return movwf temp_wr call d_write banksel PORTA ;bank 0 call SIO_off ; turn off the RS-232 chip. return ;---------------------------------------------------------------------- ;-------------------- d_write: --------------------------------- d_write ; next, transmit character banksel temp_wr ; bank 0 movf temp_wr,w movwf TXREG banksel TXSTA btfss TXSTA,TRMT ;wait for data TX goto $-1 banksel PORTA return ;-------------------- SIO_on: ---------------------------------- SIO_on banksel PORTB ; bank 0 bsf PORTB,2 ; RS-232 /SHDN to HI (don't shut down) ;bsf PORTB,3 ; RS-232 EN to HI (enable) ; begin inserted delay banksel temp_1 movlw 0xFF movwf temp_1 ;movlw 0x0A ;movwf temp_2 ;; decfsz temp_1,f ;; goto $-1 ;decfsz temp_2,f ;goto $-3 ; end inserted delay return ;-------------------- SIO_off: --------------------------------- SIO_off ; begin inserted delay ;banksel temp_1 ;movlw 0xFF ;movwf temp_1 ;movlw 0x0A ;movwf temp_2 ;decfsz temp_1,f ;goto $-1 ;decfsz temp_2,f ;goto $-3 ; end inserted delay banksel PORTA ; bank 0 bcf PORTB,2 ; RS-232 /SHDN to LO (do shut down) ;bcf PORTB,3 ; RS-232 EN to LO (don't enable) return ;------------------ 100ms Delay -------------------------------- delay_100ms banksel temp_1 movlw 0xFF movwf temp_1 movlw 0x83 movwf temp_2 decfsz temp_1,f goto $-1 decfsz temp_2,f goto $-3 return ;---------------- 1s Delay ----------------------------------- delay_1s banksel temp_1 movlw 0xFF movwf temp_1 movwf temp_2 movlw 0x05 movwf temp_3 decfsz temp_1,f goto $-1 decfsz temp_2,f goto $-3 decfsz temp_3,f goto $-5 return ;---------------- Binary (8-bit) to BCD ----------------------- ; 255 = highest possible result bin_bcd banksel MSD clrf MSD clrf MsD movwf LSD ;move value to LSD ghundreth movlw .100 ;subtract 100 from LSD subwf LSD,w btfss STATUS,C ;is value greater then 100 goto gtenth ;NO goto tenths movwf LSD ;YES, move subtraction result into LSD incf MSD,f ;increment hundreths goto ghundreth gtenth movlw .10 ;take care of tenths subwf LSD,w btfss STATUS,C goto over ;finished conversion movwf LSD incf MsD,f ;increment tenths position goto gtenth over ;0 - 9, high nibble = 3 for LCD movf MSD,w ;get BCD values ready for LCD display xorlw 0x30 ;convert to LCD digit movwf MSD movf MsD,w xorlw 0x30 ;convert to LCD digit movwf MsD movf LSD,w xorlw 0x30 ;convert to LCD digit movwf LSD retlw 0 ;---------------- Binary (16-bit) to BCD ----------------------- ; xxx = highest possible result bin16_bcd ; Takes number in NumH:NumL ; Returns decimal in TenK:Thou:Hund:Tens:Ones banksel NumH swapf NumH,w andlw 0x0F addlw 0xF0 movwf Thou addwf Thou,f addlw 0xE2 movwf Hund addlw 0x32 movwf Ones movf NumH,w andlw 0x0F addwf Hund,f addwf Hund,f addwf Ones,f addlw 0xE9 movwf Tens addwf Tens,f addwf Tens,f swapf NumL,w andlw 0x0F addwf Tens,f addwf Ones,f rlf Tens,f rlf Ones,f comf Ones,f rlf Ones,f movf NumL,w andlw 0x0F addwf Ones,f rlf Thou,f movlw 0x07 movwf TenK movlw 0x0A ; Ten Lb1: addwf Ones,f decf Tens,f btfss 3,0 goto Lb1 Lb2: addwf Tens,f decf Hund,f btfss 3,0 goto Lb2 Lb3: addwf Hund,f decf Thou,f btfss 3,0 goto Lb3 Lb4: addwf Thou,f decf TenK,f btfss 3,0 goto Lb4 retlw 0 ;---------------------------- EEPROM WRITE ------------------------------- write_eeprom banksel SSPCON2 ;write to EEPROM bsf SSPCON2,SEN ;start bit btfsc SSPCON2,SEN goto $-1 movlw B'10100000' ;send control byte (write) banksel SSPBUF movwf SSPBUF call ssprw banksel SSPCON2 btfsc SSPCON2,ACKSTAT ;ack? goto $-1 movlw 0x00 ;send slave address HIGH byte banksel SSPBUF movwf SSPBUF call ssprw banksel SSPCON2 btfsc SSPCON2,ACKSTAT ;ack? goto $-1 movlw 0x05 ;send slave address LOW byte(0x0005) banksel SSPBUF movwf SSPBUF call ssprw banksel SSPCON2 btfsc SSPCON2,ACKSTAT ;ack? goto $-1 banksel temperature movf temperature,w ;send slave DATA = temperature movwf SSPBUF call ssprw banksel SSPCON2 btfsc SSPCON2,ACKSTAT ;ack? goto $-1 bsf SSPCON2,PEN ;stop bit btfsc SSPCON2,PEN goto $-1 banksel TMR1L bcf PIR1,TMR1IF ;clear TIMER1 overflow flag clrf TMR1L ;clear registers for next overflow clrf TMR1H return ;------------------------ IDLE MODULE ------------------------------------- ssprw ;check for idle SSP module movlw 0x00 banksel SSPCON2 andwf SSPCON2,w sublw 0x00 btfss STATUS,Z goto $-4 btfsc SSPSTAT,R_W goto $-1 return ;--------------------------------------------------------------------------- timer_read ; read current value from timer 1 into tim_h, tim_l banksel TMR1H movf TMR1H,W ; Read hi byte banksel tim_h movwf tim_h ; banksel TMR1L movf TMR1L,W ; Read lo byte banksel tim_l movwf tim_l banksel TMR1H movf TMR1H,W ; re-read hi byte to see if it changed banksel tim_h subwf tim_h,W ; sub first read with second read banksel STATUS btfsc STATUS,Z ; is result = 0? goto tim_rd_ok ; good 16 bit read ; TMR1L may have rolled over between the read of the hi and lo bytes. ; Read bytes again will definitely yield an acceptable result. banksel TMR1H movf TMR1H,W ; read hi byte banksel tim_h movwf tim_h ; banksel TMR1L movf TMR1L,W ; read lo byte banksel tim_l movwf tim_l tim_rd_ok return ;----------------------------------------------------------------------------- end