From a1f769d96fa20ba88faebb5d53aa38bcf6723361 Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Tue, 28 Nov 2023 14:45:18 +0000 Subject: [PATCH 01/29] Update --- main.s | 77 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/main.s b/main.s index dba4af8d..cc2ab002 100644 --- a/main.s +++ b/main.s @@ -1,11 +1,15 @@ #include extrn UART_Setup, UART_Transmit_Message ; external subroutines -extrn LCD_Setup, LCD_Write_Message +extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D +extrn Keypad_INIT, Keypad_READ psect udata_acs ; reserve data space in access ram counter: ds 1 ; reserve one byte for a counter variable delay_count:ds 1 ; reserve one byte for counter in the delay routine +pressed: ds 1 +kb_pressed: ds 1 ; check if keypad pressed +digit_input_counter: ds 1 ; counter for checking how many digits of the age has been inputted psect udata_bank4 ; reserve data anywhere in RAM (here at 0x400) myArray: ds 0x80 ; reserve 128 bytes for message data @@ -25,39 +29,50 @@ rst: org 0x0 ; ******* Programme FLASH read Setup Code *********************** setup: bcf CFGS ; point to Flash program memory bsf EEPGD ; access Flash program memory - call UART_Setup ; setup UART + ;call UART_Setup ; setup UART + call Keypad_INIT ; setup keypad call LCD_Setup ; setup UART + + movlw 0x00 + movwf TRISD + + movlw 0x00 + movwf TRISJ + + movlw 0 + movwf kb_pressed, A ; initialise this as 0, to indicate o key has been pressed + + movlw 2 + movwf digit_input_counter + goto start ; ******* Main programme **************************************** -start: lfsr 0, myArray ; Load FSR0 with address in RAM - movlw low highword(myTable) ; address of data in PM - movwf TBLPTRU, A ; load upper bits to TBLPTRU - movlw high(myTable) ; address of data in PM - movwf TBLPTRH, A ; load high byte to TBLPTRH - movlw low(myTable) ; address of data in PM - movwf TBLPTRL, A ; load low byte to TBLPTRL - movlw myTable_l ; bytes to read - movwf counter, A ; our counter register -loop: tblrd*+ ; one byte from PM to TABLAT, increment TBLPRT - movff TABLAT, POSTINC0; move data from TABLAT to (FSR0), inc FSR0 - decfsz counter, A ; count down to zero - bra loop ; keep going until finished - - movlw myTable_l ; output message to UART - lfsr 2, myArray - call UART_Transmit_Message - - movlw myTable_l ; output message to LCD - addlw 0xff ; don't send the final carriage return to LCD - lfsr 2, myArray - call LCD_Write_Message +start: + movff digit_input_counter, PORTJ + movlw 0 + cpfseq digit_input_counter ; check if there are any digits left to input, skip if = + call Age_Read + nop ; move on to the rest of the code + nop + movlw 0xFF + movwf PORTJ - goto $ ; goto current line in code - - ; a delay subroutine if you need one, times around loop in delay_count -delay: decfsz delay_count, A ; decrement until zero - bra delay - return + +Age_Read: + call Keypad_READ + movwf PORTD + movwf pressed + + movlw 0xFF + cpfslt pressed ; do not output anything to LCD if there is no/invalid input + bra Age_Read - end rst \ No newline at end of file + lfsr 2, pressed + movlw 1 + call LCD_Write_Message + decf digit_input_counter + bra start + + end rst + From aad9faf4f0deccf9b2bdb8234d603b2818073c49 Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Tue, 28 Nov 2023 14:45:32 +0000 Subject: [PATCH 02/29] Update --- LCD.s | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/LCD.s b/LCD.s index ab1f2218..f763ea28 100644 --- a/LCD.s +++ b/LCD.s @@ -1,6 +1,6 @@ #include -global LCD_Setup, LCD_Write_Message +global LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D psect udata_acs ; named variables in access ram LCD_cnt_l: ds 1 ; reserve 1 byte for variable LCD_cnt_l @@ -8,6 +8,7 @@ LCD_cnt_h: ds 1 ; reserve 1 byte for variable LCD_cnt_h LCD_cnt_ms: ds 1 ; reserve 1 byte for ms counter LCD_tmp: ds 1 ; reserve 1 byte for temporary use LCD_counter: ds 1 ; reserve 1 byte for counting through nessage +TwoLineCounter: ds 1 LCD_E EQU 5 ; LCD enable bit LCD_RS EQU 4 ; LCD register select bit @@ -53,6 +54,10 @@ LCD_Loop_message: call LCD_Send_Byte_D decfsz LCD_counter, A bra LCD_Loop_message + movlw 2000 + call LCD_delay_ms + dcfsnz TwoLineCounter, A + bra SetTwoLines return LCD_Send_Byte_I: ; Transmits byte stored in W to instruction reg @@ -85,6 +90,13 @@ LCD_Send_Byte_D: ; Transmits byte stored in W to data reg call LCD_delay_x4us return + + +SetTwoLines: + movlw 11000000B + call LCD_Send_Byte_I + return + LCD_Enable: ; pulse enable bit LCD_E for 500ns nop nop @@ -135,4 +147,3 @@ lcdlp1: decf LCD_cnt_l, F, A ; no carry when 0x00 -> 0xff end - From 92f9f3fa127645820b2c9928b092e72c4215bbc3 Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Tue, 28 Nov 2023 14:50:03 +0000 Subject: [PATCH 03/29] Keypad module contains subroutine for Keypad reading --- Keypad.s | 180 +++++++++++++++++++++++++++++++++++ nbproject/configurations.xml | 43 ++++++++- 2 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 Keypad.s diff --git a/Keypad.s b/Keypad.s new file mode 100644 index 00000000..461fcef8 --- /dev/null +++ b/Keypad.s @@ -0,0 +1,180 @@ +#include + +global Keypad_INIT, Keypad_READ + +psect udata_acs ; reserve data space in access ram +Keypad_counter: ds 1 ; reserve 1 byte for variable UART_counter +row: ds 1 +col: ds 1 +keyval: ds 1 +cnt_ms: ds 1 ; reserve 1 byte for ms counter +cnt_l: ds 1 ; reserve 1 byte for variable cnt_l +cnt_h: ds 1 ; reserve 1 byte for variable cnt_h + +psect uart_code,class=CODE + +Keypad_INIT: + + banksel PADCFG1 + bsf REPU ;PADCFG1, REPU, 1 Pulling up resistors + clrf LATE, A + banksel 0 + + movlw 0x0F + movwf TRISE, A + + movlw 1 + call delay_ms + + return + + +Keypad_READ: + ; Drive output bits low all at once + movlw 0x00 + movwf PORTE, A + + movff PORTE, col ; read in column values + + movlw 0xF0 + movwf TRISE, A ; changing TRI state + + movlw 1 + call delay_ms ;delay + + ; Drive output bits low all at once + movlw 0x00 + movwf PORTE, A + + movff PORTE, row ; read in row values + movff row, WREG + + iorwf col, 0, 0 ; inclusive or logic for row and column + movwf keyval ; + + movlw 0x0F + movwf TRISE, A + + movlw 1 + call delay_ms + + call Test_none ; decode results, returns with result in working directory + + return + +Test_none: ; no key pressed + movlw 0xFF + cpfseq keyval, A + bra Test_0 ; this is the ?no? result + retlw 0xFF ; this is the ?yes? result +Test_0: + movlw 0xBE + cpfseq keyval, A + bra Test_1 + retlw '0' +Test_1: + movlw 0x77 + cpfseq keyval, A + bra Test_2 + retlw '1' +Test_2: + movlw 0xB7 + cpfseq keyval, A + bra Test_3 + retlw '2' +Test_3: + movlw 0xD7 + cpfseq keyval, A + bra Test_4 + retlw '3' +Test_4: + movlw 0x7B + cpfseq keyval, A + bra Test_5 + retlw '4' +Test_5: + movlw 0xBB + cpfseq keyval, A + bra Test_6 + retlw '5' +Test_6: + movlw 0xDB + cpfseq keyval, A + bra Test_7 + retlw '6' +Test_7: + movlw 0x7D + cpfseq keyval, A + bra Test_8 + retlw '7' +Test_8: + movlw 0xBD + cpfseq keyval, A + bra Test_9 + retlw '8' +Test_9: + movlw 0xDD + cpfseq keyval, A + bra Test_A + retlw '9' +Test_A: + movlw 0x7E + cpfseq keyval, A + bra Test_B + retlw 'A' +Test_B: + movlw 0xDE + cpfseq keyval, A + bra Test_C + retlw 'B' +Test_C: + movlw 0xEE + cpfseq keyval, A + bra Test_D + retlw 'C' +Test_D: + movlw 0xED + cpfseq keyval, A + bra Test_E + retlw 'D' +Test_E: + movlw 0xEB + cpfseq keyval, A + bra Test_F + retlw 'E' +Test_F: + movlw 0xE7 + cpfseq keyval, A + retlw 0xFF ; error message + retlw 'F' + + +delay_ms: ; delay given in ms in W + movwf cnt_ms, A +lp2: movlw 250 + call delay_x4us + decfsz cnt_ms, A + bra lp2 + return + +delay_x4us: ; delay given in chunks of 4 microsecond in W + movwf cnt_l, A ; now need to multiply by 16 + swapf cnt_l, F, A ; swap nibbles + movlw 0x0f + andwf cnt_l, W, A ; move low nibble to W + movwf cnt_h, A ; then to cnt_h + movlw 0xf0 + andwf cnt_l, F, A ; keep high nibble in cnt_l + call delay + return + +delay: ; delay routine 4 instruction loop == 250ns + movlw 0x00 ; W=0 +lp1: decf cnt_l, F, A ; no carry when 0x00 -> 0xff + subwfb cnt_h, F, A ; no carry when 0x00 -> 0xff + bc lp1 ; carry, then loop again + return ; carry reset so return + + + + diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 06bd9f31..ccbfb946 100755 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -16,6 +16,7 @@ main.s UART.s LCD.s + Keypad.s ICD3PlatformTool pic-as - 2.30 + 2.45 4 @@ -58,6 +59,7 @@ false + false false @@ -562,6 +564,45 @@ value=""/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 593eea7d8ec7325170f83e2a536ce6c8b516bb0a Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Tue, 28 Nov 2023 21:54:57 +0000 Subject: [PATCH 04/29] Age Input Code Update Added module for decoding two digit inputs. Changed main.s to: read in two digits accordingly, add digits together to get final age, find maximum heart rate from age and save all data above to memory. ** Need testing and checking if decoder works. --- Calculations.s | 9 + Digit_Reader.s | 134 ++++++++++ Keypad.s | 4 +- main.s | 80 ++++-- nbproject/configurations.xml | 501 ++++++++++++++++++++++++++++++++++- 5 files changed, 704 insertions(+), 24 deletions(-) create mode 100644 Calculations.s create mode 100644 Digit_Reader.s diff --git a/Calculations.s b/Calculations.s new file mode 100644 index 00000000..ae294a11 --- /dev/null +++ b/Calculations.s @@ -0,0 +1,9 @@ +#include + +global Find_Max_Heart_Rate + +; this includes subroutines for calculations: e.g. max heart rate calculation, boundary calculations + +Find_Max_Heart_Rate: + sublw 220 ; subtract age from 220 to find the maximum heart rate, store in WREG + return diff --git a/Digit_Reader.s b/Digit_Reader.s new file mode 100644 index 00000000..1303e653 --- /dev/null +++ b/Digit_Reader.s @@ -0,0 +1,134 @@ +#include + +; This includes the subroutine to decode the input from the keypad for the two-digit age input + +global Decode_First_Digit, Decode_Second_Digit + +;psect data_section, global, class = DABS +;first_digit: ds 1 +;second_digit: ds 1 + +psect udata ; reserve data space in access ram +first_digit: ds 1 +second_digit: ds 1 + +Decode_First_Digit: ; Read input from keypad, interpret as the 10s value, return as literal + movwf first_digit, A +Test_none_1: ; no key pressed + movlw 0xFF + cpfseq first_digit, A + bra Test_0_1 ; this is the ?no? result + retlw 0xFF ; this is the ?yes? result +Test_0_1: + movlw 0xBE + cpfseq first_digit, A + bra Test_1_1 + retlw 0 +Test_1_1: + movlw 0x77 + cpfseq first_digit, A + bra Test_2_1 + retlw 10 +Test_2_1: + movlw 0xB7 + cpfseq first_digit, A + bra Test_3_1 + retlw 20 +Test_3_1: + movlw 0xD7 + cpfseq first_digit, A + bra Test_4_1 + retlw 30 +Test_4_1: + movlw 0x7B + cpfseq first_digit, A + bra Test_5_1 + retlw 40 +Test_5_1: + movlw 0xBB + cpfseq first_digit, A + bra Test_6_1 + retlw 50 +Test_6_1: + movlw 0xDB + cpfseq first_digit, A + bra Test_7_1 + retlw 60 +Test_7_1: + movlw 0x7D + cpfseq first_digit, A + bra Test_8_1 + retlw 70 +Test_8_1: + movlw 0xBD + cpfseq first_digit, A + bra Test_9_1 + retlw 80 +Test_9_1: + movlw 0xDD + cpfseq first_digit, A + retlw 0xFF ; error message: when a letter or an invalid input has been detected + retlw 90 + + +Decode_Second_Digit: ; Read input from keypad, interpret as the 10s value, return as literal + movwf second_digit, A +Test_none_2: ; no key pressed + movlw 0xFF + cpfseq second_digit, A + bra Test_0_2 ; this is the ?no? result + retlw 0xFF ; this is the ?yes? result +Test_0_2: + movlw 0xBE + cpfseq second_digit, A + bra Test_1_2 + retlw 0 +Test_1_2: + movlw 0x77 + cpfseq second_digit, A + bra Test_2_2 + retlw 1 +Test_2_2: + movlw 0xB7 + cpfseq second_digit, A + bra Test_3_2 + retlw 2 +Test_3_2: + movlw 0xD7 + cpfseq second_digit, A + bra Test_4_2 + retlw 3 +Test_4_2: + movlw 0x7B + cpfseq second_digit, A + bra Test_5_2 + retlw 4 +Test_5_2: + movlw 0xBB + cpfseq second_digit, A + bra Test_6_2 + retlw 5 +Test_6_2: + movlw 0xDB + cpfseq second_digit, A + bra Test_7_2 + retlw 6 +Test_7_2: + movlw 0x7D + cpfseq second_digit, A + bra Test_8_2 + retlw 7 +Test_8_2: + movlw 0xBD + cpfseq second_digit, A + bra Test_9_2 + retlw 8 +Test_9_2: + movlw 0xDD + cpfseq second_digit, A + retlw 0xFF ; error message: when a letter or an invalid input has been detected + retlw 9 + + + + diff --git a/Keypad.s b/Keypad.s index 461fcef8..13f5f8c2 100644 --- a/Keypad.s +++ b/Keypad.s @@ -58,7 +58,9 @@ Keypad_READ: movlw 1 call delay_ms - call Test_none ; decode results, returns with result in working directory + movff keyval, WREG ; move keyvalue into WREG for decoder to work + + ;call Test_none ; decode results, returns with result in working directory return diff --git a/main.s b/main.s index cc2ab002..6ad995b2 100644 --- a/main.s +++ b/main.s @@ -3,6 +3,8 @@ extrn UART_Setup, UART_Transmit_Message ; external subroutines extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D extrn Keypad_INIT, Keypad_READ +extrn Find_Max_Heart_Rate +extrn Decode_First_Digit, Decode_Second_Digit psect udata_acs ; reserve data space in access ram counter: ds 1 ; reserve one byte for a counter variable @@ -10,6 +12,10 @@ delay_count:ds 1 ; reserve one byte for counter in the delay routine pressed: ds 1 kb_pressed: ds 1 ; check if keypad pressed digit_input_counter: ds 1 ; counter for checking how many digits of the age has been inputted +age_first: ds 1 ; first digit of age input +age_second: ds 1 ; second digit of age input +age: ds 1 ; age, after combining the two digits +maximum_heart_rate: ds 1 ; value for maximum heart rate is stored here psect udata_bank4 ; reserve data anywhere in RAM (here at 0x400) myArray: ds 0x80 ; reserve 128 bytes for message data @@ -43,36 +49,68 @@ setup: bcf CFGS ; point to Flash program memory movwf kb_pressed, A ; initialise this as 0, to indicate o key has been pressed movlw 2 - movwf digit_input_counter + movwf digit_input_counter ; initialise digit counter to 2, as our upper limit of age is 99 goto start ; ******* Main programme **************************************** -start: - movff digit_input_counter, PORTJ - movlw 0 - cpfseq digit_input_counter ; check if there are any digits left to input, skip if = - call Age_Read - nop ; move on to the rest of the code - nop - movlw 0xFF - movwf PORTJ +Age_Read_1: + movlw 0xB7 ; this is just for a test + movwf PORTE ; also for test -Age_Read: - call Keypad_READ - movwf PORTD - movwf pressed + call Keypad_READ ; keypad read subroutine, value stored in W + call Decode_First_Digit ; decode first digit, return with 10s value in WREG + movwf age_first ; save value in variable age_first + movwf PORTD ; output to PORTD to visualise the number just inputted - movlw 0xFF - cpfslt pressed ; do not output anything to LCD if there is no/invalid input - bra Age_Read + movlw 0xFF ; value of error message + cpfslt age_first ; if no valid input, branch to Age_Read_1 to read from Keypad again; + bra Age_Read_1 + decf digit_input_counter ; if there has been a valid input, decrement the digit counter and return + return - lfsr 2, pressed +Age_Read_2: + movlw 0xB7 ; this is just for a test + movwf PORTE ; also for test + + call Keypad_READ ; keypad read subroutine, value stored in W + call Decode_Second_Digit ; decode first digit, return with 10s value in WREG + movwf age_second ; save value in variable age_first + movwf PORTD ; output to PORTD to visualise the number just inputted + + movlw 0xFF ; value of error message + cpfslt age_second ; if no valid input, branch to Age_Read_1 to read from Keypad again; + bra Age_Read_2 + decf digit_input_counter ; if there has been a valid input, decrement the digit counter and return + return + + +start: + + ; read in age input from keypad + movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted + movlw 2 ; set WREG to 2, to deduce value in digit coubnter + cpfslt digit_input_counter ; skip if smaller than two, otherwise read first digit + call Age_Read_1 movlw 1 - call LCD_Write_Message - decf digit_input_counter - bra start + cpfslt digit_input_counter ; skip if smaller than 1, otherwise read second digit + call Age_Read_2 + + ; add the two digits of age together + movff age_first, WREG ; move first digit of age to WREG + addwf age_second, W ; add second digit to WRED (age_first) and store result in WREG + movwf age ; store age in memory + movff age, PORTD ; output to PORTD to visualise age + + ; find maximum heart rate + movff age, WREG ; put age in WREG for use in subroutine + call Find_Max_Heart_Rate + movwf maximum_heart_rate ; move value for maximum heart rate into variable + + nop ; move on to the rest of the code + nop + end rst diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index ccbfb946..ec4baff3 100755 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -17,6 +17,8 @@ UART.s LCD.s Keypad.s + Digit_Reader.s + Calculations.s PIC18F87K22 - ICD3PlatformTool + Simulator pic-as 2.45 4 - + @@ -74,8 +76,13 @@ + + + + + @@ -110,6 +117,11 @@ + + + + + @@ -134,6 +146,13 @@ value="toolpack.updateoptions.uselatestoolpack"/> + + + + + + + @@ -263,6 +282,8 @@ value="report"/> + + + + + + + + + + @@ -586,6 +617,24 @@ value="${memories.instruction.ram.ranges}"/> + + + + + + + + + + + + + + + + + + @@ -601,7 +650,453 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -617,6 +1112,7 @@ + @@ -637,6 +1133,7 @@ + From 23b474959fd1b9f5734ba4831445f9c31be5412b Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Thu, 30 Nov 2023 12:32:15 +0000 Subject: [PATCH 05/29] End of session 2 working code (30/11) Keypad input working --- Keypad.s | 3 ++- main.s | 43 +++++++++++++++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/Keypad.s b/Keypad.s index 13f5f8c2..08b4aba2 100644 --- a/Keypad.s +++ b/Keypad.s @@ -1,6 +1,6 @@ #include -global Keypad_INIT, Keypad_READ +global Keypad_INIT, Keypad_READ, delay_ms psect udata_acs ; reserve data space in access ram Keypad_counter: ds 1 ; reserve 1 byte for variable UART_counter @@ -180,3 +180,4 @@ lp1: decf cnt_l, F, A ; no carry when 0x00 -> 0xff + diff --git a/main.s b/main.s index 6ad995b2..23bb63ab 100644 --- a/main.s +++ b/main.s @@ -2,7 +2,7 @@ extrn UART_Setup, UART_Transmit_Message ; external subroutines extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D -extrn Keypad_INIT, Keypad_READ +extrn Keypad_INIT, Keypad_READ, delay_ms extrn Find_Max_Heart_Rate extrn Decode_First_Digit, Decode_Second_Digit @@ -56,40 +56,46 @@ setup: bcf CFGS ; point to Flash program memory ; ******* Main programme **************************************** Age_Read_1: - movlw 0xB7 ; this is just for a test - movwf PORTE ; also for test + + movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted call Keypad_READ ; keypad read subroutine, value stored in W call Decode_First_Digit ; decode first digit, return with 10s value in WREG movwf age_first ; save value in variable age_first movwf PORTD ; output to PORTD to visualise the number just inputted + movlw 0xFF + call delay_ms + movlw 0xFF ; value of error message cpfslt age_first ; if no valid input, branch to Age_Read_1 to read from Keypad again; bra Age_Read_1 - decf digit_input_counter ; if there has been a valid input, decrement the digit counter and return + decf digit_input_counter,1 ; if there has been a valid input, decrement the digit counter and return + return Age_Read_2: - movlw 0xB7 ; this is just for a test - movwf PORTE ; also for test + + movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted call Keypad_READ ; keypad read subroutine, value stored in W call Decode_Second_Digit ; decode first digit, return with 10s value in WREG movwf age_second ; save value in variable age_first movwf PORTD ; output to PORTD to visualise the number just inputted + movlw 0xFF + call delay_ms + movlw 0xFF ; value of error message cpfslt age_second ; if no valid input, branch to Age_Read_1 to read from Keypad again; bra Age_Read_2 - decf digit_input_counter ; if there has been a valid input, decrement the digit counter and return + decf digit_input_counter, 1 ; if there has been a valid input, decrement the digit counter and return + movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted return start: - ; read in age input from keypad - movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted movlw 2 ; set WREG to 2, to deduce value in digit coubnter cpfslt digit_input_counter ; skip if smaller than two, otherwise read first digit call Age_Read_1 @@ -101,16 +107,33 @@ start: movff age_first, WREG ; move first digit of age to WREG addwf age_second, W ; add second digit to WRED (age_first) and store result in WREG movwf age ; store age in memory + movff age, PORTD + + movlw 0xFF + movwf PORTJ + + movlw 0xFF + call delay_ms - movff age, PORTD ; output to PORTD to visualise age + movlw 0xFF + call delay_ms + + movlw 0xFF + call delay_ms + + movlw 0xFF + call delay_ms ; delay to see on board ; find maximum heart rate movff age, WREG ; put age in WREG for use in subroutine + call Find_Max_Heart_Rate movwf maximum_heart_rate ; move value for maximum heart rate into variable nop ; move on to the rest of the code nop + + goto $ end rst From 3bdfe219d94043c069b4542a3fb626eccdd87dd8 Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Thu, 30 Nov 2023 16:11:49 +0000 Subject: [PATCH 06/29] Division Subroutine Integrated with Module Clean Up Now main.s only contains calling of subroutines, all subroutines are contained in other files. --- Calculations.s | 48 +++++++++++++++++++++- Digit_Reader.s | 95 ++++++++++++++++++++++++++++++++++++++++++-- main.s | 106 +++++++++---------------------------------------- 3 files changed, 157 insertions(+), 92 deletions(-) diff --git a/Calculations.s b/Calculations.s index ae294a11..0150572d 100644 --- a/Calculations.s +++ b/Calculations.s @@ -1,9 +1,55 @@ #include -global Find_Max_Heart_Rate +global Find_Max_Heart_Rate, Divide_By_20 ; this includes subroutines for calculations: e.g. max heart rate calculation, boundary calculations +psect udata_acs +myDenominator:ds 1 +myNumerator:ds 1 +myQuotient:ds 1 +myRemainder:ds 1 +myDiff:ds 1 + +psect calculations_code,class=CODE + Find_Max_Heart_Rate: sublw 220 ; subtract age from 220 to find the maximum heart rate, store in WREG return + +Divide_By_20: ; divide the number stored in WREG by 20 + ; Ensure myDenominator is not zero + MOVWF myNumerator + MOVLW 20 + MOVWF myDenominator ; divide by 20 + + MOVLW 0 ; Move 0 into WREG to check if denominator is zero + CPFSEQ myDenominator + GOTO Clear ; Check the MSB of myDenominator + GOTO DivisionError ; If zero, handle division by zero +Clear: ; Perform division algorithm + CLRF myQuotient ; Clear the quotient register + CLRF myRemainder ; Clear the remainder register + +DivideLoop: + MOVFF myNumerator, WREG + ; rather than doing subtraction, just do a comparison + CPFSGT myDenominator ; myNumerator(WREG) < myDenominator, skip to finish + GOTO Incr + GOTO DivisionDone ; Done if myNumerator < myDenominator +Incr: + INCF myQuotient, 1 ; Increment quotient + MOVFF myDenominator, WREG + SUBWF myNumerator, 1 ; myNumerator -= myDenominator + GOTO DivideLoop ; Repeat the loop + +DivisionDone: + ; Quotient is in myQuotient, remainder is in myRemainder + MOVFF myQuotient, PORTC + MOVFF myQuotient, WREG + RETURN + +DivisionError: + ; Handle division by zero or other error + ; Your code here + RETURN diff --git a/Digit_Reader.s b/Digit_Reader.s index 1303e653..ee5f36c3 100644 --- a/Digit_Reader.s +++ b/Digit_Reader.s @@ -2,15 +2,104 @@ ; This includes the subroutine to decode the input from the keypad for the two-digit age input -global Decode_First_Digit, Decode_Second_Digit - +global Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max +extrn Keypad_READ +extrn delay_ms +extrn Find_Max_Heart_Rate + ;psect data_section, global, class = DABS ;first_digit: ds 1 ;second_digit: ds 1 -psect udata ; reserve data space in access ram +psect udata_acs ; reserve data space in access ram first_digit: ds 1 second_digit: ds 1 +digit_input_counter: ds 1 ; counter for checking how many digits of the age has been inputted +age_first: ds 1 ; first digit of age input +age_second: ds 1 ; second digit of age input +age: ds 1 ; age, after combining the two digits +maximum_heart_rate: ds 1 ; value for maximum heart rate is stored here + +psect digit_reader_code,class=CODE + +Age_Read_1: + + movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted + + call Keypad_READ ; keypad read subroutine, value stored in W + call Decode_First_Digit ; decode first digit, return with 10s value in WREG + movwf age_first ; save value in variable age_first + movwf PORTD ; output to PORTD to visualise the number just inputted + + movlw 0xFF + call delay_ms + + movlw 0xFF ; value of error message + cpfslt age_first ; if no valid input, branch to Age_Read_1 to read from Keypad again; + bra Age_Read_1 + decf digit_input_counter,1 ; if there has been a valid input, decrement the digit counter and return + + return + +Age_Read_2: + movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted + + call Keypad_READ ; keypad read subroutine, value stored in W + call Decode_Second_Digit ; decode first digit, return with 10s value in WREG + movwf age_second ; save value in variable age_first + movwf PORTD ; output to PORTD to visualise the number just inputted + + movlw 0xFF + call delay_ms + + movlw 0xFF ; value of error message + cpfslt age_second ; if no valid input, branch to Age_Read_1 to read from Keypad again; + bra Age_Read_2 + decf digit_input_counter, 1 ; if there has been a valid input, decrement the digit counter and return + movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted + return + +Read_Age_Input_Find_HR_Max: + ; read in age input from keypad + movlw 2 + movwf digit_input_counter + + movlw 2 ; set WREG to 2, to deduce value in digit coubnter + cpfslt digit_input_counter ; skip if smaller than two, otherwise read first digit + call Age_Read_1 + movlw 1 + cpfslt digit_input_counter ; skip if smaller than 1, otherwise read second digit + call Age_Read_2 + + ; add the two digits of age together + movff age_first, WREG ; move first digit of age to WREG + addwf age_second, W ; add second digit to WRED (age_first) and store result in WREG + movwf age ; store age in memory + movff age, PORTD + + movlw 0xFF + movwf PORTJ + + movlw 0xFF + call delay_ms + + movlw 0xFF + call delay_ms + + movlw 0xFF + call delay_ms + + movlw 0xFF + call delay_ms ; delay to see on board + + ; find maximum heart rate + movff age, WREG ; put age in WREG for use in subroutine + + call Find_Max_Heart_Rate + movwf maximum_heart_rate ; move value for maximum heart rate into variable + movff maximum_heart_rate, WREG + + return Decode_First_Digit: ; Read input from keypad, interpret as the 10s value, return as literal movwf first_digit, A diff --git a/main.s b/main.s index 23bb63ab..2946b0ed 100644 --- a/main.s +++ b/main.s @@ -1,21 +1,18 @@ #include -extrn UART_Setup, UART_Transmit_Message ; external subroutines +;extrn UART_Setup, UART_Transmit_Message ; external subroutines extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D extrn Keypad_INIT, Keypad_READ, delay_ms -extrn Find_Max_Heart_Rate -extrn Decode_First_Digit, Decode_Second_Digit +extrn Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max +extrn Divide_By_20 psect udata_acs ; reserve data space in access ram -counter: ds 1 ; reserve one byte for a counter variable -delay_count:ds 1 ; reserve one byte for counter in the delay routine -pressed: ds 1 +counter: ds 1 ; reserve one byte for a counter variable +delay_count:ds 1 ; reserve one byte for counter in the delay routine +pressed:ds 1 kb_pressed: ds 1 ; check if keypad pressed -digit_input_counter: ds 1 ; counter for checking how many digits of the age has been inputted -age_first: ds 1 ; first digit of age input -age_second: ds 1 ; second digit of age input -age: ds 1 ; age, after combining the two digits -maximum_heart_rate: ds 1 ; value for maximum heart rate is stored here +HR_max: ds 1 ; the maximum heart rate calculated froma ge +HR_max_20: ds 1 ; the quotient of HR_max divided by 20 psect udata_bank4 ; reserve data anywhere in RAM (here at 0x400) myArray: ds 0x80 ; reserve 128 bytes for message data @@ -45,91 +42,24 @@ setup: bcf CFGS ; point to Flash program memory movlw 0x00 movwf TRISJ - movlw 0 - movwf kb_pressed, A ; initialise this as 0, to indicate o key has been pressed - - movlw 2 - movwf digit_input_counter ; initialise digit counter to 2, as our upper limit of age is 99 - + ;movlw 0 + ;movwf kb_pressed, A ; initialise this as 0, to indicate o key has been pressed + goto start ; ******* Main programme **************************************** -Age_Read_1: - - movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted - - call Keypad_READ ; keypad read subroutine, value stored in W - call Decode_First_Digit ; decode first digit, return with 10s value in WREG - movwf age_first ; save value in variable age_first - movwf PORTD ; output to PORTD to visualise the number just inputted - - movlw 0xFF - call delay_ms - - movlw 0xFF ; value of error message - cpfslt age_first ; if no valid input, branch to Age_Read_1 to read from Keypad again; - bra Age_Read_1 - decf digit_input_counter,1 ; if there has been a valid input, decrement the digit counter and return - - return - -Age_Read_2: - - movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted - - call Keypad_READ ; keypad read subroutine, value stored in W - call Decode_Second_Digit ; decode first digit, return with 10s value in WREG - movwf age_second ; save value in variable age_first - movwf PORTD ; output to PORTD to visualise the number just inputted - - movlw 0xFF - call delay_ms - - movlw 0xFF ; value of error message - cpfslt age_second ; if no valid input, branch to Age_Read_1 to read from Keypad again; - bra Age_Read_2 - decf digit_input_counter, 1 ; if there has been a valid input, decrement the digit counter and return - movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted - return - - start: - ; read in age input from keypad - movlw 2 ; set WREG to 2, to deduce value in digit coubnter - cpfslt digit_input_counter ; skip if smaller than two, otherwise read first digit - call Age_Read_1 - movlw 1 - cpfslt digit_input_counter ; skip if smaller than 1, otherwise read second digit - call Age_Read_2 - - ; add the two digits of age together - movff age_first, WREG ; move first digit of age to WREG - addwf age_second, W ; add second digit to WRED (age_first) and store result in WREG - movwf age ; store age in memory - movff age, PORTD + movlw 201 ; for testing + movwf HR_max ; for testing - movlw 0xFF - movwf PORTJ + ;call Read_Age_Input_Find_HR_Max ; return with W = HRmax + ;movwf HR_max - movlw 0xFF - call delay_ms + movff HR_max, WREG ; move HR_max into WREG for use with function + call Divide_By_20 ; return with HR_max/20 in WREG + movwf HR_max_20 ; save quotient of divison (integer) in variable HR_max_20 - movlw 0xFF - call delay_ms - - movlw 0xFF - call delay_ms - - movlw 0xFF - call delay_ms ; delay to see on board - - ; find maximum heart rate - movff age, WREG ; put age in WREG for use in subroutine - - call Find_Max_Heart_Rate - movwf maximum_heart_rate ; move value for maximum heart rate into variable - nop ; move on to the rest of the code nop From 15354bf0ed26edef360ea87d6b8a57bcbd4480bd Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Thu, 30 Nov 2023 16:54:29 +0000 Subject: [PATCH 07/29] Started Table Subroutine Setup table Need to check if loop is running through the table correctly. --- main.s | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/main.s b/main.s index 2946b0ed..f0bbd164 100644 --- a/main.s +++ b/main.s @@ -13,17 +13,21 @@ pressed:ds 1 kb_pressed: ds 1 ; check if keypad pressed HR_max: ds 1 ; the maximum heart rate calculated froma ge HR_max_20: ds 1 ; the quotient of HR_max divided by 20 +LOOP_COUNTER:ds 1 ; loop counter for HRZ boundary value calculations +TABLE_INDEX_DIFF:ds 1 ; variable used to check end of loop condition +STATUS_CHECK:ds 1 ; use this in loop to check if the end of loop as been reached + TABLE_START_ADDRESS EQU 0xA0 ; table start address for HRZ boundary values + TABLE_SIZE EQU 8 ; this value needs to be n+1, where n is how many times you want to read/write the table psect udata_bank4 ; reserve data anywhere in RAM (here at 0x400) myArray: ds 0x80 ; reserve 128 bytes for message data -psect data +psect HRZ_data ; ******* myTable, data in programme memory, and its length ***** myTable: - db 'H','e','l','l','o',' ','W','o','r','l','d','!',0x0a - ; message, plus carriage return - myTable_l EQU 13 ; length of data - align 2 + db 20, 18, 17, 15, 13, 11 + myTable_l EQU 6 ; length of data + ;align 2 psect code, abs rst: org 0x0 @@ -60,7 +64,49 @@ start: call Divide_By_20 ; return with HR_max/20 in WREG movwf HR_max_20 ; save quotient of divison (integer) in variable HR_max_20 - nop ; move on to the rest of the code +; The following code creates a table that contain the upper boundary value for HRZs. +; Initialize loop counter + MOVLW 0 + MOVWF LOOP_COUNTER + +LOOP: ; Loop through the table + + MOVLW myTable + ADDWF LOOP_COUNTER, W ; Calculate the address of the current table element + MOVWF TBLPTRH + MOVLW 0 + MOVWF TBLPTRL + + TBLRD* ; Read the current table element + MOVF TABLAT, W ; Use the value in WREG as needed + MOVFF TABLAT, PORTD + +; Your processing code goes here +; Example: Increment the value and write it back to the table + ;INCF WREG, 0 + ;MOVWF TABLAT + ;MOVWF PORTD + ;TBLWT* + + MOVFF LOOP_COUNTER, 0x10 + INCF LOOP_COUNTER, 1 ; Increment loop counter + + ; Check if we've reached the end of the table + MOVLW myTable_l + MOVWF TABLE_INDEX_DIFF ; set variable to be equal to the size of the table + SUBFWB LOOP_COUNTER, 0 ; Store difference in WREG + MOVWF STATUS_CHECK + + MOVLW 0 + CPFSEQ STATUS_CHECK ; If f=W=0, end loop + GOTO LOOP ; Repeat the loop + GOTO END_LOOP + +END_LOOP: + MOVLW 0xFF + MOVWF PORTE + ; Your code continues... + nop ; move on with the rest of the code nop goto $ From 3fbf709d6404c1f48ef7e525801331a321e52216 Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Thu, 30 Nov 2023 21:59:38 +0000 Subject: [PATCH 08/29] Table Access Code Works Still need to implement multiplication to find the actual HR boundary value, find out how to use TBLWT. --- main.s | 87 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/main.s b/main.s index f0bbd164..d072baed 100644 --- a/main.s +++ b/main.s @@ -23,11 +23,12 @@ psect udata_bank4 ; reserve data anywhere in RAM (here at 0x400) myArray: ds 0x80 ; reserve 128 bytes for message data psect HRZ_data +ORG 0x1000 ; ******* myTable, data in programme memory, and its length ***** -myTable: - db 20, 18, 17, 15, 13, 11 - myTable_l EQU 6 ; length of data - ;align 2 +Database: + DB 20, 18, 17, 15, 13, 11 + CurrentIndex EQU 0x30 + align 2 psect code, abs rst: org 0x0 @@ -43,6 +44,12 @@ setup: bcf CFGS ; point to Flash program memory movlw 0x00 movwf TRISD + movlw 0x00 + movwf TRISC + + movlw 0x00 + movwf TRISB + movlw 0x00 movwf TRISJ @@ -64,50 +71,48 @@ start: call Divide_By_20 ; return with HR_max/20 in WREG movwf HR_max_20 ; save quotient of divison (integer) in variable HR_max_20 -; The following code creates a table that contain the upper boundary value for HRZs. -; Initialize loop counter - MOVLW 0 - MOVWF LOOP_COUNTER - -LOOP: ; Loop through the table - - MOVLW myTable - ADDWF LOOP_COUNTER, W ; Calculate the address of the current table element + ; Set up the table read pointer + MOVLW high(Database) MOVWF TBLPTRH - MOVLW 0 + MOVLW low(Database) MOVWF TBLPTRL - TBLRD* ; Read the current table element - MOVF TABLAT, W ; Use the value in WREG as needed - MOVFF TABLAT, PORTD - -; Your processing code goes here -; Example: Increment the value and write it back to the table - ;INCF WREG, 0 - ;MOVWF TABLAT - ;MOVWF PORTD - ;TBLWT* - - MOVFF LOOP_COUNTER, 0x10 - INCF LOOP_COUNTER, 1 ; Increment loop counter + ; Initialize the index + ;MOVLW 0 + ;MOVWF CurrentIndex + ;MOVFF CurrentIndex, PORTC + + ; Main loop to access the database +AccessLoop: + ; Calculate the address of the current record + ;MOVLW 0 + ;ADDWF CurrentIndex, W + ;MOVWF TBLPTRU - ; Check if we've reached the end of the table - MOVLW myTable_l - MOVWF TABLE_INDEX_DIFF ; set variable to be equal to the size of the table - SUBFWB LOOP_COUNTER, 0 ; Store difference in WREG - MOVWF STATUS_CHECK + ; Read the data from the database + TBLRD*+ + MOVF TABLAT, W ; Move the read data to WREG or other register + MOVFF TABLAT, PORTD + + ;INCF CurrentIndex, 1 + + ;MOVFF CurrentIndex, WREG + MOVFF TBLPTRL, PORTC + MOVFF TBLPTRL, WREG + + SUBLW 6 + MOVWF STATUS_CHECK ; difference between length of database and current index + MOVFF STATUS_CHECK, PORTB MOVLW 0 - CPFSEQ STATUS_CHECK ; If f=W=0, end loop - GOTO LOOP ; Repeat the loop - GOTO END_LOOP + CPFSEQ STATUS_CHECK ; If difference is zero, skip to end of the loop + GOTO AccessLoop + GOTO EndAccessLoop +EndAccessLoop: + GOTO $ + + -END_LOOP: - MOVLW 0xFF - MOVWF PORTE - ; Your code continues... - nop ; move on with the rest of the code - nop goto $ From f880d572a0ad30fd2e46bca068fe8d4738e00156 Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Fri, 1 Dec 2023 14:34:25 +0000 Subject: [PATCH 09/29] Update: HRZ Table Read/Write Code ready to move onto next section: Read in heart rate data from sensor --- Calculations.s | 52 ++++++++++++++++------------- main.s | 91 +++++++++++++++++++++++++------------------------- 2 files changed, 73 insertions(+), 70 deletions(-) diff --git a/Calculations.s b/Calculations.s index 0150572d..75d1b9cd 100644 --- a/Calculations.s +++ b/Calculations.s @@ -4,7 +4,7 @@ global Find_Max_Heart_Rate, Divide_By_20 ; this includes subroutines for calculations: e.g. max heart rate calculation, boundary calculations psect udata_acs -myDenominator:ds 1 +myDenominator_low:ds 1 myNumerator:ds 1 myQuotient:ds 1 myRemainder:ds 1 @@ -19,37 +19,41 @@ Find_Max_Heart_Rate: Divide_By_20: ; divide the number stored in WREG by 20 ; Ensure myDenominator is not zero - MOVWF myNumerator - MOVLW 20 - MOVWF myDenominator ; divide by 20 + ; MOVWF myNumerator + + MOVLW 19 ; Think this needs to be n - 1, where n is the denominator?? + MOVWF myDenominator_low ; divide by 20 MOVLW 0 ; Move 0 into WREG to check if denominator is zero - CPFSEQ myDenominator + CPFSEQ myDenominator_low GOTO Clear ; Check the MSB of myDenominator GOTO DivisionError ; If zero, handle division by zero Clear: ; Perform division algorithm CLRF myQuotient ; Clear the quotient register CLRF myRemainder ; Clear the remainder register -DivideLoop: - MOVFF myNumerator, WREG - ; rather than doing subtraction, just do a comparison - CPFSGT myDenominator ; myNumerator(WREG) < myDenominator, skip to finish - GOTO Incr - GOTO DivisionDone ; Done if myNumerator < myDenominator -Incr: - INCF myQuotient, 1 ; Increment quotient - MOVFF myDenominator, WREG - SUBWF myNumerator, 1 ; myNumerator -= myDenominator - GOTO DivideLoop ; Repeat the loop - -DivisionDone: - ; Quotient is in myQuotient, remainder is in myRemainder - MOVFF myQuotient, PORTC - MOVFF myQuotient, WREG +Division_Loop: + MOVFF myDenominator_low, WREG + CPFSLT PRODL ; if lower byte is smaller than denominator: need to borrow + bra Subtract + bra Borrow_or_Done +Borrow_or_Done: + MOVLW 0 + CPFSGT PRODH ; Check if done, i.e. if the upper byte is zero. + bra Division_Done + DECF PRODH, 1 ; Borrow from higher byte + MOVFF PRODH, PORTB +Subtract: + INCF myQuotient, 1 ; Increment quotient + MOVFF myQuotient, PORTD + MOVFF myDenominator_low, WREG + SUBWFB PRODL, 1 ; myNumerator -= myDenominator + MOVFF PRODL, PORTC + bra Division_Loop +Division_Done: + ;MOVFF myQuotient, PORTC + MOVFF myQuotient, WREG ; return with the quotient in the WREG RETURN - DivisionError: - ; Handle division by zero or other error - ; Your code here RETURN + diff --git a/main.s b/main.s index d072baed..e07cda46 100644 --- a/main.s +++ b/main.s @@ -11,6 +11,8 @@ counter: ds 1 ; reserve one byte for a counter variable delay_count:ds 1 ; reserve one byte for counter in the delay routine pressed:ds 1 kb_pressed: ds 1 ; check if keypad pressed +denominator_high:ds 1 +denominator_low:ds 1 HR_max: ds 1 ; the maximum heart rate calculated froma ge HR_max_20: ds 1 ; the quotient of HR_max divided by 20 LOOP_COUNTER:ds 1 ; loop counter for HRZ boundary value calculations @@ -22,14 +24,13 @@ STATUS_CHECK:ds 1 ; use this in loop to check if the end of loop as been reach psect udata_bank4 ; reserve data anywhere in RAM (here at 0x400) myArray: ds 0x80 ; reserve 128 bytes for message data -psect HRZ_data -ORG 0x1000 +psect edata ; store data in EEPROM, so can read and write +;ORG 0x1000 ; ******* myTable, data in programme memory, and its length ***** Database: DB 20, 18, 17, 15, 13, 11 - CurrentIndex EQU 0x30 align 2 - + psect code, abs rst: org 0x0 goto setup @@ -61,55 +62,53 @@ setup: bcf CFGS ; point to Flash program memory ; ******* Main programme **************************************** start: - movlw 201 ; for testing - movwf HR_max ; for testing - - ;call Read_Age_Input_Find_HR_Max ; return with W = HRmax - ;movwf HR_max - movff HR_max, WREG ; move HR_max into WREG for use with function - call Divide_By_20 ; return with HR_max/20 in WREG - movwf HR_max_20 ; save quotient of divison (integer) in variable HR_max_20 - - ; Set up the table read pointer - MOVLW high(Database) - MOVWF TBLPTRH - MOVLW low(Database) - MOVWF TBLPTRL + call Read_Age_Input_Find_HR_Max ; return with W = HRmax + movwf HR_max - ; Initialize the index - ;MOVLW 0 - ;MOVWF CurrentIndex - ;MOVFF CurrentIndex, PORTC ; Main loop to access the database -AccessLoop: - ; Calculate the address of the current record - ;MOVLW 0 - ;ADDWF CurrentIndex, W - ;MOVWF TBLPTRU - - ; Read the data from the database - TBLRD*+ - MOVF TABLAT, W ; Move the read data to WREG or other register - MOVFF TABLAT, PORTD - - ;INCF CurrentIndex, 1 - - ;MOVFF CurrentIndex, WREG - MOVFF TBLPTRL, PORTC - MOVFF TBLPTRL, WREG + ;MOVLW 3 + ;MOVWF HR_max +AccessLoop: + CLRF EEADR ; start at address 0 + BCF EECON1, 6 ; set for memory, bit 6 = CFGS + BCF EECON1, 7 ; set for data EEPROM, bit 7 = EEPGD + BCF INTCON, 7 ; disable interrupts, bit 7 = GIE + BSF EECON1, 2 ; write enable, bit 2 = WREN + +Loop: + MOVFF EEADR, PORTB + BSF EECON1, 0 ; read current address, bit 0 = RD + nop ; need to have delay after read instruction for reading to complete + MOVFF EEDATA, WREG ; W = eedata + MOVFF EEDATA, PORTC + + + MULWF HR_max + + CALL Divide_By_20 + MOVWF PORTB + MOVWF EECON2 ; move data from WREG to EECON2 waiting to be written + BSF EECON1, 1 ; to write data, bit 1 = WR + BTFSC EECON1, 1 + bra $-2 ; wait for write to complete + INCF EEADR, 1 ; Increment address and save back to EEADR + + MOVFF EEADR, WREG ; Routine to check if the end has been reached SUBLW 6 - MOVWF STATUS_CHECK ; difference between length of database and current index - MOVFF STATUS_CHECK, PORTB - + MOVWF STATUS_CHECK MOVLW 0 - CPFSEQ STATUS_CHECK ; If difference is zero, skip to end of the loop - GOTO AccessLoop - GOTO EndAccessLoop -EndAccessLoop: - GOTO $ + CPFSEQ STATUS_CHECK ; comparison to see if the end of the table has been reached + bra Loop + bra End_Write +End_Write: + ; Continue on with the rest of the code + BCF EECON1, 2 ; disenable writing function + MOVLW 0xFF + MOVWF PORTD + goto $ From c8bfbf6c55740e224df56b3280dea1a5296aae2a Mon Sep 17 00:00:00 2001 From: Alex Coleman <111077126+alexncoleman@users.noreply.github.com> Date: Mon, 4 Dec 2023 14:48:03 +0000 Subject: [PATCH 10/29] Timer0 interrupt This is the interrupt for timer 0 --- RRInterval.s | 3 +++ Timer0.s | 36 ++++++++++++++++++++++++++++++++++++ nbproject/configurations.xml | 2 ++ 3 files changed, 41 insertions(+) create mode 100644 RRInterval.s create mode 100644 Timer0.s diff --git a/RRInterval.s b/RRInterval.s new file mode 100644 index 00000000..b28b04f6 --- /dev/null +++ b/RRInterval.s @@ -0,0 +1,3 @@ + + + diff --git a/Timer0.s b/Timer0.s new file mode 100644 index 00000000..c38b8f02 --- /dev/null +++ b/Timer0.s @@ -0,0 +1,36 @@ +#include + +psect External_timer, class = CODE + +Timer_int_hi: + btfss TMROIF ;check this is a timer 0 interrupt + retfie f ;if not then return + btfss PORTA, 4 ;check if bit 4 is set (skips next instruction if set) + bra Turn_off + bra Turn_on + +Turn_off: + bcf PORTA, 4 + bcf TMR0IF + retfie f + +Turn_on: + bsf PORTA, 4 + bcf TMR0IF + retfie f + +Timer_Setup: + movlw 00100000 ;set RA5 as input and rest of Port A as output + movwf PORTA, A + movlw 11000100 ;set Timer0 to 8-bit, Fosc/4/32 + movwf T0CON, A ;approximately 0.5ms rollover + bsf TIMR0IE ;enable timer0 interrupt + bsf GIE ;enable all interrupts + goto start + return + + + + + + diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index ec4baff3..065671aa 100755 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -19,6 +19,8 @@ Keypad.s Digit_Reader.s Calculations.s + Timer0.s + RRInterval.s Date: Mon, 4 Dec 2023 16:21:08 +0000 Subject: [PATCH 11/29] HRZ Table Read/Write updated --- Calculations.s | 51 +++++++++++++++++++++++++++++++++++++++++++++++++- main.s | 50 +++---------------------------------------------- 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/Calculations.s b/Calculations.s index 75d1b9cd..dc25a2c2 100644 --- a/Calculations.s +++ b/Calculations.s @@ -1,6 +1,6 @@ #include -global Find_Max_Heart_Rate, Divide_By_20 +global Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table ; this includes subroutines for calculations: e.g. max heart rate calculation, boundary calculations psect udata_acs @@ -9,6 +9,8 @@ myNumerator:ds 1 myQuotient:ds 1 myRemainder:ds 1 myDiff:ds 1 +STATUS_CHECK:ds 1 +HR_max:ds 1 psect calculations_code,class=CODE @@ -57,3 +59,50 @@ Division_Done: DivisionError: RETURN + +Load_HRZ_Table: ; call with HR_max in WREG + MOVWF HR_max + + CLRF EEADR ; start at address 0 + BCF EECON1, 6 ; set for memory, bit 6 = CFGS + BCF EECON1, 7 ; set for data EEPROM, bit 7 = EEPGD + BSF EECON1, 2 ; write enable, bit 2 = WREN + +Loop: + MOVFF EEADR, PORTB + BSF EECON1, 0 ; read current address, bit 0 = RD + nop ; need to have delay after read instruction for reading to complete + MOVFF EEDATA, WREG ; W = multiplier + MOVFF EEDATA, PORTC + MULWF HR_max + + CALL Divide_By_20 ; (HR_max*multiplier)/20, return with quotient in WREG + + MOVWF EEDATA ; move data to EE + + BCF INTCON, 7 ; disable interrupts, bit 7 = GIE + + MOVLW 0x55 + MOVWF EECON2 + MOVLW 0xAA + MOVWF EECON2 + + BSF EECON1, 1 ; to write data, bit 1 = WR + BTFSC EECON1, 1 + bra $-2 ; wait for write to complete + INCF EEADR, 1 ; Increment address and save back to EEADR + + MOVFF EEADR, WREG ; Routine to check if the end has been reached + SUBLW 6 + MOVWF STATUS_CHECK + MOVLW 0 + CPFSEQ STATUS_CHECK ; comparison to see if the end of the table has been reached + bra Loop + bra End_Write +End_Write: + ; Continue on with the rest of the code + BCF EECON1, 2 ; disenable writing function + MOVLW 0xFF + MOVWF PORTD + RETURN + diff --git a/main.s b/main.s index e07cda46..de49dde9 100644 --- a/main.s +++ b/main.s @@ -4,7 +4,7 @@ extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D extrn Keypad_INIT, Keypad_READ, delay_ms extrn Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max -extrn Divide_By_20 +extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table psect udata_acs ; reserve data space in access ram counter: ds 1 ; reserve one byte for a counter variable @@ -66,52 +66,8 @@ start: call Read_Age_Input_Find_HR_Max ; return with W = HRmax movwf HR_max - - ; Main loop to access the database - ;MOVLW 3 - ;MOVWF HR_max - -AccessLoop: - CLRF EEADR ; start at address 0 - BCF EECON1, 6 ; set for memory, bit 6 = CFGS - BCF EECON1, 7 ; set for data EEPROM, bit 7 = EEPGD - BCF INTCON, 7 ; disable interrupts, bit 7 = GIE - BSF EECON1, 2 ; write enable, bit 2 = WREN - -Loop: - MOVFF EEADR, PORTB - BSF EECON1, 0 ; read current address, bit 0 = RD - nop ; need to have delay after read instruction for reading to complete - MOVFF EEDATA, WREG ; W = eedata - MOVFF EEDATA, PORTC - - - MULWF HR_max - - CALL Divide_By_20 - MOVWF PORTB - MOVWF EECON2 ; move data from WREG to EECON2 waiting to be written - BSF EECON1, 1 ; to write data, bit 1 = WR - BTFSC EECON1, 1 - bra $-2 ; wait for write to complete - INCF EEADR, 1 ; Increment address and save back to EEADR - - MOVFF EEADR, WREG ; Routine to check if the end has been reached - SUBLW 6 - MOVWF STATUS_CHECK - MOVLW 0 - CPFSEQ STATUS_CHECK ; comparison to see if the end of the table has been reached - bra Loop - bra End_Write -End_Write: - ; Continue on with the rest of the code - BCF EECON1, 2 ; disenable writing function - MOVLW 0xFF - MOVWF PORTD - goto $ - - - + movlw 200 ; FICTITOUS HR MAX FOR TESTING + call Load_HRZ_Table goto $ From 2197c1abfa55dcd9971411f38f54831db1c630c4 Mon Sep 17 00:00:00 2001 From: Alex Coleman <111077126+alexncoleman@users.noreply.github.com> Date: Mon, 4 Dec 2023 16:48:20 +0000 Subject: [PATCH 12/29] Update RRInterval.s Created new file for working out period --- RRInterval.s | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/RRInterval.s b/RRInterval.s index b28b04f6..6d1eff0b 100644 --- a/RRInterval.s +++ b/RRInterval.s @@ -1,3 +1,14 @@ +#include - +psect External_timer, class = CODE + + + +RR_Setup: + bsf CCP1CON, 0 + bsf CCP1CON, 2 ; sets up ECCP1 as capture on every rising edge + movlw 0x00 + movwf CCPTMRS0 ;sets ECCP1 to use timer1 for capture + movlw 10110011 ;enables Timer1 to synchronise with external clock at RA5 and perform read/write in 1 16bit operation + movwf T1CON \ No newline at end of file From 168d8a8e15edebb05af5b450f4582856e5068bfd Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Mon, 4 Dec 2023 16:49:49 +0000 Subject: [PATCH 13/29] Cleaned some unnecessary variables --- Digit_Reader.s | 4 ---- main.s | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Digit_Reader.s b/Digit_Reader.s index ee5f36c3..c535d59a 100644 --- a/Digit_Reader.s +++ b/Digit_Reader.s @@ -6,10 +6,6 @@ global Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max extrn Keypad_READ extrn delay_ms extrn Find_Max_Heart_Rate - -;psect data_section, global, class = DABS -;first_digit: ds 1 -;second_digit: ds 1 psect udata_acs ; reserve data space in access ram first_digit: ds 1 diff --git a/main.s b/main.s index de49dde9..0da0cc18 100644 --- a/main.s +++ b/main.s @@ -63,8 +63,8 @@ setup: bcf CFGS ; point to Flash program memory start: - call Read_Age_Input_Find_HR_Max ; return with W = HRmax - movwf HR_max + ;call Read_Age_Input_Find_HR_Max ; return with W = HRmax + ;movwf HR_max movlw 200 ; FICTITOUS HR MAX FOR TESTING call Load_HRZ_Table From 33c088b8b3fa8a429c93828404a181f9575d3d5c Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Mon, 4 Dec 2023 21:28:53 +0000 Subject: [PATCH 14/29] Example Routine for Timer added --- Timer0.s | 4 +-- Timer_Example_Code.s | 65 ++++++++++++++++++++++++++++++++++++ ctmu.s | 59 ++++++++++++++++++++++++++++++++ nbproject/configurations.xml | 2 ++ 4 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 Timer_Example_Code.s create mode 100644 ctmu.s diff --git a/Timer0.s b/Timer0.s index c38b8f02..891ea221 100644 --- a/Timer0.s +++ b/Timer0.s @@ -3,8 +3,8 @@ psect External_timer, class = CODE Timer_int_hi: - btfss TMROIF ;check this is a timer 0 interrupt - retfie f ;if not then return + btfss TMROIF ;check this is a timer 0 interrupt + retfie f ;if not then return btfss PORTA, 4 ;check if bit 4 is set (skips next instruction if set) bra Turn_off bra Turn_on diff --git a/Timer_Example_Code.s b/Timer_Example_Code.s new file mode 100644 index 00000000..4254b03a --- /dev/null +++ b/Timer_Example_Code.s @@ -0,0 +1,65 @@ +; Define your oscillator frequency +#define _XTAL_FREQ 4000000 ; Replace with your actual oscillator frequency + +; Variable declarations +PREVIOUS_CAPTURE equ 0x20 ; Store the previous capture value + +; Reset vector +ORG 0x00 +GOTO Main + +; High-Priority Interrupt Vectors +ORG 0x08 +GOTO Timer1_ISR + +; Main program +Main: + ; Initialize + BSF STATUS, RP0 ; Bank 1 + CLRF T1CON ; Clear Timer1 control register + CLRF TMR1H ; Clear Timer1 high register + CLRF TMR1L ; Clear Timer1 low register + CLRF PREVIOUS_CAPTURE ; Clear previous capture value + BCF STATUS, RP0 ; Bank 0 + + ; Configure Timer1 for capture mode + BSF CCP1CON, CCP1M0 ; Set capture mode on rising edge, bit 0 = CCP1M0 + BSF CCP1CON, CCP1M1 ; Set capture mode on falling edge, bit 1 = CCP1M1 + BSF PIE3, 1 ; Enable CCP1 interrupt, bit 1 = CCP1IE + BSF PIR1, 1 ; Clear CCP1 interrupt flag, bit 1 = CCP1IF + + ; Configure interrupts + BSF INTCON, 7 ; Enable global interrupts, bit 7 = GIE + BSF INTCON, 6 ; Enable peripheral interrupts, bit 6 = PEIE + + ; Configure T1CKI pin as input (replace with the actual pin configuration) + BCF TRISC, 0 ; Make T1CKI an input + + ; Configure Timer1 prescaler (adjust as needed) + BSF T1CON, T1CKPS0 ; Set prescaler to 1:1, bit 5-4 = T1CKPS (customise for specific prescale value) + + ; Enable Timer1 + BSF T1CON, TMR1ON ; bit 0 = TMR1ON, set as 1 to enable Timer 1 + + ; Main loop +MainLoop: + ; Your main code goes here + + GOTO MainLoop + +; Timer1 CCP1 interrupt service routine +Timer1_ISR: + ; Read the captured time + MOVF CCPR1H, W + MOVWF PREVIOUS_CAPTURE + 1 + MOVF CCPR1L, W + MOVWF PREVIOUS_CAPTURE + + ; Your ISR code goes here + + ; Clear CCP1 interrupt flag + BCF PIR1, CCP1IF + + RETFIE + + diff --git a/ctmu.s b/ctmu.s new file mode 100644 index 00000000..d72026fe --- /dev/null +++ b/ctmu.s @@ -0,0 +1,59 @@ +; Define your oscillator frequency +#define _XTAL_FREQ 4000000 ; Replace with your actual oscillator frequency + +; Variable declarations +CAPTURE_TIME equ 0x20 ; Store the captured time value + +; Reset vector +ORG 0x00 +GOTO Main + +; High-Priority Interrupt Vectors +ORG 0x08 +GOTO CTMU_ISR + +; Main program +Main: + ; Initialize + BSF STATUS, RP0 ; Bank 1 + CLRF CAPTURE_TIME ; Clear captured time value + BCF STATUS, RP0 ; Bank 0 + + ; Configure CTMU + BSF ANSEL, ANS0 ; Enable the analog input (replace with the actual pin) + BSF TRISB, TRISB0 ; Set the pin as input, connect sensor signal to this + + BSF CTMUCONH, CTTRIG ; Enable the CTMU trigger, bit 0 = CTTRIG + BSF CTMUCONL, EDG1STAT ; Edge1 enabled, bit 0 = EDG1STAT + + ; Configure Timer1 for reference time + BSF T1CON, T1CKPS0 ; Set prescaler to 1:1, bit 5-4 = T1CKPS + BSF T1CON, TMR1ON ; Enable Timer1, bit 0 = TMR1ON + + ; Main loop +MainLoop: + ; Start a new measurement + BSF CTMUCONL, CTGO ; find corresponding status bit + + ; Your main code goes here + + ; Wait for measurement to complete + BTFSC CTMUCONL, CTGO ; Wait for the CTGO bit to clear + GOTO $-1 + + ; Your code to process the measured time goes here + + GOTO MainLoop + +; CTMU interrupt service routine +CTMU_ISR: + ; Read the captured time + MOVF CTMUCONH, W + MOVWF CAPTURE_TIME + 1 + MOVF CTMUCONL, W + MOVWF CAPTURE_TIME + + ; Clear CTMU interrupt flag + BCF PIR2, CTIF + + RETFIE \ No newline at end of file diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 065671aa..6cdcb6a0 100755 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -21,6 +21,8 @@ Calculations.s Timer0.s RRInterval.s + Timer_Example_Code.s + ctmu.s Date: Mon, 4 Dec 2023 21:33:09 +0000 Subject: [PATCH 15/29] Update main.s --- main.s | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main.s b/main.s index 0da0cc18..ea96d699 100644 --- a/main.s +++ b/main.s @@ -35,6 +35,9 @@ psect code, abs rst: org 0x0 goto setup +timer_interrupt_low: org 0x0008 + goto Timer + ; ******* Programme FLASH read Setup Code *********************** setup: bcf CFGS ; point to Flash program memory bsf EEPGD ; access Flash program memory From f9c80f4e9d9cc8675db247b87d2071fe34243136 Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:24:04 +0000 Subject: [PATCH 16/29] HRZ Table Compare Code added, deleted unnecessary files --- .DS_Store | Bin 0 -> 6148 bytes Calculations.s | 29 ++++++++++++- Digit_Reader.s | 78 +++++++++++++++++++++++++++-------- LCD.s | 38 +++++++++++++++-- Timer0.s | 9 ++-- Timer_Example_Code.s | 65 ----------------------------- ctmu.s | 59 -------------------------- main.s | 30 +++++++++----- nbproject/configurations.xml | 2 - 9 files changed, 147 insertions(+), 163 deletions(-) create mode 100644 .DS_Store delete mode 100644 Timer_Example_Code.s delete mode 100644 ctmu.s diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..400a800ade98b290fd1d952d873e522c718c9d1e GIT binary patch literal 6148 zcmeHKJxc^J5S`Hz7HqDxun1^rbA^38Rz%zT1F|l7!XA6g_38ax{v~VQd?-d2>_m?l zNZw>VlFfrnGDO77UB4ij6H$XE$f8V$m?vEa9y|lG&e0E#i`B!p*-lLJH%;>GN7T`d zo@k)@`_C>eYwu=k+in;;Sew(^o7cPNm#eQ4{SOh_^(ThT{|`~vXGky*3*C{ay27-Y- zV}NJvs$F7Jez$(xp4_zw?H)};;)*B`=+z?t135=d)M@@CI^wcpF_c-vuIa#d2q+=Z J1p~jpz#A7rDsKP) literal 0 HcmV?d00001 diff --git a/Calculations.s b/Calculations.s index dc25a2c2..c0ff2cd2 100644 --- a/Calculations.s +++ b/Calculations.s @@ -1,6 +1,6 @@ #include -global Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table +global Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ ; this includes subroutines for calculations: e.g. max heart rate calculation, boundary calculations psect udata_acs @@ -11,6 +11,8 @@ myRemainder:ds 1 myDiff:ds 1 STATUS_CHECK:ds 1 HR_max:ds 1 +Zone_Value:ds 1 +HR_Measured:ds 1 ; reserve one byte for measured HR value from sensor psect calculations_code,class=CODE @@ -105,4 +107,27 @@ End_Write: MOVLW 0xFF MOVWF PORTD RETURN - + +Determine_HRZ: ; enter with measured HR stored in WREG + movwf HR_Measured + + MOVLW 6 + MOVWF Zone_Value ; initialise at 6, highest possible zone value is 5 + + CLRF EEADR ; start at address 0 + BCF EECON1, 6 ; set for memory, bit 6 = CFGS + BCF EECON1, 7 ; set for data EEPROM, bit 7 = EEPGD + BCF EECON1, 2 ; write enable, bit 2 = WREN +Table_Compare_Loop: + MOVFF EEADR, PORTB + BSF EECON1, 0 ; read current address, bit 0 = RD + nop ; need to have delay after read instruction for reading to complete + MOVFF EEDATA, WREG ; zone boundary + CPFSLT HR_Measured ; f < W + bra Output_Zone_Value + DECF Zone_Value, 1 + INCF EEADR, 1 + bra Table_Compare_Loop +Output_Zone_Value: + MOVFF Zone_Value, WREG + return diff --git a/Digit_Reader.s b/Digit_Reader.s index c535d59a..f4580c61 100644 --- a/Digit_Reader.s +++ b/Digit_Reader.s @@ -6,6 +6,7 @@ global Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max extrn Keypad_READ extrn delay_ms extrn Find_Max_Heart_Rate +extrn LCD_Write_Message psect udata_acs ; reserve data space in access ram first_digit: ds 1 @@ -34,6 +35,7 @@ Age_Read_1: cpfslt age_first ; if no valid input, branch to Age_Read_1 to read from Keypad again; bra Age_Read_1 decf digit_input_counter,1 ; if there has been a valid input, decrement the digit counter and return + call LCD_Write_Message ; digit stored in POSTINC0 return @@ -52,7 +54,9 @@ Age_Read_2: cpfslt age_second ; if no valid input, branch to Age_Read_1 to read from Keypad again; bra Age_Read_2 decf digit_input_counter, 1 ; if there has been a valid input, decrement the digit counter and return + call LCD_Write_Message ; digit stored in POSTINC0 movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted + return Read_Age_Input_Find_HR_Max: @@ -108,51 +112,71 @@ Test_0_1: movlw 0xBE cpfseq first_digit, A bra Test_1_1 + movlw '0' + movwf POSTINC0 retlw 0 Test_1_1: movlw 0x77 cpfseq first_digit, A - bra Test_2_1 + bra Test_2_1 + movlw '1' + movwf POSTINC0 retlw 10 Test_2_1: movlw 0xB7 cpfseq first_digit, A - bra Test_3_1 + bra Test_3_1 + movlw '2' + movwf POSTINC0 retlw 20 Test_3_1: movlw 0xD7 cpfseq first_digit, A - bra Test_4_1 + bra Test_4_1 + movlw '3' + movwf POSTINC0 retlw 30 Test_4_1: movlw 0x7B cpfseq first_digit, A - bra Test_5_1 + bra Test_5_1 + movlw '4' + movwf POSTINC0 retlw 40 Test_5_1: movlw 0xBB cpfseq first_digit, A - bra Test_6_1 + bra Test_6_1 + movlw '5' + movwf POSTINC0 retlw 50 Test_6_1: movlw 0xDB cpfseq first_digit, A - bra Test_7_1 + bra Test_7_1 + movlw '6' + movwf POSTINC0 retlw 60 Test_7_1: movlw 0x7D cpfseq first_digit, A - bra Test_8_1 + bra Test_8_1 + movlw '7' + movwf POSTINC0 retlw 70 Test_8_1: movlw 0xBD cpfseq first_digit, A - bra Test_9_1 + bra Test_9_1 + movlw '8' + movwf POSTINC0 retlw 80 Test_9_1: movlw 0xDD cpfseq first_digit, A retlw 0xFF ; error message: when a letter or an invalid input has been detected + movlw '9' + movwf POSTINC0 retlw 90 @@ -166,52 +190,72 @@ Test_none_2: ; no key pressed Test_0_2: movlw 0xBE cpfseq second_digit, A - bra Test_1_2 + bra Test_1_2 + movlw '0' + movwf POSTINC0 retlw 0 Test_1_2: movlw 0x77 cpfseq second_digit, A - bra Test_2_2 + bra Test_2_2 + movlw '1' + movwf POSTINC0 retlw 1 Test_2_2: movlw 0xB7 cpfseq second_digit, A - bra Test_3_2 + bra Test_3_2 + movlw '2' + movwf POSTINC0 retlw 2 Test_3_2: movlw 0xD7 cpfseq second_digit, A - bra Test_4_2 + bra Test_4_2 + movlw '3' + movwf POSTINC0 retlw 3 Test_4_2: movlw 0x7B cpfseq second_digit, A - bra Test_5_2 + bra Test_5_2 + movlw '4' + movwf POSTINC0 retlw 4 Test_5_2: movlw 0xBB cpfseq second_digit, A - bra Test_6_2 + bra Test_6_2 + movlw '5' + movwf POSTINC0 retlw 5 Test_6_2: movlw 0xDB cpfseq second_digit, A - bra Test_7_2 + bra Test_7_2 + movlw '6' + movwf POSTINC0 retlw 6 Test_7_2: movlw 0x7D cpfseq second_digit, A - bra Test_8_2 + bra Test_8_2 + movlw '7' + movwf POSTINC0 retlw 7 Test_8_2: movlw 0xBD cpfseq second_digit, A - bra Test_9_2 + bra Test_9_2 + movlw '8' + movwf POSTINC0 retlw 8 Test_9_2: movlw 0xDD cpfseq second_digit, A retlw 0xFF ; error message: when a letter or an invalid input has been detected + movlw '9' + movwf POSTINC0 retlw 9 diff --git a/LCD.s b/LCD.s index f763ea28..3f278f0a 100644 --- a/LCD.s +++ b/LCD.s @@ -1,6 +1,6 @@ #include -global LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D +global LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D, Write_Welcome, SetTwoLines psect udata_acs ; named variables in access ram LCD_cnt_l: ds 1 ; reserve 1 byte for variable LCD_cnt_l @@ -9,10 +9,20 @@ LCD_cnt_ms: ds 1 ; reserve 1 byte for ms counter LCD_tmp: ds 1 ; reserve 1 byte for temporary use LCD_counter: ds 1 ; reserve 1 byte for counting through nessage TwoLineCounter: ds 1 +counter:ds 1 +myArray:ds 1 LCD_E EQU 5 ; LCD enable bit LCD_RS EQU 4 ; LCD register select bit +psect data + ; ******* Input Message, data in programme memory, and its length ***** +InputMessage: + db 'P','l','e','a','s','e',' ','I','n','p','u','t',' ','A','g','e',0x0a + ; message, plus carriage return + myTable_l EQU 17 ; length of data + align 2 + psect lcd_code,class=CODE LCD_Setup: @@ -50,14 +60,14 @@ LCD_Setup: LCD_Write_Message: ; Message stored at FSR2, length stored in W movwf LCD_counter, A LCD_Loop_message: - movf POSTINC2, W, A + movf POSTINC0, W, A call LCD_Send_Byte_D decfsz LCD_counter, A bra LCD_Loop_message movlw 2000 call LCD_delay_ms - dcfsnz TwoLineCounter, A - bra SetTwoLines + ;dcfsnz TwoLineCounter, A + ;bra SetTwoLines return LCD_Send_Byte_I: ; Transmits byte stored in W to instruction reg @@ -90,6 +100,26 @@ LCD_Send_Byte_D: ; Transmits byte stored in W to data reg call LCD_delay_x4us return +Write_Welcome: + lfsr 0, myArray ; Load FSR0 with address in RAM + movlw low highword(InputMessage) ; address of data in PM + movwf TBLPTRU, A ; load upper bits to TBLPTRU + movlw high(InputMessage) ; address of data in PM + movwf TBLPTRH, A ; load high byte to TBLPTRH + movlw low(InputMessage) ; address of data in PM + movwf TBLPTRL, A ; load low byte to TBLPTRL + movlw myTable_l ; bytes to read + movwf counter, A ; our counter register +loop: tblrd*+ ; one byte from PM to TABLAT, increment TBLPRT + movff TABLAT, POSTINC0; move data from TABLAT to (FSR0), inc FSR0 + decfsz counter, A ; count down to zero + bra loop ; keep going until finished + + movlw myTable_l ; output message to LCD + addlw 0xff ; don't send the final carriage return to LCD + lfsr 2, myArray + call LCD_Write_Message + SetTwoLines: diff --git a/Timer0.s b/Timer0.s index 891ea221..62b17af4 100644 --- a/Timer0.s +++ b/Timer0.s @@ -1,9 +1,11 @@ #include - + +global Timer_Setup, Timer_int_hi + psect External_timer, class = CODE Timer_int_hi: - btfss TMROIF ;check this is a timer 0 interrupt + btfss INTCON, 2 ;check this is a timer 0 interrupt, bit 2 = TMR0IF retfie f ;if not then return btfss PORTA, 4 ;check if bit 4 is set (skips next instruction if set) bra Turn_off @@ -24,9 +26,8 @@ Timer_Setup: movwf PORTA, A movlw 11000100 ;set Timer0 to 8-bit, Fosc/4/32 movwf T0CON, A ;approximately 0.5ms rollover - bsf TIMR0IE ;enable timer0 interrupt + bsf INTCON, 5 ;enable timer0 interrupt, bit 5 = TMR0IE bsf GIE ;enable all interrupts - goto start return diff --git a/Timer_Example_Code.s b/Timer_Example_Code.s deleted file mode 100644 index 4254b03a..00000000 --- a/Timer_Example_Code.s +++ /dev/null @@ -1,65 +0,0 @@ -; Define your oscillator frequency -#define _XTAL_FREQ 4000000 ; Replace with your actual oscillator frequency - -; Variable declarations -PREVIOUS_CAPTURE equ 0x20 ; Store the previous capture value - -; Reset vector -ORG 0x00 -GOTO Main - -; High-Priority Interrupt Vectors -ORG 0x08 -GOTO Timer1_ISR - -; Main program -Main: - ; Initialize - BSF STATUS, RP0 ; Bank 1 - CLRF T1CON ; Clear Timer1 control register - CLRF TMR1H ; Clear Timer1 high register - CLRF TMR1L ; Clear Timer1 low register - CLRF PREVIOUS_CAPTURE ; Clear previous capture value - BCF STATUS, RP0 ; Bank 0 - - ; Configure Timer1 for capture mode - BSF CCP1CON, CCP1M0 ; Set capture mode on rising edge, bit 0 = CCP1M0 - BSF CCP1CON, CCP1M1 ; Set capture mode on falling edge, bit 1 = CCP1M1 - BSF PIE3, 1 ; Enable CCP1 interrupt, bit 1 = CCP1IE - BSF PIR1, 1 ; Clear CCP1 interrupt flag, bit 1 = CCP1IF - - ; Configure interrupts - BSF INTCON, 7 ; Enable global interrupts, bit 7 = GIE - BSF INTCON, 6 ; Enable peripheral interrupts, bit 6 = PEIE - - ; Configure T1CKI pin as input (replace with the actual pin configuration) - BCF TRISC, 0 ; Make T1CKI an input - - ; Configure Timer1 prescaler (adjust as needed) - BSF T1CON, T1CKPS0 ; Set prescaler to 1:1, bit 5-4 = T1CKPS (customise for specific prescale value) - - ; Enable Timer1 - BSF T1CON, TMR1ON ; bit 0 = TMR1ON, set as 1 to enable Timer 1 - - ; Main loop -MainLoop: - ; Your main code goes here - - GOTO MainLoop - -; Timer1 CCP1 interrupt service routine -Timer1_ISR: - ; Read the captured time - MOVF CCPR1H, W - MOVWF PREVIOUS_CAPTURE + 1 - MOVF CCPR1L, W - MOVWF PREVIOUS_CAPTURE - - ; Your ISR code goes here - - ; Clear CCP1 interrupt flag - BCF PIR1, CCP1IF - - RETFIE - - diff --git a/ctmu.s b/ctmu.s deleted file mode 100644 index d72026fe..00000000 --- a/ctmu.s +++ /dev/null @@ -1,59 +0,0 @@ -; Define your oscillator frequency -#define _XTAL_FREQ 4000000 ; Replace with your actual oscillator frequency - -; Variable declarations -CAPTURE_TIME equ 0x20 ; Store the captured time value - -; Reset vector -ORG 0x00 -GOTO Main - -; High-Priority Interrupt Vectors -ORG 0x08 -GOTO CTMU_ISR - -; Main program -Main: - ; Initialize - BSF STATUS, RP0 ; Bank 1 - CLRF CAPTURE_TIME ; Clear captured time value - BCF STATUS, RP0 ; Bank 0 - - ; Configure CTMU - BSF ANSEL, ANS0 ; Enable the analog input (replace with the actual pin) - BSF TRISB, TRISB0 ; Set the pin as input, connect sensor signal to this - - BSF CTMUCONH, CTTRIG ; Enable the CTMU trigger, bit 0 = CTTRIG - BSF CTMUCONL, EDG1STAT ; Edge1 enabled, bit 0 = EDG1STAT - - ; Configure Timer1 for reference time - BSF T1CON, T1CKPS0 ; Set prescaler to 1:1, bit 5-4 = T1CKPS - BSF T1CON, TMR1ON ; Enable Timer1, bit 0 = TMR1ON - - ; Main loop -MainLoop: - ; Start a new measurement - BSF CTMUCONL, CTGO ; find corresponding status bit - - ; Your main code goes here - - ; Wait for measurement to complete - BTFSC CTMUCONL, CTGO ; Wait for the CTGO bit to clear - GOTO $-1 - - ; Your code to process the measured time goes here - - GOTO MainLoop - -; CTMU interrupt service routine -CTMU_ISR: - ; Read the captured time - MOVF CTMUCONH, W - MOVWF CAPTURE_TIME + 1 - MOVF CTMUCONL, W - MOVWF CAPTURE_TIME - - ; Clear CTMU interrupt flag - BCF PIR2, CTIF - - RETFIE \ No newline at end of file diff --git a/main.s b/main.s index ea96d699..bc358efa 100644 --- a/main.s +++ b/main.s @@ -1,18 +1,17 @@ #include ;extrn UART_Setup, UART_Transmit_Message ; external subroutines -extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D +extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D, Write_Welcome, SetTwoLines extrn Keypad_INIT, Keypad_READ, delay_ms extrn Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max -extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table +extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ +extrn Timer_Setup, Timer_int_hi psect udata_acs ; reserve data space in access ram counter: ds 1 ; reserve one byte for a counter variable delay_count:ds 1 ; reserve one byte for counter in the delay routine -pressed:ds 1 -kb_pressed: ds 1 ; check if keypad pressed -denominator_high:ds 1 -denominator_low:ds 1 +Measured_Zone:ds 1 +HR_Measured:ds 1 ; reserve one byte for measured HR value from sensor HR_max: ds 1 ; the maximum heart rate calculated froma ge HR_max_20: ds 1 ; the quotient of HR_max divided by 20 LOOP_COUNTER:ds 1 ; loop counter for HRZ boundary value calculations @@ -30,13 +29,13 @@ psect edata ; store data in EEPROM, so can read and write Database: DB 20, 18, 17, 15, 13, 11 align 2 - + psect code, abs rst: org 0x0 goto setup timer_interrupt_low: org 0x0008 - goto Timer + goto Timer_int_hi ; ******* Programme FLASH read Setup Code *********************** setup: bcf CFGS ; point to Flash program memory @@ -65,13 +64,24 @@ setup: bcf CFGS ; point to Flash program memory ; ******* Main programme **************************************** start: - + ;call Write_Welcome + ;bra SetTwoLines ;call Read_Age_Input_Find_HR_Max ; return with W = HRmax ;movwf HR_max - movlw 200 ; FICTITOUS HR MAX FOR TESTING + movlw 10 ; FICTITOUS HR MAX FOR TESTING call Load_HRZ_Table + ; heart rate measurement here + movlw 7 ; FICTITOUS HR VALUE FOR TESTING + + call Determine_HRZ ; Zone value stored in WREG + MOVWF Measured_Zone + + + + ; sift through HRZ_Table and find the relevant heart rate zone + goto $ end rst diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 6cdcb6a0..065671aa 100755 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -21,8 +21,6 @@ Calculations.s Timer0.s RRInterval.s - Timer_Example_Code.s - ctmu.s Date: Tue, 5 Dec 2023 15:56:04 +0000 Subject: [PATCH 17/29] Subtraction and Addition Subroutines in RRInterval.s added and checked --- RRInterval.s | 109 +++++++++++++++++++++++++++++++++++++++++++++++---- Timer0.s | 29 ++++++-------- main.s | 19 ++++----- 3 files changed, 123 insertions(+), 34 deletions(-) diff --git a/RRInterval.s b/RRInterval.s index 6d1eff0b..7c2f9a82 100644 --- a/RRInterval.s +++ b/RRInterval.s @@ -1,14 +1,109 @@ #include - +global no_overflow, overflow + +psect udata_acs + +prevtimeH: ds 1 +prevtimeL: ds 1 +maxH:ds 1 +maxL:ds 1 +periodH: ds 1 +periodL: ds 1 +HR: ds 1 +Numerator: ds 1 ;for working out bpm 60/RR interval + psect External_timer, class = CODE - - RR_Setup: - bsf CCP1CON, 0 - bsf CCP1CON, 2 ; sets up ECCP1 as capture on every rising edge + movlw 60 + movwf Numerator ;for working out bpm 60/RR interval + bsf CCP5CON, 1 + bsf CCP5CON, 2 ; sets up CCP5 as capture on every rising edge (00000110) movlw 0x00 - movwf CCPTMRS0 ;sets ECCP1 to use timer1 for capture + movwf CCPTMRS1 ;sets CCP5 to use timer1 for capture movlw 10110011 ;enables Timer1 to synchronise with external clock at RA5 and perform read/write in 1 16bit operation - movwf T1CON \ No newline at end of file + movwf T1CON + bsf PIE4, 2 ;enables CCP5 interrupt + bsf PIE1, 0 ;enables timer1 overflow interrupt + return + +RR_int: + btfss PIR4, 2 ;Checks to see if CCP5 interrupt flag + retfie f + btfss PIR1, 0 ;Checks to see if timer1 overflowed + bra no_overflow + bra overflow + +no_overflow: + ;subtract values stored in prevtimeH and prevtimeL from CCPR5H and CCPR5L store result in period + ;period returned in units of 1.024 ms + ;Do subtraction + MOVFF prevtimeL, WREG + CPFSLT CCPR5L + bra Subtract_no + bra Borrow_no +Borrow_no: + DECF CCPR5H, 1 +Subtract_no: + MOVFF prevtimeL, WREG + SUBWF CCPR5L, 0 ; subtract prevtimeL from CCPR5L, store result in WREG + MOVWF periodL ; move value into periodL + MOVFF prevtimeH, WREG + SUBWF CCPR5H, 0 ; subtract prevtimeH from CCPR5H, store result in WREG + MOVWF periodH + ;store value in periodH and periodL + + + movff CCPR5H, WREG ;update previous time + movwf prevtimeH + movff CCPR5L, WREG + movwf prevtimeL + bcf PIR4, 2 ;clear CCP interrupt flag + retfie f + +overflow: + ;subtract prevtimeH and prevtimeL from 11111111B as this will be max value + ;add this result to values stored in CCPR5H and CCPR5L to calculate period + ;period returned in units of 1.024 ms (as this is the period of external clock) + ;Do subtraction + MOVLW 0xFF + MOVWF maxL + MOVWF maxH + + CPFSEQ prevtimeL ; prevtimeL = 0xFF, need to borrow + bra Subtract_o + bra Borrow_o +Borrow_o: + DECF maxH, 1 +Subtract_o: + MOVFF prevtimeL, WREG + SUBWF maxL, 0 ; subtract prevtimeL from CCPR5L, store result in WREG + MOVWF periodL ; move value into periodL + MOVFF prevtimeH, WREG + SUBWF maxH, 0 ; subtract prevtimeH from CCPR5H, store result in WREG + MOVWF periodH + + ;Addition periodL/H + CCPR5L/H +Addition: + + MOVFF CCPR5L, WREG + ADDWF periodL, 1 ; place value back into periodL + MOVFF periodL, WREG + + MOVFF CCPR5H, WREG + ADDWFC periodH, 1 + MOVFF periodH, WREG + + ;store final value in periodH and periodL + + movff CCPR5H, WREG ;update previous time + movwf prevtimeH + movff CCPR5L, WREG + movwf prevtimeL + bcf PIR4, 2 ;clear CCP interrupt flag + bcf PIR1, 2 + retfie f + +convert: + ;Need to multiply period by 1.024ms to determine \ No newline at end of file diff --git a/Timer0.s b/Timer0.s index 62b17af4..68284e39 100644 --- a/Timer0.s +++ b/Timer0.s @@ -1,37 +1,30 @@ #include -global Timer_Setup, Timer_int_hi - +global Timer_Setup, Timer_int_hi psect External_timer, class = CODE Timer_int_hi: - btfss INTCON, 2 ;check this is a timer 0 interrupt, bit 2 = TMR0IF + btfss INTCON, 2 ;check this is a timer 0 interrupt, bit 5 = TMR0IF retfie f ;if not then return btfss PORTA, 4 ;check if bit 4 is set (skips next instruction if set) - bra Turn_off bra Turn_on + bra Turn_off Turn_off: bcf PORTA, 4 - bcf TMR0IF + bcf INTCON, 2 retfie f Turn_on: bsf PORTA, 4 - bcf TMR0IF + bcf INTCON, 2 retfie f Timer_Setup: - movlw 00100000 ;set RA5 as input and rest of Port A as output - movwf PORTA, A - movlw 11000100 ;set Timer0 to 8-bit, Fosc/4/32 + movlw 00100000B ;set RA5 as input and rest of Port A as output + movwf TRISA, A + movlw 11000100B ;set Timer0 to 8-bit, Fosc/4/32 movwf T0CON, A ;approximately 0.5ms rollover - bsf INTCON, 5 ;enable timer0 interrupt, bit 5 = TMR0IE - bsf GIE ;enable all interrupts - return - - - - - - + bsf INTCON, 5 ;enable timer0 interrupt, bit 5 = TIME0IE + bsf INTCON, 7 ;enable all interrupts 7=GIE + return \ No newline at end of file diff --git a/main.s b/main.s index bc358efa..87c3bf78 100644 --- a/main.s +++ b/main.s @@ -1,11 +1,12 @@ #include ;extrn UART_Setup, UART_Transmit_Message ; external subroutines -extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D, Write_Welcome, SetTwoLines +extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D extrn Keypad_INIT, Keypad_READ, delay_ms extrn Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max -extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ -extrn Timer_Setup, Timer_int_hi +extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table +extrn Timer_Setup, Timer_int_hi +extrn no_overflow, overflow psect udata_acs ; reserve data space in access ram counter: ds 1 ; reserve one byte for a counter variable @@ -69,16 +70,16 @@ start: ;call Read_Age_Input_Find_HR_Max ; return with W = HRmax ;movwf HR_max - movlw 10 ; FICTITOUS HR MAX FOR TESTING - call Load_HRZ_Table + ;movlw 10 ; FICTITOUS HR MAX FOR TESTING + ;call Load_HRZ_Table ; heart rate measurement here - movlw 7 ; FICTITOUS HR VALUE FOR TESTING + ;movlw 7 ; FICTITOUS HR VALUE FOR TESTING - call Determine_HRZ ; Zone value stored in WREG - MOVWF Measured_Zone + ;call Determine_HRZ ; Zone value stored in WREG + ;MOVWF Measured_Zone - + call overflow ; sift through HRZ_Table and find the relevant heart rate zone From 5184c1325dd1165602c9376f4d50489d070166ad Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Tue, 5 Dec 2023 16:01:48 +0000 Subject: [PATCH 18/29] HRZ Search Subroutine integrated into main.s --- main.s | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/main.s b/main.s index 87c3bf78..85b56701 100644 --- a/main.s +++ b/main.s @@ -4,7 +4,7 @@ extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D extrn Keypad_INIT, Keypad_READ, delay_ms extrn Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max -extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table +extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ extrn Timer_Setup, Timer_int_hi extrn no_overflow, overflow @@ -70,18 +70,21 @@ start: ;call Read_Age_Input_Find_HR_Max ; return with W = HRmax ;movwf HR_max - ;movlw 10 ; FICTITOUS HR MAX FOR TESTING - ;call Load_HRZ_Table - - ; heart rate measurement here - ;movlw 7 ; FICTITOUS HR VALUE FOR TESTING + movlw 10 ; FICTITOUS HR MAX FOR TESTING + call Load_HRZ_Table ;call Determine_HRZ ; Zone value stored in WREG ;MOVWF Measured_Zone - call overflow + ;call overflow + + ; heart rate measurement here + movlw 7 ; FICTITOUS HR VALUE FOR TESTING + + ; sift through HRZ_Table and find the relevant heart rate zone, with measured HR in WREG + call Determine_HRZ ; return with zone number in WREG + MOVWF PORTF - ; sift through HRZ_Table and find the relevant heart rate zone goto $ From 7a5684b34b83fdf437d599b059c325142ba903a3 Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Wed, 6 Dec 2023 20:36:23 +0000 Subject: [PATCH 19/29] 16 bit Division Subroutine --- main.s | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/main.s b/main.s index 85b56701..55993a87 100644 --- a/main.s +++ b/main.s @@ -12,6 +12,11 @@ psect udata_acs ; reserve data space in access ram counter: ds 1 ; reserve one byte for a counter variable delay_count:ds 1 ; reserve one byte for counter in the delay routine Measured_Zone:ds 1 +Num_H:ds 1 +Num_L:ds 1 +Den_H:ds 1 +Den_L:ds 1 +Quotient:ds 1 HR_Measured:ds 1 ; reserve one byte for measured HR value from sensor HR_max: ds 1 ; the maximum heart rate calculated froma ge HR_max_20: ds 1 ; the quotient of HR_max divided by 20 @@ -70,8 +75,8 @@ start: ;call Read_Age_Input_Find_HR_Max ; return with W = HRmax ;movwf HR_max - movlw 10 ; FICTITOUS HR MAX FOR TESTING - call Load_HRZ_Table + ;movlw 10 ; FICTITOUS HR MAX FOR TESTING + ;call Load_HRZ_Table ;call Determine_HRZ ; Zone value stored in WREG ;MOVWF Measured_Zone @@ -79,11 +84,59 @@ start: ;call overflow ; heart rate measurement here - movlw 7 ; FICTITOUS HR VALUE FOR TESTING + ;movlw 5 ; FICTITOUS HR VALUE FOR TESTING ; sift through HRZ_Table and find the relevant heart rate zone, with measured HR in WREG - call Determine_HRZ ; return with zone number in WREG - MOVWF PORTF + ;call Determine_HRZ ; return with zone number in WREG + ;MOVWF PORTB + + MOVLW 0x11 + MOVWF Num_H + MOVLW 0x22 + MOVWF Num_L + MOVLW 0x66 + MOVWF Den_H + MOVLW 0x66 + MOVWF Den_L + + call Sixteen_Division + nop + nop + nop + +Sixteen_Division: + MOVLW 0 + MOVWF Quotient ; initialise quotient +High_byte_check: + MOVFF Den_H, WREG + CPFSGT Num_H + bra End_Sixteen_Division ; when high byte of denominator is greater than numerator + bra Low_byte_check +Low_byte_check: + MOVFF Den_L, WREG + CPFSGT Num_L + bra Sixteen_Borrow + bra Sixteen_Subtraction +Sixteen_Subtraction: + MOVFF Den_L, WREG + SUBWF Num_L, 1 + MOVFF Den_H, WREG + SUBWF Num_H, 1 + INCF Quotient, 1 + MOVFF Quotient, PORTB + bra High_byte_check +Sixteen_Borrow: + DECF Num_H, 1 ; borrow from Num_H + MOVFF Den_H, WREG + CPFSGT Num_H + bra End_Sixteen_Division + bra Sixteen_Subtraction +End_Sixteen_Division: + MOVFF Quotient, PORTC + ; move results into results register pair + return + + goto $ From fd463fcbb722e12dab049ad5484a5ac21ce2a990 Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Thu, 7 Dec 2023 12:32:46 +0000 Subject: [PATCH 20/29] 07/12 End of Session Update --- RRInterval.s | 68 +++++++++++++++++++++++++++++++++++++++++----- Timer0.s | 6 ++-- main.s | 77 +++++++++++++++++----------------------------------- 3 files changed, 90 insertions(+), 61 deletions(-) diff --git a/RRInterval.s b/RRInterval.s index 7c2f9a82..81f5b661 100644 --- a/RRInterval.s +++ b/RRInterval.s @@ -1,34 +1,47 @@ #include -global no_overflow, overflow +global RR_int, RR_Setup, no_overflow, overflow, Sixteen_Division psect udata_acs prevtimeH: ds 1 prevtimeL: ds 1 + maxH:ds 1 maxL:ds 1 +Num_H:ds 1 +Num_L:ds 1 +Den_H:ds 1 +Den_L:ds 1 +Heart_Rate:ds 1 + periodH: ds 1 periodL: ds 1 -HR: ds 1 Numerator: ds 1 ;for working out bpm 60/RR interval psect External_timer, class = CODE RR_Setup: - movlw 60 - movwf Numerator ;for working out bpm 60/RR interval + ;movlw 60 + ;movwf Numerator ;for working out bpm 60/RR interval bsf CCP5CON, 1 bsf CCP5CON, 2 ; sets up CCP5 as capture on every rising edge (00000110) movlw 0x00 movwf CCPTMRS1 ;sets CCP5 to use timer1 for capture - movlw 10110011 ;enables Timer1 to synchronise with external clock at RA5 and perform read/write in 1 16bit operation + movlw 10110111 ;enables Timer1 to synchronise with external clock at RA5 and perform read/write in 1 16bit operation movwf T1CON bsf PIE4, 2 ;enables CCP5 interrupt bsf PIE1, 0 ;enables timer1 overflow interrupt + bsf IPR4, 2 + bsf ODCON2, 2 + movlw 0x00 + movwf TRISF return RR_int: + ;bsf PIR4, 2 + nop + nop btfss PIR4, 2 ;Checks to see if CCP5 interrupt flag retfie f btfss PIR1, 0 ;Checks to see if timer1 overflowed @@ -60,6 +73,7 @@ Subtract_no: movff CCPR5L, WREG movwf prevtimeL bcf PIR4, 2 ;clear CCP interrupt flag + movff periodL, PORTF retfie f overflow: @@ -103,7 +117,47 @@ Addition: movwf prevtimeL bcf PIR4, 2 ;clear CCP interrupt flag bcf PIR1, 2 + movff periodL, PORTF retfie f -convert: - ;Need to multiply period by 1.024ms to determine \ No newline at end of file +Sixteen_Division: + MOVLW 0xEA + MOVWF Num_H + MOVLW 0x60 + MOVWF Num_L ; initiate numerator to 60000 ms + MOVLW 0x02 + MOVWF Den_H + MOVLW 0x58 + MOVWF Den_L + + MOVLW 0 + MOVWF Heart_Rate ; initialise quotient +High_byte_check: + MOVFF Den_H, WREG + CPFSGT Num_H + bra End_Sixteen_Division ; when high byte of denominator is greater than numerator + bra Low_byte_check +Low_byte_check: + MOVFF Den_L, WREG + CPFSGT Num_L + bra Sixteen_Borrow + bra Sixteen_Subtraction +Sixteen_Subtraction: + MOVFF Den_L, WREG + SUBWF Num_L, 1 + MOVFF Den_H, WREG + SUBWF Num_H, 1 + INCF Heart_Rate, 1 + MOVFF Heart_Rate, PORTB + bra High_byte_check +Sixteen_Borrow: + DECF Num_H, 1 ; borrow from Num_H + MOVFF Den_H, WREG + CPFSGT Num_H + bra End_Sixteen_Division + bra Sixteen_Subtraction +End_Sixteen_Division: + MOVFF Heart_Rate, PORTC + MOVFF Heart_Rate, WREG + ; move results into results register pair + return ; return with Heart Rate in \ No newline at end of file diff --git a/Timer0.s b/Timer0.s index 68284e39..5ddaef08 100644 --- a/Timer0.s +++ b/Timer0.s @@ -23,8 +23,10 @@ Turn_on: Timer_Setup: movlw 00100000B ;set RA5 as input and rest of Port A as output movwf TRISA, A - movlw 11000100B ;set Timer0 to 8-bit, Fosc/4/32 + movlw 11000111B ;set Timer0 to 8-bit, Fosc/4/256 movwf T0CON, A ;approximately 0.5ms rollover bsf INTCON, 5 ;enable timer0 interrupt, bit 5 = TIME0IE bsf INTCON, 7 ;enable all interrupts 7=GIE - return \ No newline at end of file + bcf INTCON2, 2 + return + diff --git a/main.s b/main.s index 55993a87..03b6d704 100644 --- a/main.s +++ b/main.s @@ -6,17 +6,12 @@ extrn Keypad_INIT, Keypad_READ, delay_ms extrn Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ extrn Timer_Setup, Timer_int_hi -extrn no_overflow, overflow +extrn RR_int, RR_Setup, no_overflow, overflow, Sixteen_Division psect udata_acs ; reserve data space in access ram counter: ds 1 ; reserve one byte for a counter variable delay_count:ds 1 ; reserve one byte for counter in the delay routine Measured_Zone:ds 1 -Num_H:ds 1 -Num_L:ds 1 -Den_H:ds 1 -Den_L:ds 1 -Quotient:ds 1 HR_Measured:ds 1 ; reserve one byte for measured HR value from sensor HR_max: ds 1 ; the maximum heart rate calculated froma ge HR_max_20: ds 1 ; the quotient of HR_max divided by 20 @@ -40,9 +35,11 @@ psect code, abs rst: org 0x0 goto setup -timer_interrupt_low: org 0x0008 +CCP_Interrupt: org 0x0008 + goto RR_int + +Timer_int_low: org 0x0018 goto Timer_int_hi - ; ******* Programme FLASH read Setup Code *********************** setup: bcf CFGS ; point to Flash program memory bsf EEPGD ; access Flash program memory @@ -50,6 +47,18 @@ setup: bcf CFGS ; point to Flash program memory call Keypad_INIT ; setup keypad call LCD_Setup ; setup UART + call RR_Setup + + call Timer_Setup + bsf INTCON, 7 ;enable all interrupts 7=GIE + bsf INTCON, 6 + bsf PIE4, 2 + bsf ODCON2, 2 + clrf TMR1H + clrf TMR1L + ;bsf INTCON, 6 + ;bsf INTCON, 4 + movlw 0x00 movwf TRISD @@ -59,8 +68,9 @@ setup: bcf CFGS ; point to Flash program memory movlw 0x00 movwf TRISB - movlw 0x00 - movwf TRISJ + movlw 00010000B + movwf TRISG + ;movlw 0 ;movwf kb_pressed, A ; initialise this as 0, to indicate o key has been pressed @@ -82,59 +92,22 @@ start: ;MOVWF Measured_Zone ;call overflow + goto $ ; heart rate measurement here - ;movlw 5 ; FICTITOUS HR VALUE FOR TESTING + ; sift through HRZ_Table and find the relevant heart rate zone, with measured HR in WREG ;call Determine_HRZ ; return with zone number in WREG ;MOVWF PORTB - MOVLW 0x11 - MOVWF Num_H - MOVLW 0x22 - MOVWF Num_L - MOVLW 0x66 - MOVWF Den_H - MOVLW 0x66 - MOVWF Den_L - call Sixteen_Division + ;call Sixteen_Division nop nop nop -Sixteen_Division: - MOVLW 0 - MOVWF Quotient ; initialise quotient -High_byte_check: - MOVFF Den_H, WREG - CPFSGT Num_H - bra End_Sixteen_Division ; when high byte of denominator is greater than numerator - bra Low_byte_check -Low_byte_check: - MOVFF Den_L, WREG - CPFSGT Num_L - bra Sixteen_Borrow - bra Sixteen_Subtraction -Sixteen_Subtraction: - MOVFF Den_L, WREG - SUBWF Num_L, 1 - MOVFF Den_H, WREG - SUBWF Num_H, 1 - INCF Quotient, 1 - MOVFF Quotient, PORTB - bra High_byte_check -Sixteen_Borrow: - DECF Num_H, 1 ; borrow from Num_H - MOVFF Den_H, WREG - CPFSGT Num_H - bra End_Sixteen_Division - bra Sixteen_Subtraction -End_Sixteen_Division: - MOVFF Quotient, PORTC - ; move results into results register pair - return + @@ -142,4 +115,4 @@ End_Sixteen_Division: goto $ end rst - + \ No newline at end of file From 344e50858d23b4124d5025b7859be7a03c2d6dfe Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Thu, 7 Dec 2023 15:18:28 +0000 Subject: [PATCH 21/29] IIR Filter Subroutine added --- Calculations.s | 88 +++++++++++++++++++++++++++++++++++++++++++++++++- main.s | 39 +++++++++++++--------- 2 files changed, 111 insertions(+), 16 deletions(-) diff --git a/Calculations.s b/Calculations.s index c0ff2cd2..350c5a52 100644 --- a/Calculations.s +++ b/Calculations.s @@ -1,6 +1,6 @@ #include -global Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ +global Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ, IIR_Filter ; this includes subroutines for calculations: e.g. max heart rate calculation, boundary calculations psect udata_acs @@ -13,6 +13,17 @@ STATUS_CHECK:ds 1 HR_max:ds 1 Zone_Value:ds 1 HR_Measured:ds 1 ; reserve one byte for measured HR value from sensor + +x1:ds 1 +x2:ds 1 +x3:ds 1 +x1x2H:ds 1 +x1x2L:ds 1 +x1x2x3H:ds 1 +x1x2x3L:ds 1 +myDen_low:ds 1 +myQuo:ds 1 +myRem:ds 1 psect calculations_code,class=CODE @@ -131,3 +142,78 @@ Table_Compare_Loop: Output_Zone_Value: MOVFF Zone_Value, WREG return + +IIR_Filter: + MOVWF x3 ; newest measurement WREG -> x3 + + MOVFF x1, WREG + ADDWF x2, 0 ; 200 + 256 = 456 = 1C8 + MOVWF x1x2L + + MOVLW 0x00 + ADDWFC x1x2H, 1 ; carry to higher byte + INCF x1x2L, 1 + + ; give newest measurement a higher weighting, multiply it by 2 + MOVFF x3, WREG ; newest measuremeng in WREG + MULLW 2 ; double the weighting than the other two measurements + ; results stored in PRODH:PRODL 2*HR_newest + MOVFF PRODH, WREG + MOVFF PRODL, WREG + ADDWF x1x2L, 0 ; 456 + 200 = 656 = 290 + MOVWF x1x2x3L ; contains lower byte of sum + + MOVFF PRODH, WREG + ADDWFC x1x2H, 0 + MOVWF x1x2x3H ; contains higher byte of sum + + ; divide by 4 + + MOVLW 3 ; Think this needs to be n - 1, where n is the denominator?? + MOVWF myDen_low ; divide by 4 to find the average + + MOVLW 0 ; Move 0 into WREG to check if denominator is zero + CPFSEQ myDen_low + GOTO Clear ; Check the MSB of myDenominator + GOTO DivisionError ; If zero, handle division by zero +Clear: ; Perform division algorithm + CLRF myQuo ; Clear the quotient register + CLRF myRem ; Clear the remainder register + +Division_Loop: + MOVFF myDen_low, WREG + CPFSLT x1x2x3L ; if lower byte is smaller than denominator: need to borrow + bra Check_Equal + bra Borrow_or_Done +Borrow_or_Done: + MOVLW 0 + CPFSGT x1x2x3H ; Check if done, i.e. if the upper byte is zero. + bra Division_Done + DECF x1x2x3H, 1 ; Borrow from higher byte + MOVFF x1x2x3H, PORTB + bra Subtract +Check_Equal: + MOVFF myDen_low, WREG + CPFSEQ x1x2x3L + bra Subtract + bra Borrow_or_Done +Subtract: + INCF myQuo, 1 ; Increment quotient + MOVFF myQuo, PORTD + MOVFF myDen_low, WREG + SUBWFB x1x2x3L, 1 ; myNumerator -= myDenominator + MOVFF x1x2x3L, PORTC + bra Division_Loop +Division_Done: + call Update_Vals + MOVFF myQuo, WREG ; 656/4 = 164 ... + RETURN +DivisionError: + RETURN +Update_Vals: + MOVFF x2, WREG + MOVWF x1 ; update x1 with value in x2 + MOVFF myQuo, WREG + MOVWF x2 ; update x2 with newest measurement + return + \ No newline at end of file diff --git a/main.s b/main.s index 03b6d704..c95c9d3b 100644 --- a/main.s +++ b/main.s @@ -4,7 +4,7 @@ extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D extrn Keypad_INIT, Keypad_READ, delay_ms extrn Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max -extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ +extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ, IIR_Filter extrn Timer_Setup, Timer_int_hi extrn RR_int, RR_Setup, no_overflow, overflow, Sixteen_Division @@ -12,6 +12,7 @@ psect udata_acs ; reserve data space in access ram counter: ds 1 ; reserve one byte for a counter variable delay_count:ds 1 ; reserve one byte for counter in the delay routine Measured_Zone:ds 1 + HR_Measured:ds 1 ; reserve one byte for measured HR value from sensor HR_max: ds 1 ; the maximum heart rate calculated froma ge HR_max_20: ds 1 ; the quotient of HR_max divided by 20 @@ -43,7 +44,7 @@ Timer_int_low: org 0x0018 ; ******* Programme FLASH read Setup Code *********************** setup: bcf CFGS ; point to Flash program memory bsf EEPGD ; access Flash program memory - ;call UART_Setup ; setup UART + call UART_Setup ; setup UART call Keypad_INIT ; setup keypad call LCD_Setup ; setup UART @@ -52,13 +53,12 @@ setup: bcf CFGS ; point to Flash program memory call Timer_Setup bsf INTCON, 7 ;enable all interrupts 7=GIE bsf INTCON, 6 + bsf INTCON, 4 bsf PIE4, 2 bsf ODCON2, 2 clrf TMR1H clrf TMR1L - ;bsf INTCON, 6 - ;bsf INTCON, 4 - + movlw 0x00 movwf TRISD @@ -71,6 +71,14 @@ setup: bcf CFGS ; point to Flash program memory movlw 00010000B movwf TRISG + MOVLW 0x00 + MOVWF x1 + MOVWF x2 + MOVWF x1x2H + MOVWF x1x2L + MOVWF x1x2x3H + MOVWF x1x2x3L + ;movlw 0 ;movwf kb_pressed, A ; initialise this as 0, to indicate o key has been pressed @@ -91,23 +99,24 @@ start: ;call Determine_HRZ ; Zone value stored in WREG ;MOVWF Measured_Zone - ;call overflow - goto $ - + ; call overflow ; heart rate measurement here + + ; call Sixteen_Division + + ; IIR Filter: subroutine is entered with most recent measurement in WREG, outputs the averaged value + + ; MOVLW 0x64 ;Fictitious HR = 100 + ; call IIR_Filter ; Output_HR = average of past 3 measurements + ; sift through HRZ_Table and find the relevant heart rate zone, with measured HR in WREG - ;call Determine_HRZ ; return with zone number in WREG - ;MOVWF PORTB + ; call Determine_HRZ ; return with zone number in WREG + ; MOVWF PORTB - ;call Sixteen_Division - nop - nop - nop - From 1deefa4f3cc2db26b5bc6d4ec4355089a39a2b03 Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:37:56 +0000 Subject: [PATCH 22/29] Sensor Pulse Pulling Routine --- Calculations.s | 26 +++++----- RRInterval.s | 58 ++++++++++++---------- Timer.s | 29 +++++++++++ Timer0.s | 32 ------------ main.s | 96 +++++++++++++++++++++--------------- nbproject/configurations.xml | 2 +- 6 files changed, 129 insertions(+), 114 deletions(-) create mode 100644 Timer.s delete mode 100644 Timer0.s diff --git a/Calculations.s b/Calculations.s index 350c5a52..9e8e6454 100644 --- a/Calculations.s +++ b/Calculations.s @@ -174,41 +174,41 @@ IIR_Filter: MOVLW 0 ; Move 0 into WREG to check if denominator is zero CPFSEQ myDen_low - GOTO Clear ; Check the MSB of myDenominator - GOTO DivisionError ; If zero, handle division by zero -Clear: ; Perform division algorithm + GOTO Clear_1 ; Check the MSB of myDenominator + GOTO DivisionError_1 ; If zero, handle division by zero +Clear_1: ; Perform division algorithm CLRF myQuo ; Clear the quotient register CLRF myRem ; Clear the remainder register -Division_Loop: +Division_Loop_1: MOVFF myDen_low, WREG CPFSLT x1x2x3L ; if lower byte is smaller than denominator: need to borrow bra Check_Equal - bra Borrow_or_Done -Borrow_or_Done: + bra Borrow_or_Done_1 +Borrow_or_Done_1: MOVLW 0 CPFSGT x1x2x3H ; Check if done, i.e. if the upper byte is zero. bra Division_Done DECF x1x2x3H, 1 ; Borrow from higher byte MOVFF x1x2x3H, PORTB - bra Subtract + bra Subtract_1 Check_Equal: MOVFF myDen_low, WREG CPFSEQ x1x2x3L - bra Subtract - bra Borrow_or_Done -Subtract: + bra Subtract_1 + bra Borrow_or_Done_1 +Subtract_1: INCF myQuo, 1 ; Increment quotient MOVFF myQuo, PORTD MOVFF myDen_low, WREG SUBWFB x1x2x3L, 1 ; myNumerator -= myDenominator MOVFF x1x2x3L, PORTC - bra Division_Loop -Division_Done: + bra Division_Loop_1 +Division_Done_1: call Update_Vals MOVFF myQuo, WREG ; 656/4 = 164 ... RETURN -DivisionError: +DivisionError_1: RETURN Update_Vals: MOVFF x2, WREG diff --git a/RRInterval.s b/RRInterval.s index 81f5b661..fe778e53 100644 --- a/RRInterval.s +++ b/RRInterval.s @@ -1,6 +1,6 @@ #include -global RR_int, RR_Setup, no_overflow, overflow, Sixteen_Division +global no_overflow, overflow, Sixteen_Division psect udata_acs @@ -21,32 +21,36 @@ Numerator: ds 1 ;for working out bpm 60/RR interval psect External_timer, class = CODE -RR_Setup: - ;movlw 60 - ;movwf Numerator ;for working out bpm 60/RR interval - bsf CCP5CON, 1 - bsf CCP5CON, 2 ; sets up CCP5 as capture on every rising edge (00000110) - movlw 0x00 - movwf CCPTMRS1 ;sets CCP5 to use timer1 for capture - movlw 10110111 ;enables Timer1 to synchronise with external clock at RA5 and perform read/write in 1 16bit operation - movwf T1CON - bsf PIE4, 2 ;enables CCP5 interrupt - bsf PIE1, 0 ;enables timer1 overflow interrupt - bsf IPR4, 2 - bsf ODCON2, 2 - movlw 0x00 - movwf TRISF - return - -RR_int: - ;bsf PIR4, 2 - nop - nop - btfss PIR4, 2 ;Checks to see if CCP5 interrupt flag - retfie f - btfss PIR1, 0 ;Checks to see if timer1 overflowed - bra no_overflow - bra overflow +;RR_Setup: +; ;movlw 60 +; ;movwf Numerator ;for working out bpm 60/RR interval +; bsf TRISA, 5, A +; movlw 0x05 +; movwf CCP5CON, A +; ;bsf CCP5CON, 1 +; ;bsf CCP5CON, 2 ; sets up CCP5 as capture on every rising edge (00000110) +; movlw 0x00 +; banksel CCPTMRS1 +; movwf CCPTMRS1,B ;sets CCP5 to use timer1 for capture +; movlw 00111111B ;enables Timer1 to synchronise with external clock at RA5 and perform read/write in 1 16bit operation +; movwf T1CON +; bsf PIE4, 2 ;enables CCP5 interrupt +; bcf PIE1, 0 ;enables timer1 overflow interrupt +; bsf IPR4, 2 ;timer 1 +; ;bsf ODCON2, 2 +; movlw 0x00 +; movwf TRISF +; movwf PIR1 +; movwf PIR4 +; return +; +;RR_int: +; movlw 0xff +; movwf LATF, A +; bcf PIR4, 2 ;Checks to see if timer1 overflowed +; retfie f +; bra no_overflow +; bra overflow no_overflow: ;subtract values stored in prevtimeH and prevtimeL from CCPR5H and CCPR5L store result in period diff --git a/Timer.s b/Timer.s new file mode 100644 index 00000000..1550fa0a --- /dev/null +++ b/Timer.s @@ -0,0 +1,29 @@ +#include + +global Timer_Setup +psect External_timer, class = CODE + +;Timer_int_hi: +; btfss INTCON, 2 ;check this is a timer 0 interrupt, bit 5 = TMR0IF +; retfie f ;if not then return +; btfss PORTA, 4 ;check if bit 4 is set (skips next instruction if set) +; bra Turn_on +; bra Turn_off +; +;Turn_off: +; bcf PORTA, 4 +; bcf INTCON, 2 +; retfie f +; +;Turn_on: +; bsf PORTA, 4 +; bcf INTCON, 2 +; retfie f + +Timer_Setup: + movlw 10000010B + movwf T0CON, A + bsf GIE ;enable all interrupts 7=GIE + bsf INTCON, 6 + bsf INTCON, 5 ;TMR0IE + return diff --git a/Timer0.s b/Timer0.s deleted file mode 100644 index 5ddaef08..00000000 --- a/Timer0.s +++ /dev/null @@ -1,32 +0,0 @@ -#include - -global Timer_Setup, Timer_int_hi -psect External_timer, class = CODE - -Timer_int_hi: - btfss INTCON, 2 ;check this is a timer 0 interrupt, bit 5 = TMR0IF - retfie f ;if not then return - btfss PORTA, 4 ;check if bit 4 is set (skips next instruction if set) - bra Turn_on - bra Turn_off - -Turn_off: - bcf PORTA, 4 - bcf INTCON, 2 - retfie f - -Turn_on: - bsf PORTA, 4 - bcf INTCON, 2 - retfie f - -Timer_Setup: - movlw 00100000B ;set RA5 as input and rest of Port A as output - movwf TRISA, A - movlw 11000111B ;set Timer0 to 8-bit, Fosc/4/256 - movwf T0CON, A ;approximately 0.5ms rollover - bsf INTCON, 5 ;enable timer0 interrupt, bit 5 = TIME0IE - bsf INTCON, 7 ;enable all interrupts 7=GIE - bcf INTCON2, 2 - return - diff --git a/main.s b/main.s index c95c9d3b..dc0c49d6 100644 --- a/main.s +++ b/main.s @@ -5,14 +5,15 @@ extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D extrn Keypad_INIT, Keypad_READ, delay_ms extrn Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ, IIR_Filter -extrn Timer_Setup, Timer_int_hi -extrn RR_int, RR_Setup, no_overflow, overflow, Sixteen_Division +extrn Timer_Setup +extrn no_overflow, overflow, Sixteen_Division psect udata_acs ; reserve data space in access ram counter: ds 1 ; reserve one byte for a counter variable delay_count:ds 1 ; reserve one byte for counter in the delay routine Measured_Zone:ds 1 - +Time_Counter:ds 1 +prev_val:ds 1 HR_Measured:ds 1 ; reserve one byte for measured HR value from sensor HR_max: ds 1 ; the maximum heart rate calculated froma ge HR_max_20: ds 1 ; the quotient of HR_max divided by 20 @@ -36,49 +37,41 @@ psect code, abs rst: org 0x0 goto setup -CCP_Interrupt: org 0x0008 - goto RR_int +Timer_Interrupt:org 0x0008 + btfss TMR0IF + retfie f + goto TMR0_INT -Timer_int_low: org 0x0018 - goto Timer_int_hi ; ******* Programme FLASH read Setup Code *********************** setup: bcf CFGS ; point to Flash program memory bsf EEPGD ; access Flash program memory - call UART_Setup ; setup UART - call Keypad_INIT ; setup keypad - call LCD_Setup ; setup UART - - call RR_Setup - - call Timer_Setup - bsf INTCON, 7 ;enable all interrupts 7=GIE - bsf INTCON, 6 - bsf INTCON, 4 - bsf PIE4, 2 - bsf ODCON2, 2 - clrf TMR1H - clrf TMR1L + ;call UART_Setup ; setup UART + ;call Keypad_INIT ; setup keypad + ;call LCD_Setup ; setup UART +; call RR_Setup movlw 0x00 - movwf TRISD + movwf Time_Counter + call Timer_Setup - movlw 0x00 - movwf TRISC + ;bsf INTCON, 4 +; bsf PIE4, 2 +; bsf ODCON2, 2 +; clrf TMR1H +; clrf TMR1L + movlw 0x00 - movwf TRISB - - movlw 00010000B - movwf TRISG + movwf TRISH + + movlw 0x00 + movwf TRISF - MOVLW 0x00 - MOVWF x1 - MOVWF x2 - MOVWF x1x2H - MOVWF x1x2L - MOVWF x1x2x3H - MOVWF x1x2x3L + movlw 0xFF + movwf TRISD + movlw 0x00 + movwf TRISJ ;movlw 0 ;movwf kb_pressed, A ; initialise this as 0, to indicate o key has been pressed @@ -114,14 +107,35 @@ start: ; sift through HRZ_Table and find the relevant heart rate zone, with measured HR in WREG ; call Determine_HRZ ; return with zone number in WREG ; MOVWF PORTB - - - - - - + + movlw 0x01 + movwf PORTJ, A ; clear checking port +Detection_Loop: + movlw 0x01 + CPFSEQ PORTD ; skip if pulse signal is high + bra Update_and_Branch + CPFSEQ PORTJ ; skip if previous pulse was also high + call Signal_Detected + bra Update_and_Branch +Update_and_Branch: + MOVFF PORTD, PORTJ ; update LATJ with current value + bra Detection_Loop +Signal_Detected: + MOVFF PORTD, PORTJ ; update LATJ with current value + MOVFF Time_Counter, WREG ; move timer count to WREG + MOVFF Time_Counter, PORTF + MOVLW 0 + MOVWF Time_Counter ; reset time_counter + bra Detection_Loop + goto $ + TMR0_INT: + INCF Time_Counter, 1 + MOVFF Time_Counter, PORTH + bcf TMR0IF + retfie f + end rst \ No newline at end of file diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 065671aa..05bc6ef4 100755 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -19,8 +19,8 @@ Keypad.s Digit_Reader.s Calculations.s - Timer0.s RRInterval.s + Timer.s Date: Fri, 8 Dec 2023 16:30:46 +0000 Subject: [PATCH 23/29] calculation of heart rate from overflow added Might need to change some parameters for the calculation. Check period of overflow --- RRInterval.s | 22 ++++++++++++---------- Timer.s | 11 ++++++++--- main.s | 23 ++++++++++++----------- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/RRInterval.s b/RRInterval.s index fe778e53..e49ea998 100644 --- a/RRInterval.s +++ b/RRInterval.s @@ -123,40 +123,42 @@ Addition: bcf PIR1, 2 movff periodL, PORTF retfie f + + Sixteen_Division: MOVLW 0xEA MOVWF Num_H MOVLW 0x60 MOVWF Num_L ; initiate numerator to 60000 ms - MOVLW 0x02 - MOVWF Den_H - MOVLW 0x58 - MOVWF Den_L +; MOVLW 0x02 +; MOVWF Den_H +; MOVLW 0x58 +; MOVWF Den_L MOVLW 0 MOVWF Heart_Rate ; initialise quotient High_byte_check: - MOVFF Den_H, WREG + MOVFF PRODH, WREG CPFSGT Num_H bra End_Sixteen_Division ; when high byte of denominator is greater than numerator bra Low_byte_check Low_byte_check: - MOVFF Den_L, WREG + MOVFF PRODL, WREG CPFSGT Num_L bra Sixteen_Borrow bra Sixteen_Subtraction Sixteen_Subtraction: - MOVFF Den_L, WREG + MOVFF PRODL, WREG SUBWF Num_L, 1 - MOVFF Den_H, WREG + MOVFF PRODH, WREG SUBWF Num_H, 1 INCF Heart_Rate, 1 MOVFF Heart_Rate, PORTB bra High_byte_check Sixteen_Borrow: DECF Num_H, 1 ; borrow from Num_H - MOVFF Den_H, WREG + MOVFF PRODH, WREG CPFSGT Num_H bra End_Sixteen_Division bra Sixteen_Subtraction @@ -164,4 +166,4 @@ End_Sixteen_Division: MOVFF Heart_Rate, PORTC MOVFF Heart_Rate, WREG ; move results into results register pair - return ; return with Heart Rate in \ No newline at end of file + return ; return with Heart Rate in WREG \ No newline at end of file diff --git a/Timer.s b/Timer.s index 1550fa0a..a27ad8fd 100644 --- a/Timer.s +++ b/Timer.s @@ -1,6 +1,6 @@ #include -global Timer_Setup +global Timer_Setup, TMR0_INT psect External_timer, class = CODE ;Timer_int_hi: @@ -19,9 +19,14 @@ psect External_timer, class = CODE ; bsf PORTA, 4 ; bcf INTCON, 2 ; retfie f - +TMR0_INT: + INCF Time_Counter, 1 + MOVFF Time_Counter, PORTH + bcf TMR0IF + retfie f + Timer_Setup: - movlw 10000010B + movlw 10000110B ; Fcyc/128 = 125 KHz movwf T0CON, A bsf GIE ;enable all interrupts 7=GIE bsf INTCON, 6 diff --git a/main.s b/main.s index dc0c49d6..24f82d8d 100644 --- a/main.s +++ b/main.s @@ -5,7 +5,7 @@ extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D extrn Keypad_INIT, Keypad_READ, delay_ms extrn Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ, IIR_Filter -extrn Timer_Setup +extrn Timer_Setup, TMR0_INT extrn no_overflow, overflow, Sixteen_Division psect udata_acs ; reserve data space in access ram @@ -13,7 +13,7 @@ counter: ds 1 ; reserve one byte for a counter variable delay_count:ds 1 ; reserve one byte for counter in the delay routine Measured_Zone:ds 1 Time_Counter:ds 1 -prev_val:ds 1 +Count:ds 1 HR_Measured:ds 1 ; reserve one byte for measured HR value from sensor HR_max: ds 1 ; the maximum heart rate calculated froma ge HR_max_20: ds 1 ; the quotient of HR_max divided by 20 @@ -51,7 +51,7 @@ setup: bcf CFGS ; point to Flash program memory ; call RR_Setup movlw 0x00 - movwf Time_Counter + movwf Time_Counter ; Initialise Time_Counter call Timer_Setup @@ -108,7 +108,7 @@ start: ; call Determine_HRZ ; return with zone number in WREG ; MOVWF PORTB - movlw 0x01 + movlw 0x00 movwf PORTJ, A ; clear checking port Detection_Loop: movlw 0x01 @@ -123,19 +123,20 @@ Update_and_Branch: Signal_Detected: MOVFF PORTD, PORTJ ; update LATJ with current value MOVFF Time_Counter, WREG ; move timer count to WREG + MOVWF Count ; Store value in Count for calculation access MOVFF Time_Counter, PORTF MOVLW 0 + call Find_HR MOVWF Time_Counter ; reset time_counter bra Detection_Loop - goto $ - - TMR0_INT: - INCF Time_Counter, 1 - MOVFF Time_Counter, PORTH - bcf TMR0IF - retfie f + +Find_HR_from_Overflow: + MOVFF Count, WREG ; move count to W for multiplication + MULLW 8 ; multiply counter with period of timer0, result stored in PRODH:PRODL + call Sixteen_Division; denominator stored in PRODH, PRODL + return end rst \ No newline at end of file From 796c0af4350b36aab1ff0c9bc015e027cfad8d96 Mon Sep 17 00:00:00 2001 From: Alex Coleman <111077126+alexncoleman@users.noreply.github.com> Date: Tue, 12 Dec 2023 08:58:24 +0000 Subject: [PATCH 24/29] LCD LCD routine --- LCD.s | 57 +++++++++++++++++++++++++++++++++------------------------ main.s | 9 ++++++++- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/LCD.s b/LCD.s index 3f278f0a..630ac97d 100644 --- a/LCD.s +++ b/LCD.s @@ -1,7 +1,7 @@ #include global LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D, Write_Welcome, SetTwoLines - +global Clear_LCD, LCD_Send_Byte_HR, LCD_Send_Byte_HRZ psect udata_acs ; named variables in access ram LCD_cnt_l: ds 1 ; reserve 1 byte for variable LCD_cnt_l LCD_cnt_h: ds 1 ; reserve 1 byte for variable LCD_cnt_h @@ -57,18 +57,6 @@ LCD_Setup: call LCD_delay_x4us return -LCD_Write_Message: ; Message stored at FSR2, length stored in W - movwf LCD_counter, A -LCD_Loop_message: - movf POSTINC0, W, A - call LCD_Send_Byte_D - decfsz LCD_counter, A - bra LCD_Loop_message - movlw 2000 - call LCD_delay_ms - ;dcfsnz TwoLineCounter, A - ;bra SetTwoLines - return LCD_Send_Byte_I: ; Transmits byte stored in W to instruction reg movwf LCD_tmp, A @@ -84,7 +72,28 @@ LCD_Send_Byte_I: ; Transmits byte stored in W to instruction reg call LCD_Enable ; Pulse enable Bit return -LCD_Send_Byte_D: ; Transmits byte stored in W to data reg +Clear_LCD: + movlw 00000001B ; display clear + call LCD_Send_Byte_I + return + +LCD_Send_Byte_HR: ; Transmits byte stored in W to data reg + movwf LCD_tmp, A + swapf LCD_tmp, W, A ; swap nibbles, high nibble goes first + andlw 0x0f ; select just low nibble + movwf LATB, A ; output data bits to LCD + bsf LATB, LCD_RS, A ; Data write set RS bit + call LCD_Enable ; Pulse enable Bit + movf LCD_tmp, W, A ; swap nibbles, now do low nibble + andlw 0x0f ; select just low nibble + movwf LATB, A ; output data bits to LCD + bsf LATB, LCD_RS, A ; Data write set RS bit + call LCD_Enable ; Pulse enable Bit + movlw 10 ; delay 40us + call LCD_delay_x4us + return + +LCD_Send_Byte_HRZ: ; Transmits byte stored in W to data reg movwf LCD_tmp, A swapf LCD_tmp, W, A ; swap nibbles, high nibble goes first andlw 0x0f ; select just low nibble @@ -100,16 +109,16 @@ LCD_Send_Byte_D: ; Transmits byte stored in W to data reg call LCD_delay_x4us return -Write_Welcome: - lfsr 0, myArray ; Load FSR0 with address in RAM - movlw low highword(InputMessage) ; address of data in PM - movwf TBLPTRU, A ; load upper bits to TBLPTRU - movlw high(InputMessage) ; address of data in PM - movwf TBLPTRH, A ; load high byte to TBLPTRH - movlw low(InputMessage) ; address of data in PM - movwf TBLPTRL, A ; load low byte to TBLPTRL - movlw myTable_l ; bytes to read - movwf counter, A ; our counter register +;Write_Welcome: +; lfsr 0, myArray ; Load FSR0 with address in RAM +; movlw low highword(InputMessage) ; address of data in PM +; movwf TBLPTRU, A ; load upper bits to TBLPTRU +; movlw high(InputMessage) ; address of data in PM +; movwf TBLPTRH, A ; load high byte to TBLPTRH +; movlw low(InputMessage) ; address of data in PM +; movwf TBLPTRL, A ; load low byte to TBLPTRL +; movlw myTable_l ; bytes to read +; movwf counter, A ; our counter register loop: tblrd*+ ; one byte from PM to TABLAT, increment TBLPRT movff TABLAT, POSTINC0; move data from TABLAT to (FSR0), inc FSR0 decfsz counter, A ; count down to zero diff --git a/main.s b/main.s index 24f82d8d..278f091b 100644 --- a/main.s +++ b/main.s @@ -1,12 +1,13 @@ #include ;extrn UART_Setup, UART_Transmit_Message ; external subroutines -extrn LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D +extrn LCD_Setup, Clear_LCD, LCD_Send_Byte_HR, LCD_Send_Byte_HRZ extrn Keypad_INIT, Keypad_READ, delay_ms extrn Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ, IIR_Filter extrn Timer_Setup, TMR0_INT extrn no_overflow, overflow, Sixteen_Division + psect udata_acs ; reserve data space in access ram counter: ds 1 ; reserve one byte for a counter variable @@ -128,6 +129,12 @@ Signal_Detected: MOVLW 0 call Find_HR MOVWF Time_Counter ; reset time_counter + ;Display HR on LCD + call Clear_LCD + ;Move HR to W + call LCD_Send_Byte_HR + ;Move HRZ to W + call LCD_Send_Byte_HRZ bra Detection_Loop goto $ From a08b587a9c889ee2264a91237b61dc2faac11aeb Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Tue, 12 Dec 2023 13:27:47 +0000 Subject: [PATCH 25/29] 12/12 Session Code Update --- Calculations.s | 48 +++++++++++++++++++- Digit_Reader.s | 5 ++- LCD.s | 80 ++++++++++++++++++++++++--------- RRInterval.s | 12 ++--- Timer.s | 11 ++--- main.s | 120 +++++++++++++++++++++++++++++++++++++++---------- 6 files changed, 217 insertions(+), 59 deletions(-) diff --git a/Calculations.s b/Calculations.s index 9e8e6454..2cbe4615 100644 --- a/Calculations.s +++ b/Calculations.s @@ -1,6 +1,6 @@ #include -global Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ, IIR_Filter +global Find_Max_Heart_Rate, Divide_By_20, Divide_By_Ten, Load_HRZ_Table, Determine_HRZ, IIR_Filter ; this includes subroutines for calculations: e.g. max heart rate calculation, boundary calculations psect udata_acs @@ -180,6 +180,47 @@ Clear_1: ; Perform division algorithm CLRF myQuo ; Clear the quotient register CLRF myRem ; Clear the remainder register +Divide_By_Ten: + ; Ensure myDenominator is not zero + MOVWF myNumerator +; Think this needs to be n - 1, where n is the denominator?? + MOVLW 9 + MOVWF myDenominator_low ; divide by 20 + + MOVLW 0 + CPFSEQ myDenominator_low + GOTO Clear_Ten ; Check the MSB of myDenominator + GOTO DivisionError_Ten ; If zero, handle division by zero +Clear_Ten: ; Perform division algorithm?? + CLRF myQuotient ; Clear the quotient register + CLRF myRemainder ; Clear the remainder register + +Division_Loop_Ten: + MOVFF myDenominator_low, WREG + CPFSLT PRODL ; if lower byte is smaller than denominator: need to borrow + BRA Subtract_Ten + BRA Borrow_or_Done_Ten +Borrow_or_Done_Ten: + MOVLW 0 + CPFSGT PRODH ; Check if done, i.e. if the upper byte is zero. + BRA Division_Done_Ten + DECF PRODH, 1 + ;MOVFF PRODH, PORTB +Subtract_Ten: + INCF myQuotient, 1 + MOVFF myQuotient, PORTD + MOVFF myDenominator_low, WREG + SUBWFB PRODL, 1 + ;MOVFF PRODL, PORTC + BRA Division_Loop_Ten +Division_Done_Ten: + ;MOVFF myQuotient, PORTC + MOVFF myQuotient, WREG ; return with the quotient in the WREG + RETURN +DivisionError_Ten: + RETURN + + Division_Loop_1: MOVFF myDen_low, WREG CPFSLT x1x2x3L ; if lower byte is smaller than denominator: need to borrow @@ -190,7 +231,7 @@ Borrow_or_Done_1: CPFSGT x1x2x3H ; Check if done, i.e. if the upper byte is zero. bra Division_Done DECF x1x2x3H, 1 ; Borrow from higher byte - MOVFF x1x2x3H, PORTB + ;MOVFF x1x2x3H, PORTB bra Subtract_1 Check_Equal: MOVFF myDen_low, WREG @@ -216,4 +257,7 @@ Update_Vals: MOVFF myQuo, WREG MOVWF x2 ; update x2 with newest measurement return + + + \ No newline at end of file diff --git a/Digit_Reader.s b/Digit_Reader.s index f4580c61..eef3e213 100644 --- a/Digit_Reader.s +++ b/Digit_Reader.s @@ -5,7 +5,7 @@ global Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max extrn Keypad_READ extrn delay_ms -extrn Find_Max_Heart_Rate +;extrn Find_Max_Heart_Rate extrn LCD_Write_Message psect udata_acs ; reserve data space in access ram @@ -95,7 +95,7 @@ Read_Age_Input_Find_HR_Max: ; find maximum heart rate movff age, WREG ; put age in WREG for use in subroutine - call Find_Max_Heart_Rate +; call Find_Max_Heart_Rate movwf maximum_heart_rate ; move value for maximum heart rate into variable movff maximum_heart_rate, WREG @@ -261,3 +261,4 @@ Test_9_2: + diff --git a/LCD.s b/LCD.s index 630ac97d..cef86db6 100644 --- a/LCD.s +++ b/LCD.s @@ -1,6 +1,6 @@ #include -global LCD_Setup, LCD_Write_Message, LCD_Send_Byte_D, Write_Welcome, SetTwoLines +global LCD_Setup, Write_Welcome, SetTwoLines, LCD_Write_Message, LCD_Write_Hex global Clear_LCD, LCD_Send_Byte_HR, LCD_Send_Byte_HRZ psect udata_acs ; named variables in access ram LCD_cnt_l: ds 1 ; reserve 1 byte for variable LCD_cnt_l @@ -8,6 +8,7 @@ LCD_cnt_h: ds 1 ; reserve 1 byte for variable LCD_cnt_h LCD_cnt_ms: ds 1 ; reserve 1 byte for ms counter LCD_tmp: ds 1 ; reserve 1 byte for temporary use LCD_counter: ds 1 ; reserve 1 byte for counting through nessage +LCD_hex_tmp: ds 1 TwoLineCounter: ds 1 counter:ds 1 myArray:ds 1 @@ -57,18 +58,42 @@ LCD_Setup: call LCD_delay_x4us return +LCD_Write_Hex: ; Writes byte stored in W as hex + movwf LCD_hex_tmp + swapf LCD_hex_tmp,W ; high nibble first + call LCD_Hex_Nib + movf LCD_hex_tmp,W ; then low nibble +LCD_Hex_Nib: ; writes low nibble as hex character + andlw 0x0F + movwf LCD_tmp + movlw 0x0A + cpfslt LCD_tmp + addlw 0x07 ; number is greater than 9 + addlw 0x26 + addwf LCD_tmp,W + call LCD_Send_Byte_D ; write out ascii + return -LCD_Send_Byte_I: ; Transmits byte stored in W to instruction reg - movwf LCD_tmp, A - swapf LCD_tmp, W, A ; swap nibbles, high nibble goes first +LCD_Write_Message: ; Message stored at FSR2, length stored in W + movwf LCD_counter, A +LCD_Loop_message: + movf POSTINC2, W, A + call LCD_Send_Byte_D + decfsz LCD_counter, A + bra LCD_Loop_message + return + +LCD_Send_Byte_I: ; Transmits byte stored in W to instruction reg + movwf LCD_tmp + swapf LCD_tmp,W ; swap nibbles, high nibble goes first andlw 0x0f ; select just low nibble - movwf LATB, A ; output data bits to LCD - bcf LATB, LCD_RS, A ; Instruction write clear RS bit + movwf LATB ; output data bits to LCD + bcf LATB, LCD_RS ; Instruction write clear RS bit call LCD_Enable ; Pulse enable Bit - movf LCD_tmp, W, A ; swap nibbles, now do low nibble + movf LCD_tmp,W ; swap nibbles, now do low nibble andlw 0x0f ; select just low nibble - movwf LATB, A ; output data bits to LCD - bcf LATB, LCD_RS, A ; Instruction write clear RS bit + movwf LATB ; output data bits to LCD + bcf LATB, LCD_RS ; Instruction write clear RS bit call LCD_Enable ; Pulse enable Bit return @@ -109,16 +134,16 @@ LCD_Send_Byte_HRZ: ; Transmits byte stored in W to data reg call LCD_delay_x4us return -;Write_Welcome: -; lfsr 0, myArray ; Load FSR0 with address in RAM -; movlw low highword(InputMessage) ; address of data in PM -; movwf TBLPTRU, A ; load upper bits to TBLPTRU -; movlw high(InputMessage) ; address of data in PM -; movwf TBLPTRH, A ; load high byte to TBLPTRH -; movlw low(InputMessage) ; address of data in PM -; movwf TBLPTRL, A ; load low byte to TBLPTRL -; movlw myTable_l ; bytes to read -; movwf counter, A ; our counter register +Write_Welcome: + lfsr 0, myArray ; Load FSR0 with address in RAM + movlw low highword(InputMessage) ; address of data in PM + movwf TBLPTRU, A ; load upper bits to TBLPTRU + movlw high(InputMessage) ; address of data in PM + movwf TBLPTRH, A ; load high byte to TBLPTRH + movlw low(InputMessage) ; address of data in PM + movwf TBLPTRL, A ; load low byte to TBLPTRL + movlw myTable_l ; bytes to read + movwf counter, A ; our counter register loop: tblrd*+ ; one byte from PM to TABLAT, increment TBLPRT movff TABLAT, POSTINC0; move data from TABLAT to (FSR0), inc FSR0 decfsz counter, A ; count down to zero @@ -128,8 +153,23 @@ loop: tblrd*+ ; one byte from PM to TABLAT, increment TBLPRT addlw 0xff ; don't send the final carriage return to LCD lfsr 2, myArray call LCD_Write_Message - + +LCD_Send_Byte_D: ; Transmits byte stored in W to data reg + movwf LCD_tmp + swapf LCD_tmp,W ; swap nibbles, high nibble goes first + andlw 0x0f ; select just low nibble + movwf LATB ; output data bits to LCD + bsf LATB, LCD_RS ; Data write set RS bit + call LCD_Enable ; Pulse enable Bit + movf LCD_tmp,W ; swap nibbles, now do low nibble + andlw 0x0f ; select just low nibble + movwf LATB ; output data bits to LCD + bsf LATB, LCD_RS ; Data write set RS bit + call LCD_Enable ; Pulse enable Bit + movlw 10 ; delay 40us + call LCD_delay_x4us + return SetTwoLines: movlw 11000000B diff --git a/RRInterval.s b/RRInterval.s index e49ea998..7e8fbb70 100644 --- a/RRInterval.s +++ b/RRInterval.s @@ -127,10 +127,10 @@ Addition: Sixteen_Division: - MOVLW 0xEA + MOVLW 0x75 MOVWF Num_H - MOVLW 0x60 - MOVWF Num_L ; initiate numerator to 60000 ms + MOVLW 0x30 + MOVWF Num_L ; initiate numerator to 15000 ms ; MOVLW 0x02 ; MOVWF Den_H ; MOVLW 0x58 @@ -154,7 +154,7 @@ Sixteen_Subtraction: MOVFF PRODH, WREG SUBWF Num_H, 1 INCF Heart_Rate, 1 - MOVFF Heart_Rate, PORTB + ;MOVFF Heart_Rate, PORTB bra High_byte_check Sixteen_Borrow: DECF Num_H, 1 ; borrow from Num_H @@ -166,4 +166,6 @@ End_Sixteen_Division: MOVFF Heart_Rate, PORTC MOVFF Heart_Rate, WREG ; move results into results register pair - return ; return with Heart Rate in WREG \ No newline at end of file + return ; return with Heart Rate in WREG + + \ No newline at end of file diff --git a/Timer.s b/Timer.s index a27ad8fd..142e64bb 100644 --- a/Timer.s +++ b/Timer.s @@ -1,6 +1,6 @@ #include -global Timer_Setup, TMR0_INT +global Timer_Setup psect External_timer, class = CODE ;Timer_int_hi: @@ -19,16 +19,13 @@ psect External_timer, class = CODE ; bsf PORTA, 4 ; bcf INTCON, 2 ; retfie f -TMR0_INT: - INCF Time_Counter, 1 - MOVFF Time_Counter, PORTH - bcf TMR0IF - retfie f Timer_Setup: - movlw 10000110B ; Fcyc/128 = 125 KHz + movlw 10000100B ; Fcyc/128 = 125 KHz movwf T0CON, A bsf GIE ;enable all interrupts 7=GIE bsf INTCON, 6 bsf INTCON, 5 ;TMR0IE return + + \ No newline at end of file diff --git a/main.s b/main.s index 278f091b..67c1c4f9 100644 --- a/main.s +++ b/main.s @@ -1,11 +1,11 @@ #include ;extrn UART_Setup, UART_Transmit_Message ; external subroutines -extrn LCD_Setup, Clear_LCD, LCD_Send_Byte_HR, LCD_Send_Byte_HRZ +extrn LCD_Setup, Clear_LCD, LCD_Send_Byte_HR, LCD_Send_Byte_HRZ, LCD_Write_Message, LCD_Write_Hex extrn Keypad_INIT, Keypad_READ, delay_ms extrn Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max -extrn Find_Max_Heart_Rate, Divide_By_20, Load_HRZ_Table, Determine_HRZ, IIR_Filter -extrn Timer_Setup, TMR0_INT +extrn Find_Max_Heart_Rate, Divide_By_20, Divide_By_Ten, Load_HRZ_Table, Determine_HRZ, IIR_Filter +extrn Timer_Setup extrn no_overflow, overflow, Sixteen_Division @@ -34,6 +34,13 @@ Database: DB 20, 18, 17, 15, 13, 11 align 2 +psect data +HRMessage: + db 'H','R','=',0x0a + ; message, plus carriage return + myTable_l EQU 4 ; length of data + align 2 + psect code, abs rst: org 0x0 goto setup @@ -41,19 +48,22 @@ rst: org 0x0 Timer_Interrupt:org 0x0008 btfss TMR0IF retfie f - goto TMR0_INT + INCF Time_Counter, 1 + bcf TMR0IF + movlw 10000100B ; Fcyc/128 = 125 KHz + movwf T0CON, A + retfie f ; ******* Programme FLASH read Setup Code *********************** setup: bcf CFGS ; point to Flash program memory bsf EEPGD ; access Flash program memory ;call UART_Setup ; setup UART ;call Keypad_INIT ; setup keypad - ;call LCD_Setup ; setup UART -; call RR_Setup movlw 0x00 movwf Time_Counter ; Initialise Time_Counter call Timer_Setup + call LCD_Setup ;bsf INTCON, 4 @@ -68,6 +78,9 @@ setup: bcf CFGS ; point to Flash program memory movlw 0x00 movwf TRISF + movlw 0x00 + movwf TRISC + movlw 0xFF movwf TRISD @@ -112,38 +125,99 @@ start: movlw 0x00 movwf PORTJ, A ; clear checking port Detection_Loop: - movlw 0x01 - CPFSEQ PORTD ; skip if pulse signal is high + ;call Write_HR_LCD + movlw 0x00 + CPFSGT PORTD ; skip if pulse signal is high bra Update_and_Branch - CPFSEQ PORTJ ; skip if previous pulse was also high + CPFSGT PORTJ ; skip if previous pulse was also high call Signal_Detected bra Update_and_Branch Update_and_Branch: MOVFF PORTD, PORTJ ; update LATJ with current value + MOVLW 0x00 + MOVWF PORTH bra Detection_Loop Signal_Detected: - MOVFF PORTD, PORTJ ; update LATJ with current value - MOVFF Time_Counter, WREG ; move timer count to WREG - MOVWF Count ; Store value in Count for calculation access - MOVFF Time_Counter, PORTF - MOVLW 0 - call Find_HR - MOVWF Time_Counter ; reset time_counter - ;Display HR on LCD - call Clear_LCD - ;Move HR to W + MOVFF PORTD, PORTJ ; update LATJ with current value + MOVLW 0xFF + MOVWF PORTH + MOVFF Time_Counter, Count ; move timer count to WREG + ;MOVFF Time_Counter, PORTF + ;MOVWF Count ; Store value in Count for calculation access + CLRF Time_Counter, A ; reset time_counter + ;call Write_HR_LCD + ;call Find_HR_from_Overflow + MOVLW 1 + MULWF Count + call Sixteen_Division + ;call LCD_Write_Hex + ;call Clear_LCD + movlw 100 + cpfslt Count ;if less skip + call Hundred + movff Count, WREG + call Divide_By_Ten + call Ten + movff Count, WREG + addlw '0' call LCD_Send_Byte_HR - ;Move HRZ to W - call LCD_Send_Byte_HRZ + ;for HRZ + ;call LCD_Send_Byte_HRZ + bra Detection_Loop - goto $ - + ;goto $ + +Write_HR_LCD: + lfsr 0, myArray ; Load FSR0 with address in RAM + movlw low highword(HRMessage) ; address of data in PM + movwf TBLPTRU, A ; load upper bits to TBLPTRU + movlw high(HRMessage) ; address of data in PM + movwf TBLPTRH, A ; load high byte to TBLPTRH + movlw low(HRMessage) ; address of data in PM + movwf TBLPTRL, A ; load low byte to TBLPTRL + movlw myTable_l ; bytes to read + movwf counter, A ; our counter register +loop: tblrd*+ ; one byte from PM to TABLAT, increment TBLPRT + movff TABLAT, POSTINC0; move data from TABLAT to (FSR0), inc FSR0 + decfsz counter, A ; count down to zero + bra loop ; keep going until finished + + movlw myTable_l ; output message to LCD + addlw 0xff ; don't send the final carriage return to LCD + lfsr 2, myArray + call LCD_Write_Message + + Find_HR_from_Overflow: MOVFF Count, WREG ; move count to W for multiplication MULLW 8 ; multiply counter with period of timer0, result stored in PRODH:PRODL call Sixteen_Division; denominator stored in PRODH, PRODL return +TMR0_INT: + INCF Time_Counter, 1 + ;MOVFF Time_Counter, PORTH + bcf TMR0IF + + movlw 10000100B ; Fcyc/128 = 125 KHz + movwf T0CON, A + retfie f + +Hundred: + movlw 1 + addlw '0' + call LCD_Send_Byte_HR + movlw 100 + subwf Count, 1 + return +Ten: + addlw '0' + call LCD_Send_Byte_HR + mullw 10 + movff PRODL, WREG + subwf Count, 1 + return + end rst \ No newline at end of file From 846ffd5a6fc5ea2b1de5790df957ab7c06d7b320 Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:02:00 +0000 Subject: [PATCH 26/29] Nested Overflow Counter Added --- RRInterval.s | 6 +++--- Timer.s | 2 +- main.s | 33 +++++++++++++++++++-------------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/RRInterval.s b/RRInterval.s index 7e8fbb70..8112b068 100644 --- a/RRInterval.s +++ b/RRInterval.s @@ -127,10 +127,10 @@ Addition: Sixteen_Division: - MOVLW 0x75 + MOVLW 0x39 MOVWF Num_H - MOVLW 0x30 - MOVWF Num_L ; initiate numerator to 15000 ms + MOVLW 0x71 + MOVWF Num_L ; initiate numerator to 14705 ms ; MOVLW 0x02 ; MOVWF Den_H ; MOVLW 0x58 diff --git a/Timer.s b/Timer.s index 142e64bb..95db18f3 100644 --- a/Timer.s +++ b/Timer.s @@ -21,7 +21,7 @@ psect External_timer, class = CODE ; retfie f Timer_Setup: - movlw 10000100B ; Fcyc/128 = 125 KHz + movlw 10000111B ; Fcyc/256 = 62.5 KHz movwf T0CON, A bsf GIE ;enable all interrupts 7=GIE bsf INTCON, 6 diff --git a/main.s b/main.s index 67c1c4f9..99357472 100644 --- a/main.s +++ b/main.s @@ -14,6 +14,8 @@ counter: ds 1 ; reserve one byte for a counter variable delay_count:ds 1 ; reserve one byte for counter in the delay routine Measured_Zone:ds 1 Time_Counter:ds 1 +OverflowCounter_1:ds 1 +OverflowCounter_2:ds 1 Count:ds 1 HR_Measured:ds 1 ; reserve one byte for measured HR value from sensor HR_max: ds 1 ; the maximum heart rate calculated froma ge @@ -48,7 +50,7 @@ rst: org 0x0 Timer_Interrupt:org 0x0008 btfss TMR0IF retfie f - INCF Time_Counter, 1 + goto Increase_Interrupt bcf TMR0IF movlw 10000100B ; Fcyc/128 = 125 KHz movwf T0CON, A @@ -122,10 +124,10 @@ start: ; call Determine_HRZ ; return with zone number in WREG ; MOVWF PORTB + movlw 0x00 movwf PORTJ, A ; clear checking port Detection_Loop: - ;call Write_HR_LCD movlw 0x00 CPFSGT PORTD ; skip if pulse signal is high bra Update_and_Branch @@ -141,17 +143,12 @@ Signal_Detected: MOVFF PORTD, PORTJ ; update LATJ with current value MOVLW 0xFF MOVWF PORTH - MOVFF Time_Counter, Count ; move timer count to WREG - ;MOVFF Time_Counter, PORTF - ;MOVWF Count ; Store value in Count for calculation access - CLRF Time_Counter, A ; reset time_counter - ;call Write_HR_LCD - ;call Find_HR_from_Overflow + MOVFF OverflowCounter_2, Count ; move timer count to WREG, OverflowCounter increments 1 every 4.08ms + CLRF OverflowCounter_2, A ; reset time_counter MOVLW 1 - MULWF Count + MULWF Count ; this multiplication stores the count in PRODH:PRODL call Sixteen_Division - ;call LCD_Write_Hex - ;call Clear_LCD + movlw 100 cpfslt Count ;if less skip call Hundred @@ -161,8 +158,7 @@ Signal_Detected: movff Count, WREG addlw '0' call LCD_Send_Byte_HR - ;for HRZ - ;call LCD_Send_Byte_HRZ + bra Detection_Loop @@ -187,7 +183,16 @@ loop: tblrd*+ ; one byte from PM to TABLAT, increment TBLPRT addlw 0xff ; don't send the final carriage return to LCD lfsr 2, myArray call LCD_Write_Message - + +Increase_Interrupt: + INCF OverflowCounter_1, 1 + ;MOVFF OverflowCounter_1, WREG + BC Increment_OFC2 ; Branch if carry + return +Increment_OFC2: + INCF OverflowCounter_2, 1 + ;MOVFF OverflowCounter_2, WREG + return Find_HR_from_Overflow: MOVFF Count, WREG ; move count to W for multiplication From affaa92df5890180ba2199b78ac37b0d6d5adba5 Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:31:25 +0000 Subject: [PATCH 27/29] LCD Display working for age input and hr display --- Calculations.s | 74 ++++++++--- Digit_Reader.s | 93 ++++++++----- LCD.s | 54 +++++--- Message.s | 105 +++++++++++++++ RRInterval.s | 14 +- Timer.s | 5 +- main.s | 248 +++++++++++++++++++++++------------ nbproject/configurations.xml | 1 + 8 files changed, 432 insertions(+), 162 deletions(-) create mode 100644 Message.s diff --git a/Calculations.s b/Calculations.s index 2cbe4615..be3ad2d7 100644 --- a/Calculations.s +++ b/Calculations.s @@ -1,6 +1,6 @@ #include -global Find_Max_Heart_Rate, Divide_By_20, Divide_By_Ten, Load_HRZ_Table, Determine_HRZ, IIR_Filter +global Divide_By_20, Divide_By_Ten, Load_HRZ_Table, Divide_By_Hundred, Determine_HRZ, IIR_Filter ; this includes subroutines for calculations: e.g. max heart rate calculation, boundary calculations psect udata_acs @@ -27,11 +27,7 @@ myRem:ds 1 psect calculations_code,class=CODE - -Find_Max_Heart_Rate: - sublw 220 ; subtract age from 220 to find the maximum heart rate, store in WREG - return - + Divide_By_20: ; divide the number stored in WREG by 20 ; Ensure myDenominator is not zero ; MOVWF myNumerator @@ -63,7 +59,7 @@ Subtract: MOVFF myQuotient, PORTD MOVFF myDenominator_low, WREG SUBWFB PRODL, 1 ; myNumerator -= myDenominator - MOVFF PRODL, PORTC + ;MOVFF PRODL, PORTC bra Division_Loop Division_Done: ;MOVFF myQuotient, PORTC @@ -82,11 +78,11 @@ Load_HRZ_Table: ; call with HR_max in WREG BSF EECON1, 2 ; write enable, bit 2 = WREN Loop: - MOVFF EEADR, PORTB + ;MOVFF EEADR, PORTB BSF EECON1, 0 ; read current address, bit 0 = RD nop ; need to have delay after read instruction for reading to complete MOVFF EEDATA, WREG ; W = multiplier - MOVFF EEDATA, PORTC + ;MOVFF EEDATA, PORTC MULWF HR_max CALL Divide_By_20 ; (HR_max*multiplier)/20, return with quotient in WREG @@ -197,20 +193,20 @@ Clear_Ten: ; Perform division algorithm?? Division_Loop_Ten: MOVFF myDenominator_low, WREG - CPFSLT PRODL ; if lower byte is smaller than denominator: need to borrow + CPFSLT myNumerator ; if lower byte is smaller than denominator: need to borrow BRA Subtract_Ten - BRA Borrow_or_Done_Ten -Borrow_or_Done_Ten: - MOVLW 0 - CPFSGT PRODH ; Check if done, i.e. if the upper byte is zero. BRA Division_Done_Ten - DECF PRODH, 1 - ;MOVFF PRODH, PORTB +;Borrow_or_Done_Ten: +; MOVLW 0 +; CPFSGT PRODH ; Check if done, i.e. if the upper byte is zero. +; BRA Division_Done_Ten +; DECF PRODH, 1 +; ;MOVFF PRODH, PORTB Subtract_Ten: INCF myQuotient, 1 - MOVFF myQuotient, PORTD + ;MOVFF myQuotient, PORTD MOVFF myDenominator_low, WREG - SUBWFB PRODL, 1 + SUBWFB myNumerator, 1 ;MOVFF PRODL, PORTC BRA Division_Loop_Ten Division_Done_Ten: @@ -220,6 +216,46 @@ Division_Done_Ten: DivisionError_Ten: RETURN +Divide_By_Hundred: + ; Ensure myDenominator is not zero + MOVWF myNumerator ; enter routine with numerator in WREG +; Think this needs to be n - 1, where n is the denominator?? + MOVLW 99 + MOVWF myDenominator_low ; divide by 20 + + MOVLW 0 + CPFSEQ myDenominator_low + GOTO Clear_Hundred ; Check the MSB of myDenominator + GOTO DivisionError_Hundred ; If zero, handle division by zero +Clear_Hundred: ; Perform division algorithm?? + CLRF myQuotient ; Clear the quotient register + CLRF myRemainder ; Clear the remainder register + +Division_Loop_Hundred: + MOVFF myDenominator_low, WREG + CPFSLT myNumerator ; if lower byte is smaller than denominator: need to borrow + BRA Subtract_Hundred + BRA Division_Done_Hundred +;Borrow_or_Done_Hundred: +; MOVLW 0 +; CPFSGT PRODH ; Check if done, i.e. if the upper byte is zero. +; BRA Division_Done_Hundred +; DECF PRODH, 1 +; ;MOVFF PRODH, PORTB +Subtract_Hundred: + INCF myQuotient, 1 + ;MOVFF myQuotient, PORTD + MOVFF myDenominator_low, WREG + SUBWF myNumerator, 1 + ;MOVFF PRODL, PORTC + BRA Division_Loop_Hundred +Division_Done_Hundred: + ;MOVFF myQuotient, PORTC + MOVFF myQuotient, WREG ; return with the quotient in the WREG + RETURN +DivisionError_Hundred: + RETURN + Division_Loop_1: MOVFF myDen_low, WREG @@ -243,7 +279,7 @@ Subtract_1: MOVFF myQuo, PORTD MOVFF myDen_low, WREG SUBWFB x1x2x3L, 1 ; myNumerator -= myDenominator - MOVFF x1x2x3L, PORTC + ;MOVFF x1x2x3L, PORTC bra Division_Loop_1 Division_Done_1: call Update_Vals diff --git a/Digit_Reader.s b/Digit_Reader.s index eef3e213..e4e95161 100644 --- a/Digit_Reader.s +++ b/Digit_Reader.s @@ -5,8 +5,8 @@ global Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max extrn Keypad_READ extrn delay_ms -;extrn Find_Max_Heart_Rate extrn LCD_Write_Message +extrn age_address_1, age_address_2 psect udata_acs ; reserve data space in access ram first_digit: ds 1 @@ -20,14 +20,15 @@ maximum_heart_rate: ds 1 ; value for maximum heart rate is stored here psect digit_reader_code,class=CODE Age_Read_1: - + movlw age_address_1 + movwf FSR0 movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted call Keypad_READ ; keypad read subroutine, value stored in W call Decode_First_Digit ; decode first digit, return with 10s value in WREG movwf age_first ; save value in variable age_first movwf PORTD ; output to PORTD to visualise the number just inputted - + movlw 0xFF call delay_ms @@ -35,11 +36,17 @@ Age_Read_1: cpfslt age_first ; if no valid input, branch to Age_Read_1 to read from Keypad again; bra Age_Read_1 decf digit_input_counter,1 ; if there has been a valid input, decrement the digit counter and return - call LCD_Write_Message ; digit stored in POSTINC0 + + movlw age_address_1 + movwf FSR2 + movlw 1 ; assume 1 digit + call LCD_Write_Message return Age_Read_2: + movlw age_address_2 + movwf FSR0 movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted call Keypad_READ ; keypad read subroutine, value stored in W @@ -54,13 +61,19 @@ Age_Read_2: cpfslt age_second ; if no valid input, branch to Age_Read_1 to read from Keypad again; bra Age_Read_2 decf digit_input_counter, 1 ; if there has been a valid input, decrement the digit counter and return - call LCD_Write_Message ; digit stored in POSTINC0 + ;call LCD_Write_Message ; digit stored in POSTINC0 movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted + movlw age_address_2 + movwf FSR2 + movlw 1 ; assume 1 digit + call LCD_Write_Message + return Read_Age_Input_Find_HR_Max: ; read in age input from keypad + movlw 2 movwf digit_input_counter @@ -75,7 +88,7 @@ Read_Age_Input_Find_HR_Max: movff age_first, WREG ; move first digit of age to WREG addwf age_second, W ; add second digit to WRED (age_first) and store result in WREG movwf age ; store age in memory - movff age, PORTD + ;movff age, PORTD movlw 0xFF movwf PORTJ @@ -94,12 +107,8 @@ Read_Age_Input_Find_HR_Max: ; find maximum heart rate movff age, WREG ; put age in WREG for use in subroutine - -; call Find_Max_Heart_Rate - movwf maximum_heart_rate ; move value for maximum heart rate into variable - movff maximum_heart_rate, WREG - - return + sublw 220 + return ; return with max HR in WREGs Decode_First_Digit: ; Read input from keypad, interpret as the 10s value, return as literal movwf first_digit, A @@ -113,70 +122,80 @@ Test_0_1: cpfseq first_digit, A bra Test_1_1 movlw '0' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 0 Test_1_1: movlw 0x77 cpfseq first_digit, A bra Test_2_1 movlw '1' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 10 Test_2_1: movlw 0xB7 cpfseq first_digit, A bra Test_3_1 movlw '2' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 20 Test_3_1: movlw 0xD7 cpfseq first_digit, A bra Test_4_1 movlw '3' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 30 Test_4_1: movlw 0x7B cpfseq first_digit, A bra Test_5_1 movlw '4' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 40 Test_5_1: movlw 0xBB cpfseq first_digit, A bra Test_6_1 movlw '5' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 50 Test_6_1: movlw 0xDB cpfseq first_digit, A bra Test_7_1 movlw '6' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 60 Test_7_1: movlw 0x7D cpfseq first_digit, A bra Test_8_1 movlw '7' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 70 Test_8_1: movlw 0xBD cpfseq first_digit, A bra Test_9_1 movlw '8' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 80 Test_9_1: movlw 0xDD cpfseq first_digit, A retlw 0xFF ; error message: when a letter or an invalid input has been detected movlw '9' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 90 @@ -192,70 +211,80 @@ Test_0_2: cpfseq second_digit, A bra Test_1_2 movlw '0' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 0 Test_1_2: movlw 0x77 cpfseq second_digit, A bra Test_2_2 movlw '1' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 1 Test_2_2: movlw 0xB7 cpfseq second_digit, A bra Test_3_2 movlw '2' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 2 Test_3_2: movlw 0xD7 cpfseq second_digit, A bra Test_4_2 movlw '3' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 3 Test_4_2: movlw 0x7B cpfseq second_digit, A bra Test_5_2 movlw '4' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 4 Test_5_2: movlw 0xBB cpfseq second_digit, A bra Test_6_2 movlw '5' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 5 Test_6_2: movlw 0xDB cpfseq second_digit, A bra Test_7_2 movlw '6' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 6 Test_7_2: movlw 0x7D cpfseq second_digit, A bra Test_8_2 movlw '7' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 7 Test_8_2: movlw 0xBD cpfseq second_digit, A bra Test_9_2 movlw '8' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 8 Test_9_2: movlw 0xDD cpfseq second_digit, A retlw 0xFF ; error message: when a letter or an invalid input has been detected movlw '9' - movwf POSTINC0 + movwf INDF0 + incf FSR0 retlw 9 diff --git a/LCD.s b/LCD.s index cef86db6..7aea9f8d 100644 --- a/LCD.s +++ b/LCD.s @@ -1,7 +1,7 @@ #include global LCD_Setup, Write_Welcome, SetTwoLines, LCD_Write_Message, LCD_Write_Hex -global Clear_LCD, LCD_Send_Byte_HR, LCD_Send_Byte_HRZ +global Clear_LCD, LCD_Send_Byte_HR, LCD_Send_Byte_HRZ, LCD_clear, LCD_shift psect udata_acs ; named variables in access ram LCD_cnt_l: ds 1 ; reserve 1 byte for variable LCD_cnt_l LCD_cnt_h: ds 1 ; reserve 1 byte for variable LCD_cnt_h @@ -82,18 +82,23 @@ LCD_Loop_message: decfsz LCD_counter, A bra LCD_Loop_message return - -LCD_Send_Byte_I: ; Transmits byte stored in W to instruction reg - movwf LCD_tmp - swapf LCD_tmp,W ; swap nibbles, high nibble goes first +LCD_shift: + movlw 0011000000B ; entry mode incr by 1 no shift + call LCD_Send_Byte_I + movlw 10 ; wait 40us + call LCD_delay_x4us + return +LCD_Send_Byte_I: ; Transmits byte stored in W to instruction reg + movwf LCD_tmp, A + swapf LCD_tmp, W, A ; swap nibbles, high nibble goes first andlw 0x0f ; select just low nibble - movwf LATB ; output data bits to LCD - bcf LATB, LCD_RS ; Instruction write clear RS bit + movwf LATB, A ; output data bits to LCD + bcf LATB, LCD_RS, A ; Instruction write clear RS bit call LCD_Enable ; Pulse enable Bit - movf LCD_tmp,W ; swap nibbles, now do low nibble + movf LCD_tmp, W, A ; swap nibbles, now do low nibble andlw 0x0f ; select just low nibble - movwf LATB ; output data bits to LCD - bcf LATB, LCD_RS ; Instruction write clear RS bit + movwf LATB, A ; output data bits to LCD + bcf LATB, LCD_RS, A ; Instruction write clear RS bit call LCD_Enable ; Pulse enable Bit return @@ -153,23 +158,29 @@ loop: tblrd*+ ; one byte from PM to TABLAT, increment TBLPRT addlw 0xff ; don't send the final carriage return to LCD lfsr 2, myArray call LCD_Write_Message - - -LCD_Send_Byte_D: ; Transmits byte stored in W to data reg - movwf LCD_tmp - swapf LCD_tmp,W ; swap nibbles, high nibble goes first + +LCD_Send_Byte_D: ; Transmits byte stored in W to data reg + movwf LCD_tmp, A + swapf LCD_tmp, W, A ; swap nibbles, high nibble goes first andlw 0x0f ; select just low nibble - movwf LATB ; output data bits to LCD - bsf LATB, LCD_RS ; Data write set RS bit + movwf LATB, A ; output data bits to LCD + bsf LATB, LCD_RS, A ; Data write set RS bit call LCD_Enable ; Pulse enable Bit - movf LCD_tmp,W ; swap nibbles, now do low nibble + movf LCD_tmp, W, A ; swap nibbles, now do low nibble andlw 0x0f ; select just low nibble - movwf LATB ; output data bits to LCD - bsf LATB, LCD_RS ; Data write set RS bit + movwf LATB, A ; output data bits to LCD + bsf LATB, LCD_RS, A ; Data write set RS bit call LCD_Enable ; Pulse enable Bit movlw 10 ; delay 40us call LCD_delay_x4us return + +LCD_clear: + movlw 00000001B ; display clear + call LCD_Send_Byte_I + movlw 2 ; wait 2ms + call LCD_delay_ms + return SetTwoLines: movlw 11000000B @@ -226,3 +237,6 @@ lcdlp1: decf LCD_cnt_l, F, A ; no carry when 0x00 -> 0xff end + + + \ No newline at end of file diff --git a/Message.s b/Message.s new file mode 100644 index 00000000..acee9843 --- /dev/null +++ b/Message.s @@ -0,0 +1,105 @@ +#include + +global Heart_Rate_Zone_Msg, Heart_Rate_Msg, Welcome_Msg + +extrn hr_msg, hrz_msg, welcome_msg + +psect Messages, class = CODE + +Heart_Rate_Msg: + movlw hr_msg + movwf FSR0 + + movlw 'H' + movwf INDF0 + incf FSR0 + movlw 'e' + movwf INDF0 + incf FSR0 + movlw 'a' + movwf INDF0 + incf FSR0 + movlw 'r' + movwf INDF0 + incf FSR0 + movlw 't' + movwf INDF0 + incf FSR0 + movlw ' ' + movwf INDF0 + incf FSR0 + movlw 'R' + movwf INDF0 + incf FSR0 + movlw 'a' + movwf INDF0 + incf FSR0 + movlw 't' + movwf INDF0 + incf FSR0 + movlw 'e' + movwf INDF0 + incf FSR0 + movlw ':' + movwf INDF0 + incf FSR0 + return + +Heart_Rate_Zone_Msg: + movlw hrz_msg + movwf FSR0 + + movlw 'Z' + movwf INDF0 + incf FSR0 + movlw 'o' + movwf INDF0 + incf FSR0 + movlw 'n' + movwf INDF0 + incf FSR0 + movlw 'e' + movwf INDF0 + incf FSR0 + movlw ':' + movwf INDF0 + incf FSR0 + return + +Welcome_Msg: + movlw welcome_msg + movwf FSR0 + + movlw 'I' + movwf INDF0 + incf FSR0 + movlw 'n' + movwf INDF0 + incf FSR0 + movlw 'p' + movwf INDF0 + incf FSR0 + movlw 'u' + movwf INDF0 + incf FSR0 + movlw 't' + movwf INDF0 + incf FSR0 + movlw ' ' + movwf INDF0 + incf FSR0 + movlw 'A' + movwf INDF0 + incf FSR0 + movlw 'g' + movwf INDF0 + incf FSR0 + movlw 'e' + movwf INDF0 + incf FSR0 + movlw ':' + movwf INDF0 + incf FSR0 + return + + diff --git a/RRInterval.s b/RRInterval.s index 8112b068..4c0949ce 100644 --- a/RRInterval.s +++ b/RRInterval.s @@ -77,7 +77,7 @@ Subtract_no: movff CCPR5L, WREG movwf prevtimeL bcf PIR4, 2 ;clear CCP interrupt flag - movff periodL, PORTF + ;movff periodL, PORTF retfie f overflow: @@ -121,7 +121,7 @@ Addition: movwf prevtimeL bcf PIR4, 2 ;clear CCP interrupt flag bcf PIR1, 2 - movff periodL, PORTF + ;movff periodL, PORTF retfie f @@ -135,9 +135,15 @@ Sixteen_Division: ; MOVWF Den_H ; MOVLW 0x58 ; MOVWF Den_L - MOVLW 0 MOVWF Heart_Rate ; initialise quotient +Check_for_zero: + MOVLW 0 + CPFSEQ PRODL + bra High_byte_check + CPFSEQ PRODH + bra High_byte_check + bra End_Sixteen_Division High_byte_check: MOVFF PRODH, WREG CPFSGT Num_H @@ -163,7 +169,7 @@ Sixteen_Borrow: bra End_Sixteen_Division bra Sixteen_Subtraction End_Sixteen_Division: - MOVFF Heart_Rate, PORTC + ;MOVFF Heart_Rate, PORTC MOVFF Heart_Rate, WREG ; move results into results register pair return ; return with Heart Rate in WREG diff --git a/Timer.s b/Timer.s index 95db18f3..9bf1212f 100644 --- a/Timer.s +++ b/Timer.s @@ -21,11 +21,14 @@ psect External_timer, class = CODE ; retfie f Timer_Setup: - movlw 10000111B ; Fcyc/256 = 62.5 KHz + movlw 10000100B ; Fcyc/256 = 62.5 KHz movwf T0CON, A bsf GIE ;enable all interrupts 7=GIE bsf INTCON, 6 bsf INTCON, 5 ;TMR0IE return + + + \ No newline at end of file diff --git a/main.s b/main.s index 99357472..2c666972 100644 --- a/main.s +++ b/main.s @@ -1,13 +1,14 @@ #include ;extrn UART_Setup, UART_Transmit_Message ; external subroutines -extrn LCD_Setup, Clear_LCD, LCD_Send_Byte_HR, LCD_Send_Byte_HRZ, LCD_Write_Message, LCD_Write_Hex +extrn LCD_Setup, Clear_LCD, LCD_Send_Byte_HR, LCD_Send_Byte_HRZ, LCD_Write_Message, LCD_Write_Hex, LCD_clear, LCD_shift extrn Keypad_INIT, Keypad_READ, delay_ms extrn Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max -extrn Find_Max_Heart_Rate, Divide_By_20, Divide_By_Ten, Load_HRZ_Table, Determine_HRZ, IIR_Filter -extrn Timer_Setup +extrn Divide_By_20, Divide_By_Ten, Load_HRZ_Table, Determine_HRZ, IIR_Filter +extrn Timer_Setup, Divide_By_Hundred extrn no_overflow, overflow, Sixteen_Division - +extrn Heart_Rate_Zone_Msg, Heart_Rate_Msg, Welcome_Msg +global hr_msg, hrz_msg, welcome_msg, age_address_1, age_address_2 psect udata_acs ; reserve data space in access ram counter: ds 1 ; reserve one byte for a counter variable @@ -17,6 +18,10 @@ Time_Counter:ds 1 OverflowCounter_1:ds 1 OverflowCounter_2:ds 1 Count:ds 1 +hundred_digit:ds 1 +ten_digit:ds 1 +single_digit:ds 1 +HR_Zone:ds 1 HR_Measured:ds 1 ; reserve one byte for measured HR value from sensor HR_max: ds 1 ; the maximum heart rate calculated froma ge HR_max_20: ds 1 ; the quotient of HR_max divided by 20 @@ -25,7 +30,14 @@ TABLE_INDEX_DIFF:ds 1 ; variable used to check end of loop condition STATUS_CHECK:ds 1 ; use this in loop to check if the end of loop as been reached TABLE_START_ADDRESS EQU 0xA0 ; table start address for HRZ boundary values TABLE_SIZE EQU 8 ; this value needs to be n+1, where n is how many times you want to read/write the table - +hr_msg EQU 0xE0 +hrz_msg EQU 0xF0 +measured_heart_rate_address EQU 0xD0 +measured_heart_rate_zone_address EQU 0xC0 +welcome_msg EQU 0xB0 +age_address_1 EQU 0xA0 +age_address_2 EQU 0xA1 + psect udata_bank4 ; reserve data anywhere in RAM (here at 0x400) myArray: ds 0x80 ; reserve 128 bytes for message data @@ -50,7 +62,7 @@ rst: org 0x0 Timer_Interrupt:org 0x0008 btfss TMR0IF retfie f - goto Increase_Interrupt + call Increase_Interrupt bcf TMR0IF movlw 10000100B ; Fcyc/128 = 125 KHz movwf T0CON, A @@ -60,19 +72,18 @@ Timer_Interrupt:org 0x0008 setup: bcf CFGS ; point to Flash program memory bsf EEPGD ; access Flash program memory ;call UART_Setup ; setup UART - ;call Keypad_INIT ; setup keypad + call Keypad_INIT ; setup keypad movlw 0x00 - movwf Time_Counter ; Initialise Time_Counter + movwf OverflowCounter_1 ; Initialise Time_Counter + movwf OverflowCounter_2 call Timer_Setup call LCD_Setup - - ;bsf INTCON, 4 -; bsf PIE4, 2 -; bsf ODCON2, 2 -; clrf TMR1H -; clrf TMR1L + ; load messages into database + call Heart_Rate_Msg + call Heart_Rate_Zone_Msg + call Welcome_Msg movlw 0x00 movwf TRISH @@ -97,13 +108,24 @@ setup: bcf CFGS ; point to Flash program memory ; ******* Main programme **************************************** start: - ;call Write_Welcome - ;bra SetTwoLines - ;call Read_Age_Input_Find_HR_Max ; return with W = HRmax - ;movwf HR_max + call LCD_clear + movlw welcome_msg + movwf FSR2 + movlw 10 ; because there are 11 letters + call LCD_Write_Message + call LCD_shift + + nop + nop + + call Read_Age_Input_Find_HR_Max ; return with W = HRmax + movwf HR_max + movff HR_max, PORTF - ;movlw 10 ; FICTITOUS HR MAX FOR TESTING - ;call Load_HRZ_Table + call Load_HRZ_Table + + nop + nop ;call Determine_HRZ ; Zone value stored in WREG ;MOVWF Measured_Zone @@ -112,22 +134,10 @@ start: ; heart rate measurement here - - ; call Sixteen_Division - - ; IIR Filter: subroutine is entered with most recent measurement in WREG, outputs the averaged value - - ; MOVLW 0x64 ;Fictitious HR = 100 - ; call IIR_Filter ; Output_HR = average of past 3 measurements - - ; sift through HRZ_Table and find the relevant heart rate zone, with measured HR in WREG - ; call Determine_HRZ ; return with zone number in WREG - ; MOVWF PORTB - - movlw 0x00 movwf PORTJ, A ; clear checking port Detection_Loop: + movlw 0x00 CPFSGT PORTD ; skip if pulse signal is high bra Update_and_Branch @@ -143,50 +153,90 @@ Signal_Detected: MOVFF PORTD, PORTJ ; update LATJ with current value MOVLW 0xFF MOVWF PORTH - MOVFF OverflowCounter_2, Count ; move timer count to WREG, OverflowCounter increments 1 every 4.08ms - CLRF OverflowCounter_2, A ; reset time_counter - MOVLW 1 - MULWF Count ; this multiplication stores the count in PRODH:PRODL - call Sixteen_Division - - movlw 100 - cpfslt Count ;if less skip - call Hundred - movff Count, WREG - call Divide_By_Ten - call Ten - movff Count, WREG - addlw '0' - call LCD_Send_Byte_HR - + + ;still need to calculate heart rate from here + movff OverflowCounter_1, WREG + mullw 8 + MOVFF PRODL, HR_Measured ; move timer count to WREG, OverflowCounter increments 1 every 4.08ms - bra Detection_Loop + ; write to LCD + MOVFF HR_Measured, WREG + call Load_Measured_Heart_Rate ; load heart rate into database + + call LCD_clear + movlw hr_msg + movwf FSR2 + movlw 11 ; because there are 11 letters + call LCD_Write_Message - ;goto $ - -Write_HR_LCD: - lfsr 0, myArray ; Load FSR0 with address in RAM - movlw low highword(HRMessage) ; address of data in PM - movwf TBLPTRU, A ; load upper bits to TBLPTRU - movlw high(HRMessage) ; address of data in PM - movwf TBLPTRH, A ; load high byte to TBLPTRH - movlw low(HRMessage) ; address of data in PM - movwf TBLPTRL, A ; load low byte to TBLPTRL - movlw myTable_l ; bytes to read - movwf counter, A ; our counter register -loop: tblrd*+ ; one byte from PM to TABLAT, increment TBLPRT - movff TABLAT, POSTINC0; move data from TABLAT to (FSR0), inc FSR0 - decfsz counter, A ; count down to zero - bra loop ; keep going until finished - - movlw myTable_l ; output message to LCD - addlw 0xff ; don't send the final carriage return to LCD - lfsr 2, myArray + ; write heart rate + movlw measured_heart_rate_address + movwf FSR2 + movlw 3 ; assume 3 digits + call LCD_Write_Message ; Display the number + call LCD_shift + + CLRF OverflowCounter_1, A ; reset time_counter + +; MOVFF HR_Measured, WREG +; call Determine_HRZ ; return with zone number in WREG + movlw 5 + call Load_Measured_Heart_Rate_Zone + + ; write hr zone prompt + movlw hrz_msg + movwf FSR2 + movlw 5 ; because there are 5 letters call LCD_Write_Message + + ; write zone information + movlw measured_heart_rate_zone_address + movwf FSR2 + movlw 1 + call LCD_Write_Message ; Display the number + ;call LCD_shift + + bra Detection_Loop + + + ; IIR Filter: subroutine is entered with most recent measurement in WREG, outputs the averaged value + + ; MOVLW 0x64 ;Fictitious HR = 100 + ; call IIR_Filter ; Output_HR = average of past 3 measurements + + ; sift through HRZ_Table and find the relevant heart rate zone, with measured HR in WREG + ; call Determine_HRZ ; return with zone number in WREG + + + +; movlw 125 +; call Load_Measured_Heart_Rate +; +; movlw 5 +; call Load_Measured_Heart_Rate_Zone +; + + ; write hr zone prompt +; movlw hrz_msg +; movwf FSR2 +; movlw 5 ; because there are 5 letters +; call LCD_Write_Message +; +; ; write zone information +; movlw measured_heart_rate_zone_address +; movwf FSR2 +; movlw 1 +; call LCD_Write_Message ; Display the number +; call LCD_shift + + + + goto $ Increase_Interrupt: INCF OverflowCounter_1, 1 - ;MOVFF OverflowCounter_1, WREG + MOVFF OverflowCounter_1, WREG + MOVFF OverflowCounter_1, PORTC BC Increment_OFC2 ; Branch if carry return Increment_OFC2: @@ -200,29 +250,55 @@ Find_HR_from_Overflow: call Sixteen_Division; denominator stored in PRODH, PRODL return -TMR0_INT: - INCF Time_Counter, 1 - ;MOVFF Time_Counter, PORTH - bcf TMR0IF +Load_Measured_Heart_Rate_Zone: + movwf HR_Zone - movlw 10000100B ; Fcyc/128 = 125 KHz - movwf T0CON, A - retfie f - -Hundred: - movlw 1 + movlw measured_heart_rate_zone_address + movwf FSR0 + + movff HR_Zone, WREG addlw '0' - call LCD_Send_Byte_HR - movlw 100 - subwf Count, 1 + call Write_to_FSR return -Ten: + +Load_Measured_Heart_Rate: ; enter with measured heart rate in WREG + movwf Count + + movlw measured_heart_rate_address + movwf FSR0 + + movff Count, WREG + call Divide_By_Hundred ; return with quotient in WREG + movwf hundred_digit + movff hundred_digit, WREG + addlw '0' + call Write_to_FSR + movff hundred_digit, WREG + mullw 100 ; subtract hundred digit + movff PRODL, WREG + subwf Count, 1 ; Count - PRODL (the hundred digit), store in Count + + movff Count, WREG + call Divide_By_Ten + movwf ten_digit + movff ten_digit, WREG addlw '0' - call LCD_Send_Byte_HR + call Write_to_FSR + movff ten_digit, WREG mullw 10 movff PRODL, WREG subwf Count, 1 + + movff Count, WREG + addlw '0' + call Write_to_FSR + return + +Write_to_FSR: + movwf INDF0 + incf FSR0 return + end rst \ No newline at end of file diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 05bc6ef4..77fa66aa 100755 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -21,6 +21,7 @@ Calculations.s RRInterval.s Timer.s + Message.s Date: Wed, 13 Dec 2023 15:41:43 +0000 Subject: [PATCH 28/29] Loop routine formatted --- main.s | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/main.s b/main.s index 2c666972..068d4763 100644 --- a/main.s +++ b/main.s @@ -73,17 +73,16 @@ setup: bcf CFGS ; point to Flash program memory bsf EEPGD ; access Flash program memory ;call UART_Setup ; setup UART call Keypad_INIT ; setup keypad - - movlw 0x00 - movwf OverflowCounter_1 ; Initialise Time_Counter - movwf OverflowCounter_2 - call Timer_Setup call LCD_Setup ; load messages into database call Heart_Rate_Msg call Heart_Rate_Zone_Msg call Welcome_Msg + + movlw 0x00 + movwf OverflowCounter_1 ; Initialise Time_Counter + movwf OverflowCounter_2 movlw 0x00 movwf TRISH @@ -112,28 +111,17 @@ start: movlw welcome_msg movwf FSR2 movlw 10 ; because there are 11 letters - call LCD_Write_Message + call LCD_Write_Message ; write welcome messgae, prompt age input call LCD_shift - nop - nop - call Read_Age_Input_Find_HR_Max ; return with W = HRmax movwf HR_max - movff HR_max, PORTF + ;movlw 3 call Load_HRZ_Table - - nop - nop - - ;call Determine_HRZ ; Zone value stored in WREG - ;MOVWF Measured_Zone - - ; call overflow - ; heart rate measurement here - - + + call Timer_Setup ; this needs to happen after loading HRZ table, because interrupts interfere with eeprom + movlw 0x00 movwf PORTJ, A ; clear checking port Detection_Loop: @@ -178,9 +166,9 @@ Signal_Detected: CLRF OverflowCounter_1, A ; reset time_counter -; MOVFF HR_Measured, WREG -; call Determine_HRZ ; return with zone number in WREG - movlw 5 + MOVFF HR_Measured, WREG + call Determine_HRZ ; return with zone number in WREG + ;movlw 5 call Load_Measured_Heart_Rate_Zone ; write hr zone prompt From f99fa621c29ff175fdd5851367be3a852be099aa Mon Sep 17 00:00:00 2001 From: minniewang12 <137521170+minniewang12@users.noreply.github.com> Date: Fri, 15 Dec 2023 10:29:48 +0000 Subject: [PATCH 29/29] Final Code Update Final Code update --- Calculations.s | 136 ++++++++++++++++++++++++------------------------- Digit_Reader.s | 1 - LCD.s | 6 +-- RRInterval.s | 6 +-- Timer.s | 3 +- UART.s | 2 +- main.s | 86 ++++++++++++++----------------- 7 files changed, 110 insertions(+), 130 deletions(-) diff --git a/Calculations.s b/Calculations.s index be3ad2d7..96b2966a 100644 --- a/Calculations.s +++ b/Calculations.s @@ -1,7 +1,7 @@ #include global Divide_By_20, Divide_By_Ten, Load_HRZ_Table, Divide_By_Hundred, Determine_HRZ, IIR_Filter - +global measured_heart_rate_zone_address, heart_rate_zone_address ; this includes subroutines for calculations: e.g. max heart rate calculation, boundary calculations psect udata_acs myDenominator_low:ds 1 @@ -53,7 +53,7 @@ Borrow_or_Done: CPFSGT PRODH ; Check if done, i.e. if the upper byte is zero. bra Division_Done DECF PRODH, 1 ; Borrow from higher byte - MOVFF PRODH, PORTB + ;sMOVFF PRODH, PORTB Subtract: INCF myQuotient, 1 ; Increment quotient MOVFF myQuotient, PORTD @@ -72,10 +72,14 @@ DivisionError: Load_HRZ_Table: ; call with HR_max in WREG MOVWF HR_max + movlw heart_rate_zone_address + movwf FSR0 + CLRF EEADR ; start at address 0 BCF EECON1, 6 ; set for memory, bit 6 = CFGS BCF EECON1, 7 ; set for data EEPROM, bit 7 = EEPGD - BSF EECON1, 2 ; write enable, bit 2 = WREN + ;BSF EECON1, 2 ; write enable, bit 2 = WREN + ;BCF INTCON, 7 ; disable interrupts, bit 7 = GIE Loop: ;MOVFF EEADR, PORTB @@ -87,18 +91,19 @@ Loop: CALL Divide_By_20 ; (HR_max*multiplier)/20, return with quotient in WREG - MOVWF EEDATA ; move data to EE - - BCF INTCON, 7 ; disable interrupts, bit 7 = GIE - - MOVLW 0x55 - MOVWF EECON2 - MOVLW 0xAA - MOVWF EECON2 + MOVWF INDF0 + INCF FSR0 - BSF EECON1, 1 ; to write data, bit 1 = WR - BTFSC EECON1, 1 - bra $-2 ; wait for write to complete +; MOVWF EEDATA ; move data to EE +; +; MOVLW 0x55 +; MOVWF EECON2 +; MOVLW 0xAA +; MOVWF EECON2 +; +; BSF EECON1, 1 ; to write data, bit 1 = WR +; BTFSC EECON1, 1 +; bra $-2 ; wait for write to complete INCF EEADR, 1 ; Increment address and save back to EEADR MOVFF EEADR, WREG ; Routine to check if the end has been reached @@ -110,7 +115,7 @@ Loop: bra End_Write End_Write: ; Continue on with the rest of the code - BCF EECON1, 2 ; disenable writing function + ;BCF EECON1, 2 ; disenable writing function MOVLW 0xFF MOVWF PORTD RETURN @@ -118,23 +123,18 @@ End_Write: Determine_HRZ: ; enter with measured HR stored in WREG movwf HR_Measured + movlw heart_rate_zone_address + movwf FSR2 + MOVLW 6 MOVWF Zone_Value ; initialise at 6, highest possible zone value is 5 - - CLRF EEADR ; start at address 0 - BCF EECON1, 6 ; set for memory, bit 6 = CFGS - BCF EECON1, 7 ; set for data EEPROM, bit 7 = EEPGD - BCF EECON1, 2 ; write enable, bit 2 = WREN + Table_Compare_Loop: - MOVFF EEADR, PORTB - BSF EECON1, 0 ; read current address, bit 0 = RD - nop ; need to have delay after read instruction for reading to complete - MOVFF EEDATA, WREG ; zone boundary - CPFSLT HR_Measured ; f < W + MOVF POSTINC2, W, A ; move heart rate to WREG + CPFSLT HR_Measured ; skip if f < W bra Output_Zone_Value - DECF Zone_Value, 1 - INCF EEADR, 1 - bra Table_Compare_Loop + decfsz Zone_Value + bra Table_Compare_Loop Output_Zone_Value: MOVFF Zone_Value, WREG return @@ -174,8 +174,44 @@ IIR_Filter: GOTO DivisionError_1 ; If zero, handle division by zero Clear_1: ; Perform division algorithm CLRF myQuo ; Clear the quotient register - CLRF myRem ; Clear the remainder register - + CLRF myRem ; Clear the remainder register +Division_Loop_1: + MOVFF myDen_low, WREG + CPFSLT x1x2x3L ; if lower byte is smaller than denominator: need to borrow + bra Check_Equal + bra Borrow_or_Done_1 +Borrow_or_Done_1: + MOVLW 0 + CPFSGT x1x2x3H ; Check if done, i.e. if the upper byte is zero. + bra Division_Done_1 + DECF x1x2x3H, 1 ; Borrow from higher byte + ;MOVFF x1x2x3H, PORTB + bra Subtract_1 +Check_Equal: + MOVFF myDen_low, WREG + CPFSEQ x1x2x3L + bra Subtract_1 + bra Borrow_or_Done_1 +Subtract_1: + INCF myQuo, 1 ; Increment quotient + MOVFF myQuo, PORTD + MOVFF myDen_low, WREG + SUBWFB x1x2x3L, 1 ; myNumerator -= myDenominator + ;MOVFF x1x2x3L, PORTC + bra Division_Loop_1 +Division_Done_1: + bra Update_Vals + MOVFF myQuo, WREG ; 656/4 = 164 ... + RETURN +DivisionError_1: + RETURN +Update_Vals: + MOVFF x2, WREG + MOVWF x1 ; update x1 with value in x2 + MOVFF myQuo, WREG + MOVWF x2 ; update x2 with newest measurement + return + Divide_By_Ten: ; Ensure myDenominator is not zero MOVWF myNumerator @@ -255,45 +291,5 @@ Division_Done_Hundred: RETURN DivisionError_Hundred: RETURN - - -Division_Loop_1: - MOVFF myDen_low, WREG - CPFSLT x1x2x3L ; if lower byte is smaller than denominator: need to borrow - bra Check_Equal - bra Borrow_or_Done_1 -Borrow_or_Done_1: - MOVLW 0 - CPFSGT x1x2x3H ; Check if done, i.e. if the upper byte is zero. - bra Division_Done - DECF x1x2x3H, 1 ; Borrow from higher byte - ;MOVFF x1x2x3H, PORTB - bra Subtract_1 -Check_Equal: - MOVFF myDen_low, WREG - CPFSEQ x1x2x3L - bra Subtract_1 - bra Borrow_or_Done_1 -Subtract_1: - INCF myQuo, 1 ; Increment quotient - MOVFF myQuo, PORTD - MOVFF myDen_low, WREG - SUBWFB x1x2x3L, 1 ; myNumerator -= myDenominator - ;MOVFF x1x2x3L, PORTC - bra Division_Loop_1 -Division_Done_1: - call Update_Vals - MOVFF myQuo, WREG ; 656/4 = 164 ... - RETURN -DivisionError_1: - RETURN -Update_Vals: - MOVFF x2, WREG - MOVWF x1 ; update x1 with value in x2 - MOVFF myQuo, WREG - MOVWF x2 ; update x2 with newest measurement - return - - \ No newline at end of file diff --git a/Digit_Reader.s b/Digit_Reader.s index e4e95161..1f90fd24 100644 --- a/Digit_Reader.s +++ b/Digit_Reader.s @@ -61,7 +61,6 @@ Age_Read_2: cpfslt age_second ; if no valid input, branch to Age_Read_1 to read from Keypad again; bra Age_Read_2 decf digit_input_counter, 1 ; if there has been a valid input, decrement the digit counter and return - ;call LCD_Write_Message ; digit stored in POSTINC0 movff digit_input_counter, PORTJ ; output digit counter to PORTJ to visualise how many digits are left to be inputted movlw age_address_2 diff --git a/LCD.s b/LCD.s index 7aea9f8d..1a1c001b 100644 --- a/LCD.s +++ b/LCD.s @@ -74,7 +74,7 @@ LCD_Hex_Nib: ; writes low nibble as hex character call LCD_Send_Byte_D ; write out ascii return -LCD_Write_Message: ; Message stored at FSR2, length stored in W +LCD_Write_Message: ; Message address stored at FSR2, length stored in W movwf LCD_counter, A LCD_Loop_message: movf POSTINC2, W, A @@ -82,6 +82,7 @@ LCD_Loop_message: decfsz LCD_counter, A bra LCD_Loop_message return + LCD_shift: movlw 0011000000B ; entry mode incr by 1 no shift call LCD_Send_Byte_I @@ -237,6 +238,3 @@ lcdlp1: decf LCD_cnt_l, F, A ; no carry when 0x00 -> 0xff end - - - \ No newline at end of file diff --git a/RRInterval.s b/RRInterval.s index 4c0949ce..cf4f8e57 100644 --- a/RRInterval.s +++ b/RRInterval.s @@ -127,10 +127,10 @@ Addition: Sixteen_Division: - MOVLW 0x39 + MOVLW 0xEA MOVWF Num_H - MOVLW 0x71 - MOVWF Num_L ; initiate numerator to 14705 ms + MOVLW 0x60 + MOVWF Num_L ; initiate numerator to 60000 ms ; MOVLW 0x02 ; MOVWF Den_H ; MOVLW 0x58 diff --git a/Timer.s b/Timer.s index 9bf1212f..8679d768 100644 --- a/Timer.s +++ b/Timer.s @@ -21,13 +21,12 @@ psect External_timer, class = CODE ; retfie f Timer_Setup: - movlw 10000100B ; Fcyc/256 = 62.5 KHz + movlw 10000011B ; Fcyc/256 = 62.5 KHz movwf T0CON, A bsf GIE ;enable all interrupts 7=GIE bsf INTCON, 6 bsf INTCON, 5 ;TMR0IE return - diff --git a/UART.s b/UART.s index 32bf8df9..19b80024 100644 --- a/UART.s +++ b/UART.s @@ -1,6 +1,6 @@ #include -global UART_Setup, UART_Transmit_Message +global UART_Setup, UART_Transmit_Message, UART_Transmit_Byte psect udata_acs ; reserve data space in access ram UART_counter: ds 1 ; reserve 1 byte for variable UART_counter diff --git a/main.s b/main.s index 068d4763..50be2a79 100644 --- a/main.s +++ b/main.s @@ -1,6 +1,6 @@ #include -;extrn UART_Setup, UART_Transmit_Message ; external subroutines +extrn UART_Setup, UART_Transmit_Message, UART_Transmit_Byte ; external subroutines extrn LCD_Setup, Clear_LCD, LCD_Send_Byte_HR, LCD_Send_Byte_HRZ, LCD_Write_Message, LCD_Write_Hex, LCD_clear, LCD_shift extrn Keypad_INIT, Keypad_READ, delay_ms extrn Decode_First_Digit, Decode_Second_Digit, Read_Age_Input_Find_HR_Max @@ -8,7 +8,7 @@ extrn Divide_By_20, Divide_By_Ten, Load_HRZ_Table, Determine_HRZ, IIR_Filter extrn Timer_Setup, Divide_By_Hundred extrn no_overflow, overflow, Sixteen_Division extrn Heart_Rate_Zone_Msg, Heart_Rate_Msg, Welcome_Msg -global hr_msg, hrz_msg, welcome_msg, age_address_1, age_address_2 +global hr_msg, hrz_msg, welcome_msg, age_address_1, age_address_2, heart_rate_zone_address, measured_heart_rate_zone_address psect udata_acs ; reserve data space in access ram counter: ds 1 ; reserve one byte for a counter variable @@ -37,6 +37,7 @@ measured_heart_rate_zone_address EQU 0xC0 welcome_msg EQU 0xB0 age_address_1 EQU 0xA0 age_address_2 EQU 0xA1 +heart_rate_zone_address EQU 0xC2 psect udata_bank4 ; reserve data anywhere in RAM (here at 0x400) myArray: ds 0x80 ; reserve 128 bytes for message data @@ -64,16 +65,17 @@ Timer_Interrupt:org 0x0008 retfie f call Increase_Interrupt bcf TMR0IF - movlw 10000100B ; Fcyc/128 = 125 KHz + movlw 10000011B ; Fcyc/128 = 125 KHz movwf T0CON, A retfie f ; ******* Programme FLASH read Setup Code *********************** setup: bcf CFGS ; point to Flash program memory bsf EEPGD ; access Flash program memory - ;call UART_Setup ; setup UART + call UART_Setup ; setup UART call Keypad_INIT ; setup keypad call LCD_Setup + call Timer_Setup ; load messages into database call Heart_Rate_Msg @@ -90,8 +92,8 @@ setup: bcf CFGS ; point to Flash program memory movlw 0x00 movwf TRISF - movlw 0x00 - movwf TRISC +; movlw 0x00 +; movwf TRISC movlw 0xFF movwf TRISD @@ -116,8 +118,7 @@ start: call Read_Age_Input_Find_HR_Max ; return with W = HRmax movwf HR_max - - ;movlw 3 + movlw 121 call Load_HRZ_Table call Timer_Setup ; this needs to happen after loading HRZ table, because interrupts interfere with eeprom @@ -144,31 +145,43 @@ Signal_Detected: ;still need to calculate heart rate from here movff OverflowCounter_1, WREG - mullw 8 - MOVFF PRODL, HR_Measured ; move timer count to WREG, OverflowCounter increments 1 every 4.08ms - + mullw 66 + call Sixteen_Division + MOVWF HR_Measured + + ;MOVFF PRODL, HR_Measured ; move timer count to WREG, OverflowCounter increments 1 every 4.08ms + ;MOVFF HR_Measured, WREG + call IIR_Filter ; Output_HR = average of past 3 measurements ; write to LCD - MOVFF HR_Measured, WREG - call Load_Measured_Heart_Rate ; load heart rate into database + call Load_Measured_Heart_Rate ; load heart rate into database call LCD_clear + movlw hr_msg movwf FSR2 movlw 11 ; because there are 11 letters call LCD_Write_Message - ; write heart rate + ; write heart rate to LCD movlw measured_heart_rate_address movwf FSR2 movlw 3 ; assume 3 digits call LCD_Write_Message ; Display the number call LCD_shift + ; write heart rate to UART + movlw measured_heart_rate_address + movwf FSR2 + movlw 3 + call UART_Transmit_Message + CLRF OverflowCounter_1, A ; reset time_counter + movlw ',' + call UART_Transmit_Byte + MOVFF HR_Measured, WREG call Determine_HRZ ; return with zone number in WREG - ;movlw 5 call Load_Measured_Heart_Rate_Zone ; write hr zone prompt @@ -182,49 +195,24 @@ Signal_Detected: movwf FSR2 movlw 1 call LCD_Write_Message ; Display the number - ;call LCD_shift - - bra Detection_Loop - + call LCD_shift - ; IIR Filter: subroutine is entered with most recent measurement in WREG, outputs the averaged value - - ; MOVLW 0x64 ;Fictitious HR = 100 - ; call IIR_Filter ; Output_HR = average of past 3 measurements - - ; sift through HRZ_Table and find the relevant heart rate zone, with measured HR in WREG - ; call Determine_HRZ ; return with zone number in WREG - + movlw measured_heart_rate_zone_address + movwf FSR2 + movlw 1 + call UART_Transmit_Message + movlw 0x0A + call UART_Transmit_Byte -; movlw 125 -; call Load_Measured_Heart_Rate -; -; movlw 5 -; call Load_Measured_Heart_Rate_Zone -; - ; write hr zone prompt -; movlw hrz_msg -; movwf FSR2 -; movlw 5 ; because there are 5 letters -; call LCD_Write_Message -; -; ; write zone information -; movlw measured_heart_rate_zone_address -; movwf FSR2 -; movlw 1 -; call LCD_Write_Message ; Display the number -; call LCD_shift + bra Detection_Loop - - - goto $ Increase_Interrupt: INCF OverflowCounter_1, 1 MOVFF OverflowCounter_1, WREG - MOVFF OverflowCounter_1, PORTC + MOVFF OverflowCounter_1, LATH BC Increment_OFC2 ; Branch if carry return Increment_OFC2: