$MOD51 ;$INCLUDE (89S52.MCU) $TITLE (RPMPRTO.ASM) $DEBUG $LIST $PAGELENGTH (50) $PAGEWIDTH (100) $DATE(7.30.2007) ;**************************************************************************** ; THIS PROGRAM WILL DO THE FOLLOWING: ; 1. READ THE NUMBER OF PULSES THAT OCCUR IN ONE SECOND ; 2. CALCULATE A "TENTATIVE" RPM MEASUREMENT BASED ON THIS 1 SECOND SAMPLE. ; 3. DISPLAY THIS RPM VALUE ON THE DISPLAY ; 4 CALCULATE PERIOD AND FREQ. BASED ON RPM MEASUREMENT ; 5. SEND SERIAL TRANSMISSION OUT THE SERIAL PORT EVERY SECOND ; ; 6 CALCULATE THE RPM MEASUREMENT BY ACCUMULATING SAMPLES OVER TIME, INTEGRATE ; ;**************************************************************************** ; ; 07-20-07 STARTED SCRAPPING TOGETHER THE PROGRAM OUT OF EARLIER ; ATTEMPTS AT GETTING THIS RIGHT. ; 07-28-07 PCB-TRIALS: TWEAKING FREQ AND RPMS TO WORK WITH DIP- ; SWITCH ON PORT 0. ; 07-30-07 RECEIVED PROTO BOARDS AND STARTED CODING USING THIS ; BOARD. EVERYTHING SEEMS TO BE WORKING. ; ADDED ROUTINES TO MOVE DECIMAL POINTS BASED ON THE ; NUMBER OF PULSES PER REVOLUTION. ; FREQUENCY, PERIOD AND RPMS SEEM TO BE CORRECT AND ; PRECISION IS PROPORTIONAL TO THE NUMBER OF PULSES PER ; REVOLUTION. WE ARE LIMITED WITH THIS BOARD TO ; 255 PULSES PER REVOLUTION DUE TO THE DIP SWITCHES. ; A SERIAL COMMAND COULD BE ADDED TO INCREASE THIS BUT ; I WON'T DO THAT SINCE THERE IS NOT ANY NV RAM. ; ADDED SERIAL ROUTINES TO TRANSMIT RPM,FREQ.,AND PERIOD EACH SEC. ; ; *FOR THE NEXT REVISION OF THIS BOARD. SHOULD DO THE FOLLOWING: ; ; 1. FIX PCB PAD AND SCH FOR TRANSISTOR Q10 ; 2. ADD MAX232 OR EQ AND DB-9 CONNECTOR FOR REAL SERIAL ; 3. DESIGN BOARD FOR A NEW ENCLOSURE. ; 4. MAKE LED DISPLAYS ABLE TO TAKE THE TWO DIFFERENT SIZES. ; 5. LOOK AT ADDING A HIGHER VOLTAGE SUPPLY e.g. +8V TO INCREASE ; THE LED BRIGHTNESS AND MAYBE LOOK AT DRIVING THE LED DISPLAY ; WITH DISCRETE TRANSISTORS VS. A SINGLE IC. THIS WOULD ALLOW ; FOR MORE FLEXIBILITY IN THE CHARACTERS TO BE GENERATED. ; 6. ADD SOME SERIAL FLASH FOR CALIBRATION VALUES AND STUFF. ; ;**************************************************************************** ;CONSTANT DEFINITIONS: ; LONG_DIVISION STUFF; BYTE_COUNT EQU R2 BIT_COUNT EQU R3 HIGHEST_NUMERATOR_BYTE EQU R4 HIGHEST_DENOMINATOR_BYTE EQU R5 ; TIMER 2 DEFINITIONS T2CON DATA 0C8h ; TIMER 2 CONTROL REGISTER T2MOD DATA 0C9h ; TIMER 2 MODE REGISTER RCAP2L DATA 0CAh ; TIMER 2 LOW-BYTE CAPTURE RCAP2H DATA 0CBh ; TIMER 2 HIGH-BYTE CAPTURE TL2 DATA 0CCh ; TIMER 2 LOW-BYTE TH2 DATA 0CDh ; TIMER 2 HIGH-BYTE ; MORE MCU REGISTERS AUXR DATA 8Eh ; AUXILIARY REGISTER FOR ALE, WDIDLE, CKCON DATA 8Fh ; NOT USED BDRCON DATA 9Bh ; BAUD RATE CONTROL REGISTER ; PCON DATA 97h ; POWER CONTROL REGISTER ( IN CASE ASSEMBLER ?) AUXR1 DATA 0A2h ; AUXILIARY REGISTER 1 FOR ALT DPTR ; BIT ADDRESSABLE STUFF CONREG DATA 20H ; CONDITION REGISTER (LOCAL) ; USED BY VARIOUS ROUTINES FOR PASSING ; CONDITION FLAGS. SERPNT DATA 21H ; SERIAL BUFFER POINTER FOR RX TEMP DATA 22H ; TEMP VAR GENERAL USE ; USED FOR BINARY TO BCD STUFF BITEA DATA 26H ; BOTTOM BYTE OF SOURCE DATA BITEB DATA 27H ; TOP BYTE OF SOURCE DATA BITEC DATA 28H ; BITED DATA 29H ; MS FOR 32-BIT VARS BCDA DATA 2AH ; BOTTOM BYTE OF BCD DATA (PACKED BCD) BCDB DATA 2BH ; TOP BYTE OF BCD DATA (PACKED BCD) BCDC DATA 2CH ; BCDD DATA 2DH ; BCDAA DATA 2EH ; MS BCDBB DATA 2FH ; END OF BIT ADDRESSABLE MEMORY BCDCC DATA 30H BCDDD DATA 31H ; LS BITCNT DATA 32H ; BIT COUNTER (IN MOST CASES 16 FOR 16-BITS). ; IRQ COUNTER STUFF MS_ACCA DATA 33H ; 0-255 * 10 mS MS_ACCB DATA 34H ; 256-65535 * 10 mS MS_ACCC DATA 35H ; 65536-16,777,215 * 10 mS ; EDGE COUNTS NCNT DATA 36H ; NUMBER OF PULSES PER REVOLUTION. EDGECNT DATA 37H ; 0-255 EDGES. ; 32-BIT MATH VARIABLES Load_16byteA DATA 38H ; MS Load_16byteB DATA 39H ; LS Load_32byteA DATA 3AH ; MS Load_32byteB DATA 3BH Load_32byteC DATA 3CH Load_32byteD DATA 3DH ; LS ;************************************ Mul_16byteA DATA 3EH ; MS Mul_16byteB DATA 3FH ; MMS Mul_16byteC DATA 40H ; MLS Mul_16byteD DATA 41H ; LS Div_16byteA DATA 42H ; MS Div_16byteB DATA 43H ; MMS Div_16byteC DATA 44H ; MLS Div_16byteD DATA 45H ; LS ;************************************** ; OutPut AND TeMP REGISTERS ;************************************** OP_0 DATA 46H ; LS OP_1 DATA 47H OP_2 DATA 48H OP_3 DATA 49H ; MS OP_4 DATA 4AH OP_5 DATA 4BH OP_6 DATA 4CH OP_7 DATA 4DH ; MMS OP_8 DATA 4EH ; MS-BYTE USED FOR OVERFLOW TMP_0 DATA 4FH ; LS TMP_1 DATA 50H TMP_2 DATA 51H TMP_3 DATA 52H ; MS TMP_4 DATA 53H TMP_5 DATA 54H TMP_6 DATA 55H TMP_7 DATA 56H ; MMS TMP_8 DATA 57H ; MS-BYTE USED FOR OVERFLOW AVBUFA DATA 58H ; LS AVERAGE BUFFER AVBUFB DATA 59H ; AVERAGE BUFFER AVBUFC DATA 5AH ; MS AVERAGE BUFFER AVACCA DATA 5BH ; LS AVERAGE ACCUMULATOR AVACCB DATA 5CH ; AVERAGE ACCUMULATOR AVACCC DATA 5DH ; AVERAGE ACCUMULATOR AVACCD DATA 5EH ; AVERAGE ACCUMULATOR AVACCE DATA 5FH ; AVERAGE ACCUMULATOR AVACCF DATA 60H ; AVERAGE ACCUMULATOR AVACCG DATA 61H ; AVERAGE ACCUMULATOR AVACCH DATA 62H ; MS AVERAGE ACCUMULATOR SAMPX DATA 63H ; THE NUMBER OF SAMPLES TO TAKE ; BEFORE DISPLAYING THE DATA. SAMPXX DATA 64H ; BACKUP OF SAMPX Add_32byteA DATA 65H ; MS Add_32byteB DATA 66H ; MMS Add_32byteC DATA 67H ; MML Add_32byteD DATA 68H ; LS TST_TIMEL DATA 69H ; THIS IS OUR TEST WORD USED FOR COUNTING SECONDS TST_TIMEH DATA 6AH ; TST_CNTR DATA 6BH ; THIS IS OUR TEST BYTE FOR LED UPTIME RFRESH DATA 6CH ; COUNTER REGISTER FOR PERIODIC INTERRUPT. ; USED FOR PETTING THE WATCHDOG.. ; COUNTER 2 BACKUP BUFFERS TL2B DATA 6DH ; BACKUP OF TL2 TH2B DATA 6EH ; BACKUP OF TH2 ; RPM INTEGRATOR VARIABLES ; 24-BIT ROLLING PULSE COUNT ACCUMULATOR PULSE_CNTA DATA 6FH ; LS PULSE_CNTB DATA 70H PULSE_CNTC DATA 71H ; MS ; 16-BIT ROLLING SECOND COUNTER SEC_CNTA DATA 72H ; LS SEC_CNTB DATA 73H ; MS ; DECIMAL POSITION VARIABLE DECI DATA 74H ; DECIMAL POSITION VARIABLE USED BY DOTTY ROUTINE DECX DATA 75H ; TEMP DECIMAL POSITION HOLDING VARIABLE SBCDA DATA 76H ; BCD DATA FOR SERIAL TX ROUTINE SPIT SBCDB DATA 77H SBCDC DATA 78H SBCDD DATA 79H ;**************************************************************************** ;INTERRUPT VECTORS ;**************************************************************************** ORG 00H ; POWER ON RESET AJMP START ORG 03H ; EXTERNAL INTERRUP 0 RETI ORG 0BH ; TIMER 0 OVERFLOW LJMP UPDATE ; PERIODIC INTERRUPT ~10mSEC. ORG 13H ; EXTERNAL INTERRUP 1 RETI ORG 1BH ; TIMER 1 OVERFLOW RETI ORG 23H ; SERIAL PORT INTERRUP RETI AJMP SERIAL_INT ; SEND THE DATA MAN ORG 2BH ; TIMER 2 OVERFLOW INTERRUP RETI ; 8X32-8X52 ONLY ;**************************************************************************** ;THIS IS THE RESET ;**************************************************************************** ORG 40H ; START OF PROGRAM START: ; CLEAR THE SRAM BEFORE WE DO ANYTHING ELSE! MOV R0, # 20h ; PUT THE START OF RAM IN ; R0 FOR CLEAR STARTA: MOV @R0, #0 ; CLEAR THAT LOCATION INC R0 ; NEXT ADDRESS PLEASE CJNE R0, #0FFh, STARTA ; LOOP UNTIL ALL RAM = 00h ; MOVE THE LOCATION OF THE STACK POINTER TO TOP OF INDIRECT ADDRESSABLE ; SRAM -SINCE STACK POINTER ARE INDIRECT OPERATIONS ANYWAY, THIS WILL WORK MOV SP, #0DFH ; MOVE THE LOCATION OF THE SP (0xE0 TO 0xFF) ;DISABLE ALE AND SET DPTR TO DP0x VS. DP1x MOV AUXR, #19h ; AUXILIARY REGISTER DISABLE ALE ; WD IDLE, RESET OUTPUT MOV AUXR1, #00000000B ; SELECT DP0x ; TIMER/COUNTER 0 & 1 SETUP ;**************************************************************************** ; SET-UP TCON - TIMER/COUNTER 0 & 1 CONTROL REGISTER - RESET VALUE IS 00h ; MODE = ;----------------------------------------------------------------------------- ; 7 6 5 4 3 2 1 0 ; TCON BITS = TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0 ; 0 0 0 0 0 0 0 0 ;----------------------------------------------------------------------------- ; ; SET-UP TMOD - TIMER 0 & 1 MODE CONTROL REGISTER - RESET VALUE IS 00h ; MODE = TIMER 1 & 0 BOTH IN 16-BIT TIMER MODE ;----------------------------------------------------------------------------- ; 7 6 5 4 3 2 1 0 ; TMOD BITS = GATE1 C/T1# M11 M01 GATE0 C/T0# M10 - M00 ; 0 0 1 0 0 0 0 1 ;----------------------------------------------------------------------------- ; ;**************************************************************************** ;SETUP COUNTER MOV TMOD, #21H ; SETUP TIMER 0 FOR 16-BIT TIMER ; SET TIMER TO ROLL EVERY 2.00 mS @ 22.1184 MHz. ; SETUP TIMER 1 FOR 8 BIT AUTO RELOAD TIMER ; THIS WILL BE USED TO GENERATE THE BAUD RATE MOV TH0, #0F1H ; LOAD UPPER TIMER REG. MOV TL0, #99H ; LOAD LOWER TIMER REG. MOV TL1, #0FDH ; SET FOR 19.2K with 22.1184Mhz MOV TH1, #0FDH ; DITTO SETB TCON.4 ; START TIMER 0 SETB TCON.6 ; START TIMER 1 (BAUD RATE GEN) ; TIMER/COUNTER 2 SETUP ;**************************************************************************** ; SET-UP T2CON - TIMER/COUNTER 2 CONTROL REGISTER - RESET VALUE IS 00h ; MODE = EXTERNAL EVENT COUNTER (FALLING EDGE TRIGGERED) ; INTERRUPT ON 16-BIT COUNTER TH2/TL2 OVERFLOW. (SHOULD NEVER INTERRUPT) ; MAX SAMPLE INPUT IS 1/24 OSC FREQ. ;----------------------------------------------------------------------------- ; 7 6 5 4 3 2 1 0 ; T2CON BITS = TF2 EXF2 RCLK TCLK EXEN2 TR2 C/T2 CP/RL2 ; 1 0 0 0 0 1 1 0 ;----------------------------------------------------------------------------- ; ; SET-UP T2MOD - TIMER 2 MODE CONTROL REGISTER - RESET VALUE IS 00h ; MODE = DISABLE TIMER 2 OUTPUT, ENABLE TIMER 2 AS UP/DOWN COUNTER ;----------------------------------------------------------------------------- ; 7 6 5 4 3 2 1 0 ; T2MOD BITS = - - - - - - T2OE DCEN ; 0 0 0 0 0 0 0 1 ;----------------------------------------------------------------------------- ; ;**************************************************************************** MOV T2MOD, #01H ; 16-BIT CAPTURE MODE. MOV T2CON, #86H ; TF2 = 0 EXF2 = 0 RCLK = 0 TCLK = 0 EXEN2 = 0 ; TR2 = 1 C/T2 = 1 CP/CL2 = 0 MOV TL2, #00h ; CLEAR THE COUNTER REGISTER MOV TH2, #00h ; DITTO MOV RCAP2L, #00h ; CLEAR THE CAPTURE REGISTER MOV RCAP2H, #00h ; DITTO ;**************************************************************************** ; SERIAL CONTROL REGISTER ;**************************************************************************** ; SET-UP SCON - CURRENTLY DISABLE RX AND TX ; MODE = SET AS 8-BIT UART, RX AND TX BOTH OFF ;----------------------------------------------------------------------------- ; 7 6 5 4 3 2 1 0 ; SCON BITS = FE/SM0 SM1 SM2 REN TB8 RB8 TI RI ; 0 1 0 0 0 0 0 0 ;----------------------------------------------------------------------------- ;**************************************************************************** MOV SCON, #40h ; SETUP SERIAL PORT ;**************************************************************************** ; POWER CONTROL REGISTER (87h) ;**************************************************************************** ; SET-UP PCON - DO NOTHING ; MODE = DO NOTHING ;----------------------------------------------------------------------------- ; 7 6 5 4 3 2 1 0 ; PCON BITS = SMOD1 SMOD0 - POF GF1 GF0 PD IDL ; 1 0 0 0 0 0 0 0 ;----------------------------------------------------------------------------- ;**************************************************************************** MOV PCON, #80h ; DOUBLE THE BAUD RATE TO 19.2K (34.8K) ;**************************************************************************** ; BAUD RATE CONTROL REGISTER (9Bh) ;**************************************************************************** ; SET-UP BDRCON - DO NOTHING ; MODE = DO NOTHING ;----------------------------------------------------------------------------- ; 7 6 5 4 3 2 1 0 ; BDRCON BITS = - - - BRR TBCK RBCK SPD SRC ; 0 0 0 0 0 0 0 0 ;----------------------------------------------------------------------------- ;**************************************************************************** MOV BDRCON, #00h ; DO NOTHING REALLY ;**************************************************************************** ; INTERRUPT ENABLE REGISTER ;**************************************************************************** ; SET-UP IE - ENABLE TIMER 0 & TIMER 1 ; MODE = ;---------------------------------------------------------------------------- ; 7 6 5 4 3 2 1 0 ; IE BITS = EA - ET2 ES ET1 EX1 ET0 EX0 ; 0 0 0 1 0 0 1 0 ;---------------------------------------------------------------------------- ;**************************************************************************** MOV IE, #12h ; ENABLE TIMER 0 & SERIAL INTERRUPTS ;**************************************************************************** ; INTERRUPT PRIORITY REGISTER ;**************************************************************************** ; SET-UP IP - ; MODE = ;---------------------------------------------------------------------------- ; 7 6 5 4 3 2 1 0 ; IE BITS = - - PT2 PS PT1 PX1 PT0 PX0 ; 0 0 0 0 0 0 0 0 ;---------------------------------------------------------------------------- ;**************************************************************************** MOV IP, #00h ; SET ALL INTERRUPTS SAME PRIORITY ;**************************************************************************** ;********************************************************************* ; THIS WILL BE READ FROM DIP SWITCHES, FROM PORT 0. ;********************************************************************* MOV NCNT, P0 ; OUR N COUNTS = TO ONE FOR NOW ; THE VALUE READ FROM DIP SWITCHES. ;********************************************************************* ;CLR IE.3 ; DISABLE INTERRUPT ;CLR TCON.6 ; STOP COUNTS SETB IE.7 ; ENABLE INTERRUPTS ; TIMER 2 STUFF ; CLR PSW.1 ; COUNTER STOPPED ; CLR P1.3 ; TEST ; SETB IE.5 ; ENABLE ( T2EX ) ; SETB P1.4 ; SET TEST BIT. ; SETB P1.5 ; SET TEST BIT. MOV SERPNT, #80h ; SET THE RX POINTER TO START OF MEM ;MAIN: ;**************************************************************************** ; THIS IS OUR MAIN PROGRAM ;**************************************************************************** MAIN: ; 1. CHECK THE VALUE OF TST_TIME, IF IT'S 100+, THEN UPDATE THE DISPLAY VARIABLES ; WITH THE SOFTWARE COUNTER VALUES. ; 2. WHEN TST_TIME IS 100+, THEN TURN ON/OFF THE SAMPLE LED KINDA AS A HEART ; BEAT THING. CLR C ; CLEAR THE CARRY FLAG MOV A, TST_TIMEL ; GET THE LSB OF SOFTWARE COUNTER CJNE A, #0F4H, MAIN ; CHECK FOR 244d MOV A, TST_TIMEH ; GET THE MSB OF SOFTWARE COUNTER CJNE A, #01H, MAIN ; LOOP UNTIL 1F4h = 500d * 2mS = 1.0S ; ONE SECOND HAS PASSED SINCE LAST SAMPLE NAILED_IT: MOV TST_TIMEH, #00H ; CLEAR OUR 1S counter MOV TST_TIMEL, #00H ; UPDATE THE SOFTWARE COUNTER ; PRESERV COUNTER 2 CONTENTS (INCASE FAST PULSES ARRIVING.) OVERKILL? MOV TL2B, TL2 ; BACKUP COUNTER 2 CONTENTS LSB MOV TH2B, TH2 ; "" MSB MOV TL2, #00H ; CLEAR THE PULSE COUNT MOV TH2, #00H ; CLEAR DATA IN TIMER 2 REGIES MOV NCNT, P0 ; READ DIP-SWITCH IN CASE USER CHANGED IT ; CHECK THE MODE PERIOD, FREQ OR RPM JNB P1.4, PERIOD ; PERIOD ONLY JNB P1.5, FREAK ; FREQ ONLY JMP RPM ; RPMS ONLY FREAK: JMP FREAKY ; NEED THIS CAUSE OF ADDRESS OUT-OF-RANGE ERROR ;-------------------------------------------------------------------------------------- ; THERE IS NO AVERAGING FOR FREQUENCY OR PERIOD, JUST DISPLAY THE INSTANTANEOUS VALUES ;-------------------------------------------------------------------------------------- ;************************************* ; CALCULATE AND DISPLAY THE PERIOD ;************************************* PERIOD: MOV A, TL2B ; GET THE COUNT VALUE JNZ PEROK ; IF NON-ZERO VALUE GOOD MOV A, TH2B ; GET MS COUNT VALUE JNZ PEROK ; IF NON-ZERO REAL GOOD JMP NOPE ; ELSE, JUMP BACK TO MAIN PEROK: ; GET THE NUMBER OF PULSES ; MAKE IT A REALLY BIG NUMBER BY MULTIPLYING THE COUNT ; BY 10,000,000 THIS IS FOR DISPLAYING MORE DECIMAL DIGITS MOV OP_0, TL2B ;LS ROLLING PULSE COUNT MOV OP_1, TH2B ; MOV OP_2, #00h ; MOV OP_3, #00h ;MS BYTE MOV OP_4, #00h ; MOV OP_5, #00h ; MOV OP_6, #00h ; MOV OP_7, #00h ; MS-BYTE MOV Mul_16byteA, #00h ; MS MOV Mul_16byteB, #98h ; MOV Mul_16byteC, #96h ; MOV Mul_16byteD, #80h ; LS CALL MUL_32 ; MULTIPLY ROUTINE ; CALC THE FREQUENCY OF THE PULSES (REV PER SECOND) MOV Div_16byteA,#00h ; MS MOV Div_16byteB,#00h ; MOV Div_16byteC,#00h ; MOV Div_16byteD,NCNT ; LS CALL Div_32 ; DO THE DIVISION ; NOW DO THE 1/X TO GET PERIOD BUT IN THIS CASE, WE'LL DO ; 100E9/X TO SCALE OUR RESULT TO FIT OUR DISPLAY XXX.XXX XX MOV Div_16byteA, OP_3 ; MS MOV Div_16byteB, OP_2 ; MOV Div_16byteC, OP_1 ; MOV Div_16byteD, OP_0 ; LS: NUMBER OF SAMPLES ; LOAD NUMERATOR WITH 1,000,000,000,000 MOV OP_0, #00h ; LS-BYTE MOV OP_1, #10h ; MOV OP_2, #0A5h ; MOV OP_3, #0D4h ; MOV OP_4, #0E8h ; MOV OP_5, #00h ; MOV OP_6, #00h ; MOV OP_7, #00h ; MS-BYTE CALL Div_32 ; DO THE DIVISION MOV BITED, OP_3 ; MSBYTE OF 32-BIT RESLULT MOV BITEC, OP_2 ; MOV BITEB, OP_1 ; MIDDLE BYTE MOV BITEA, OP_0 ; LSBYTE. MOV BITCNT,#32d ; FOR 32 BITS CALL BIN2BCD ; MAKE IT PACKED BCD. MOV DECI, #05d ; TURN ON THE DECIMAL FOR DISPLAY XXX.XXX XX ; CALL SURPZERO ; TURN OFF LEADING ZEROS ; LOAD THE DISPLAY REGISTERS MOV BCDAA, BCDA ; IF IT IS NOT ZERO, THEN THE MOV BCDBB, BCDB ; REST OF THE DIGITS MUST BE MOV BCDCC, BCDC ; DISPLAYED MOV BCDDD, BCDD JMP BLINKY ; JUMP TO UPDATE/NOT UPDATE SAMPLE LED ; IF THE RESULT PULSE COUNT IS ZERO, JUMP HERE SO NO DIVIDE BY ZEROS NOPE: MOV BCDAA, #00h ; DISPLAY ALL ZEROS MOV BCDBB, #00h ; MOV BCDCC, #00h ; MOV BCDDD, #00h ; MOV DECI, #05d ; TURN ON THE DECIMAL FOR DISPLAY XXX.XXX XX JMP BLINKY ; JUMP TO UPDATE/NOT UPDATE SAMPLE LED ;************************************* ; CALCULATE AND DISPLAY THE FREQUENCY ;************************************* FREAKY: CALL GFREQ ; GET THE FREQ MOV BITED, OP_3 ; MSBYTE OF 32-BIT RESLULT MOV BITEC, OP_2 ; MSBYTE OF 24-BIT VALUE MOV BITEB, OP_1 ; MIDDLE BYTE MOV BITEA, OP_0 ; LSBYTE. MOV BITCNT, #32d ; FOR 24 BITS CALL BIN2BCD ; MAKE IT PACKED BCD. MOV DECI, DECX ; UPDATE THE DECIMAL VARIABLE CALL SURPZERO ; TURN OFF LEADING ZEROS MOV BCDAA, BCDA ; UPDATE THE DISPLAY BCD DIGIT MOV BCDBB, BCDB ; STUFF MOV BCDCC, BCDC ; MOV BCDDD, BCDD ; JMP BLINKY ; JUMP TO UPDATE/NOT UPDATE SAMPLE LED ;************************************* ; CALCULATE AND DISPLAY THE RPMS ;************************************* RPM: CALL RPMIT ; GO DO THE RPM THING ; FALL INTO BLINKY ;************************************************************************************ ; CHECK AND CLEAR THE VALUE OF PULSE COUNTER AND BLINK THE SAMPLE LED IF PULSES WERE ; COUNTED ;************************************************************************************ BLINKY: MOV A, TL2B ; GET THE COUNT VALUE JNZ BLINKOK ; IF NON-ZERO VALUE GOOD MOV A, TH2B ; GET MS COUNT VALUE JNZ BLINKOK ; IF NON-ZERO REAL GOOD JMP NOWAY;MAIN ; ELSE, JUMP BACK TO MAIN BLINKOK: ; CHECK FOR ON/OFF OF LED MOV A, TST_CNTR ; GET OUR HEART BEAT VALUE CJNE A, #01H, LEDOFF ; IF LED IS ON, TURN IT OFF CLR P1.3 ; TURN THE LED ON MOV TST_CNTR, #00H ; CLEAR OUR FLAG FOR NEXT TIME JMP NOWAY;MAIN ; LOOP LEDOFF: MOV TST_CNTR, #01H ; SET THE FLAG FOR NEXT TIME SETB P1.3 ; TURN THE LED OFF ; JMP MAIN ; LOOP NOWAY: CALL SPIT ; BUILD AND SEND THE SERIAL STRING CALL PURGE ; CLEAR THE BUFFER. CLR CONREG.0 ; CLEAR CONDITION FLAG JMP MAIN ; BACK TO MAIN. ;**************************************************************************** ;---------------------- INTERRUPT SERVICE ROUTINES -------------------------- ;UPDATE ;**************************************************************************** ; PERIODIC INTERRUPT USING TIMER0 OVERFLOW ; APPROX. EVERY 2.00 mS.FOR A 16.00mS OR 62.5Hz SWEEP OF THE LED DISPLAY ; ; UPDATE THE LED DISPLAYS ; THE VARIABLE (BCDD) CONTAINS THE PACKED BCD UPPER BYTE OF COUNTER. ; THE VARIABLE (BCDC) CONTAINS THE PACKED BCD LOWER BYTE OF COUNTER. ; THE VARIABLE (BCDB) CONTAINS THE PACKED BCD UPPER BYTE OF COUNTER. ; THE VARIABLE (BCDA) CONTAINS THE PACKED BCD LOWER BYTE OF COUNTER. ; ;**************************************************************************** ; 2.00 mS !+ TIME LOST ( 5 TO 6 CYCLES ) UPDATE: MOV TL0, #091H ; LOAD LOWER COUNTER REG.(+ 3 CYCLES) MOV TH0, #0F1H ; LOAD UPPER COUNTER REG. PUSH ACC ; SAVE A PUSH PSW PUSH DPL PUSH DPH PUSH B ;-- LED0 -- MOV A, RFRESH LEDD: CJNE A, #00h, NLED0 MOV A, BCDAA ; GET THE PACKED BCD ANL A, #0Fh ; MASK OFF UPPER NIBBLE MOV B, A ; STASH IT FOR A MOMENT. MOV A, RFRESH ; GET THE INT COUNT ANL A, #0Fh ; MAKE SURE IT IS 0-7 SWAP A ; PUT IT IN THE UPPER NIBBLE ORL A, B ; OR THE DATA CALL DOTTY ; CHECK AND UPDATE THE DECIMAL JMP FINA ; JUMP TO DISPLAY AND EXIT ;-- LED1 -- NLED0: CJNE A, #01h, NLED1 MOV A, BCDAA ; GET THE PACKED BCD SWAP A ; PUT IT IN THE LOWER NIBBLE ANL A, #0Fh ; MASK OFF UPPER NIBBLE MOV B, A ; STASH IT FOR A MOMENT. MOV A, RFRESH ; GET THE INT COUNT ANL A, #0Fh ; MAKE SURE IT IS 0-7 SWAP A ; PUT IT IN THE UPPER NIBBLE ORL A, B ; OR THE DATA CALL DOTTY ; CHECK AND UPDATE THE DECIMAL JMP FINA ; JUMP TO DISPLAY AND EXIT ;-- LED2 -- NLED1: CJNE A, #02h, NLED2 MOV A, BCDBB ; GET THE PACKED BCD ANL A, #0Fh ; MASK OFF UPPER NIBBLE MOV B, A ; STASH IT FOR A MOMENT. MOV A, RFRESH ; GET THE INT COUNT ANL A, #0Fh ; MAKE SURE IT IS 0-7 SWAP A ; PUT IT IN THE UPPER NIBBLE ORL A, B ; OR THE DATA CALL DOTTY ; CHECK AND UPDATE THE DECIMAL JNB P1.4, NLED1A ; IF THIS IS NOT RPM THEN JNB P1.5, NLED1A ; TURN OFF THE RPM LED SETB P1.6 ; ELSE TURN ON LED AND JMP FINA ; SKIP OVER TURNING IT OFF NLED1A: CLR P1.6 ; TURN OFF THE RPM LED JMP FINA ; JUMP TO DISPLAY AND EXIT ;-- LED3 -- NLED2: CJNE A, #03h, NLED3 MOV A, BCDBB ; GET THE PACKED BCD SWAP A ; PUT IT IN THE LOWER NIBBLE ANL A, #0Fh ; MASK OFF UPPER NIBBLE MOV B, A ; STASH IT FOR A MOMENT. MOV A, RFRESH ; GET THE INT COUNT ANL A, #0Fh ; MAKE SURE IT IS 0-7 SWAP A ; PUT IT IN THE UPPER NIBBLE ORL A, B ; OR THE DATA CALL DOTTY ; CHECK AND UPDATE THE DECIMAL JMP FINA ; JUMP TO DISPLAY AND EXIT ;-- LED4 -- NLED3: CJNE A, #04h, NLED4 MOV A, BCDCC ; GET THE PACKED BCD ANL A, #0Fh ; MASK OFF UPPER NIBBLE MOV B, A ; STASH IT FOR A MOMENT. MOV A, RFRESH ; GET THE INT COUNT ANL A, #0Fh ; MAKE SURE IT IS 0-7 SWAP A ; PUT IT IN THE UPPER NIBBLE ORL A, B ; OR THE DATA CALL DOTTY ; CHECK AND UPDATE THE DECIMAL JMP FINA ; JUMP TO DISPLAY AND EXIT ;-- LED5 -- NLED4: CJNE A, #05h, NLED5 MOV A, BCDCC ; GET THE PACKED BCD SWAP A ; PUT IT IN THE LOWER NIBBLE ANL A, #0Fh ; MASK OFF UPPER NIBBLE MOV B, A ; STASH IT FOR A MOMENT. MOV A, RFRESH ; GET THE INT COUNT ANL A, #0Fh ; MAKE SURE IT IS 0-7 SWAP A ; PUT IT IN THE UPPER NIBBLE ORL A, B ; OR THE DATA CALL DOTTY ; CHECK AND UPDATE THE DECIMAL JMP FINA ; JUMP TO DISPLAY AND EXIT ;-- LED6 -- NLED5: CJNE A, #06h, NLED6 MOV A, BCDDD ; GET THE PACKED BCD ANL A, #0Fh ; MASK OFF UPPER NIBBLE MOV B, A ; STASH IT FOR A MOMENT. MOV A, RFRESH ; GET THE INT COUNT ANL A, #0Fh ; MAKE SURE IT IS 0-7 SWAP A ; PUT IT IN THE UPPER NIBBLE ORL A, B ; OR THE DATA CALL DOTTY ; CHECK AND UPDATE THE DECIMAL FINA: MOV P2, A ; WRITE A TO PORT 2 JMP FINAB ; JUMP AROUND LAST DIGIT AND STUFF ;-- LED7 -- NLED6: MOV A, BCDDD ; GET THE PACKED BCD SWAP A ; PUT IT IN THE LOWER NIBBLE ANL A, #0Fh ; MASK OFF UPPER NIBBLE MOV B, A ; STASH IT FOR A MOMENT. MOV A, RFRESH ; GET THE INT COUNT ANL A, #0Fh ; MAKE SURE IT IS 0-7 SWAP A ; PUT IT IN THE UPPER NIBBLE ORL A, B ; OR THE DATA CALL DOTTY ; CHECK AND UPDATE THE DECIMAL MOV RFRESH, #00 ; CLEAR COUNTER MOV P2, A ; WRITE A TO PORT 2 JMP FINAC ; SKIP AND DON'T INCREMENT FOR LED0 FINAB: INC RFRESH ; ADD ONE TO REFRESH COUNTER FINAC: ; UPDATE SOFTWARE COUNTER FOR MAIN MOV A, TST_TIMEL ; GET LSB OF SOFTWARE COUNTER INC A ; ADD ON TO IT JZ ROLL_SEC ; WELL, WE JUST ROLLED! MOV TST_TIMEL, A ; NO ROLL SO WRITE IT BACK JMP FINAD ; AND JUMP AROUND ; ROLL_SEC: MOV TST_TIMEL, A ; WRITE IT BACK MOV A, TST_TIMEH ; GET MSB OF SOFTWARE COUNTER INC A ; ADD ONE TO IT MOV TST_TIMEH, A ; UPDATE IT FINAD: POP B POP DPH POP DPL POP PSW POP ACC RETI ;**************************************************************************** ;DOTTY ;***************************************************************************** ; ROUTINE USED BY UPDATE TO TURN ON THE PROPER DECIMAL POINT ; VARIABLE USED ; WRITE A 0 THRU 7 TO DECI TO TURN ON YOUR DECIMAL POINT OF THAT CHARACTER ; ; NOTE: THIS ROUTINE IS USED EXCLUSIVELY BY UPDATE: ; ;***************************************************************************** DOTTY: MOV B, A ; BACKUP THE ACC MOV A, DECI ; GET THE VARIABLE CJNE A, RFRESH, NODOT ; IS THE CORRECT CHARACTER TO PLACE A DECIMAL BEHIND? MOV A, B ; YES-SO GET ACC BACK AND ORL A, #80h ; TURN ON THE DECIMAL BY SETTING THE MSB JMP DOTYES ; JUMP AROUND NODOT: MOV A, B ; NO-SO RESTORE ACC DOTYES: RET ; BACK TO UPDATE: ;***************************************************************************** ; <<<<<<<<< REVISE FOR FUTURE USE >>>>>>>>>>>> ;SERIAL_INT: ;**************************************************************************** ; THIS IS THE SERIAL INTERRUPT. ; THIS ROUTINE WILL CHECK TO MAKE SURE WE RECEIVED A BYTE. ; THEN GET THE CURRENT POINTER LOCATION AND CHECK FOR A BUFFER ROLL-OVER. ; ; IF WE ARE GOING TO ROLL, ; DON'T ACCEPT ANY MORE DATA UNTIL THE CURRENT STRING IS PROCESSED. ; ; IF NOT, ; WRITE THE DATA BYTE INTO THE BUFFER AND INCREMENT THE POINTER. ;**************************************************************************** SERIAL_INT: JBC RI, GOT_RI ; CHECK FOR CHARACTER IN BUFFEER RETI GOT_RI: PUSH ACC ; SAVE THE ACC PUSH PSW ; SAVE FLAGS PUSH DPL PUSH DPH MOV TEMP, R0 ; STASH R0, ASS WON'T LET ME USE A PUSH MOV R0, SERPNT ; GET THE POINTER FROM MEM MOV A, R0 ; GET THE BUFFER POINTER VALUE INC A ; SEE IF WE ARE GONNA ROLL CJNE A, #00H,NOROLL MOV R0, #80H ; SET THE POINTER BACK TO START OF THE ; BUFFER. DON'T ACCEPT ANY MORE DATA ; UNTIL THE STRING IS PROCESSED! ; LET R0 ROLL! NOROLL: MOV A,SBUF ; GET THE CHARACTER WAITING CJNE A, #0Ah, NOLF ; IS IT A ? IF NOT JUMP SETB CONREG.0 ; IF WE FOUND IT THEN SET THE BIT IN THE ; CONDITION REGISTER TO TELL THE WORLD THAT ; WE'VE GOT A SENTENCE IN OUR BUFFER! NOLF: MOV @R0, A ; SAVE THE CHARACTER INC R0 ; INCREMENT THE BUFFER POINTER MOV SERPNT, R0 ; PUT THE POINTER BACK IN MEM MOV R0, TEMP ; STASH R0, ASS WON'T LET ME USE A PUSH POP DPH POP DPL KEYEXIT: POP PSW ; RESTORE FLAGS. POP ACC ; RESTORE ACC. RETI ;**************************************************************************** ;--------------------GENERAL SUBROUTINES & FUNCTIONS ------------------------ ;SPIT ;**************************************************************************** ; THIS ROUTINE WILL BUILD THE STRING TO TRANSMIT IN INTERNAL RAM ; IT WILL WRITE OVER ANYTHING IN THIS RAM LOCATION (80-90h) ;**************************************************************************** SPIT: MOV R0, #80h ; GET THE SERIAL POINTER MOV A, # '$' ; PUT "$" INTO STRING. (80) MOV @R0, A ; WRITE IT TO BUFFER INC R0 ; GO TO NEXT ADDRESS LOCATION. MOV A, # ',' ; PUT "," INTO STRING. MOV @R0, A ; WRITE IT TO BUFFER (81) INC R0 ; GO TO NEXT ADDRESS LOCATION. JNB P1.4, DISPER ; DISPLAY "PER" JNB P1.5, DISFRE ; DISPLAY "FRE" JMP DISRPM ; DISPLAY "RPM" DISPER: MOV A, #'P' ; PUT "P" INTO STRING. (82) MOV @R0, A ; WRITE IT TO BUFFER INC R0 ; GO TO NEXT ADDRESS LOCATION. MOV A, #'E' ; PUT "E" INTO STRING. (83) MOV @R0, A ; WRITE IT TO BUFFER INC R0 ; GO TO NEXT ADDRESS LOCATION. MOV A, #'R' ; PUT "R" INTO STRING. (84) MOV @R0, A ; WRITE IT TO BUFFER INC R0 ; GO TO NEXT ADDRESS LOCATION. JMP CONDISP ; JUMP AND CONTINUE DISFRE: MOV A, #'F' ; PUT "F" INTO STRING. MOV @R0, A ; WRITE IT TO BUFFER INC R0 ; GO TO NEXT ADDRESS LOCATION. MOV A, #'R' ; PUT "R" INTO STRING. MOV @R0, A ; WRITE IT TO BUFFER INC R0 ; GO TO NEXT ADDRESS LOCATION. MOV A, #'E' ; PUT "E" INTO STRING. MOV @R0, A ; WRITE IT TO BUFFER INC R0 ; GO TO NEXT ADDRESS LOCATION. JMP CONDISP ; JUMP AND CONTINUE DISRPM: MOV A, #'R' ; PUT "R" INTO STRING. MOV @R0, A ; WRITE IT TO BUFFER INC R0 ; GO TO NEXT ADDRESS LOCATION. MOV A, #'P' ; PUT "P" INTO STRING. MOV @R0, A ; WRITE IT TO BUFFER INC R0 ; GO TO NEXT ADDRESS LOCATION. MOV A, #'M' ; PUT "M" INTO STRING. MOV @R0, A ; WRITE IT TO BUFFER INC R0 ; GO TO NEXT ADDRESS LOCATION. CONDISP: MOV A, # ',' ; PUT "," INTO STRING. (85) MOV @R0, A ; WRITE IT TO BUFFER INC R0 ; GO TO NEXT ADDRESS LOCATION. MOV R0, #90h ; POINT TO END OF STRING MOV A, #0AH ; SEND LINE FEED MOV @R0, A ; WRITE IT (8F) DEC R0 ; DECREMENT POINTER MOV A, #0DH ; CARRIAGE RETURN MOV @R0, A ; WRITE IT (8E) DEC R0 ; DECREMENT POINTER ;-- LED 0 & 1 -- MOV A, SBCDA ; GET THE PACKED BCD MOV B, A ; STASH A COPY ANL A, #0Fh ; MASK OFF UPPER NIBBLE ORL A, #30h ; MAKE IT ASCII MOV @R0, A ; WRITE IT (8D) DEC R0 ; DECREMENT POINTER MOV R1, DECI ; GET THE DECIMAL LOCATION CJNE R1, #00h, NZRO ; NOT ZERO? MOV A, # '.' ; PLACE THE "." IN STRING. MOV @R0, A ; WRITE IT DEC R0 ; NEXT. NZRO: MOV A, B ; GET STASHED SWAP A ; PUT IT IN THE LOWER NIBBLE ANL A, #0Fh ; MASK OFF UPPER NIBBLE ORL A, #30h ; MAKE IT ASCII MOV @R0, A ; WRITE IT (8C) DEC R0 ; DECREMENT POINTER CJNE R1, #01h, NONE ; NOT ONE? MOV A, # '.' ; PLACE THE "." IN STRING. MOV @R0, A ; WRITE IT DEC R0 ; NEXT. NONE: ;-- LED 2 & 3 -- MOV A, SBCDB ; GET THE PACKED BCD MOV B, A ; STASH A COPY ANL A, #0Fh ; MASK OFF UPPER NIBBLE ORL A, #30h ; MAKE IT ASCII MOV @R0, A ; WRITE IT (8B) DEC R0 ; DECREMENT POINTER CJNE R1, #02h, NTWO ; NOT TWO? MOV A, # '.' ; PLACE THE "." IN STRING. MOV @R0, A ; WRITE IT DEC R0 ; NEXT. NTWO: MOV A, B ; GET STASHED SWAP A ; PUT IT IN THE LOWER NIBBLE ANL A, #0Fh ; MASK OFF UPPER NIBBLE ORL A, #30h ; MAKE IT ASCII MOV @R0, A ; WRITE IT (8A) DEC R0 ; DECREMENT POINTER CJNE R1, #03h, NTRE ; NOT THREE? MOV A, # '.' ; PLACE THE "." IN STRING. MOV @R0, A ; WRITE IT DEC R0 ; NEXT. NTRE: ;-- LED 4 & 5 -- MOV A, SBCDC ; GET THE PACKED BCD MOV B, A ; STASH A COPY ANL A, #0Fh ; MASK OFF UPPER NIBBLE ORL A, #30h ; MAKE IT ASCII MOV @R0, A ; WRITE IT (89) DEC R0 ; DECREMENT POINTER CJNE R1, #04h, NFOR ; NOT FOUR? MOV A, # '.' ; PLACE THE "." IN STRING. MOV @R0, A ; WRITE IT DEC R0 ; NEXT. NFOR: MOV A, B ; GET STASHED SWAP A ; PUT IT IN THE LOWER NIBBLE ANL A, #0Fh ; MASK OFF UPPER NIBBLE ORL A, #30h ; MAKE IT ASCII MOV @R0, A ; WRITE IT (88) DEC R0 ; DECREMENT POINTER CJNE R1, #05h, NFIV ; NOT FIVE? MOV A, # '.' ; PLACE THE "." IN STRING. MOV @R0, A ; WRITE IT DEC R0 ; NEXT. NFIV: ;-- LED 6 & 7 -- MOV A, SBCDD ; GET THE PACKED BCD MOV B, A ; STASH A COPY ANL A, #0Fh ; MASK OFF UPPER NIBBLE ORL A, #30h ; MAKE IT ASCII MOV @R0, A ; WRITE IT (87) DEC R0 ; DECREMENT POINTER CJNE R1, #06h, NSIX ; NOT SIX? MOV A, # '.' ; PLACE THE "." IN STRING. MOV @R0, A ; WRITE IT DEC R0 ; NEXT. NSIX: MOV A, B ; GET STASHED SWAP A ; PUT IT IN THE LOWER NIBBLE ANL A, #0Fh ; MASK OFF UPPER NIBBLE ORL A, #30h ; MAKE IT ASCII MOV @R0, A ; WRITE IT (86) DEC R0 ; DECREMENT POINTER CJNE R1, #07h, NSEV ; NOT SEVEN? MOV A, # '.' ; PLACE THE "." IN STRING. MOV @R0, A ; WRITE IT DEC R0 ; NEXT. NSEV: ; GO-AHEAD AND SEND THE STRING OUT THE PORT MAN. SPITS: CLR IE.4 ; DISABLE SERIAL INTERRUPT MOV R0, #80h ; POINT TO START OF BUFFER MOV B, #17d ; MOVE INTO B THE CHARACTER COUNT SPITSS: MOV A, @R0 ; MOVE CONTENTS AT THE DATA POINTER TO A CLR TI ; CLEAR THE TRANSMIT INTERRUPT BIT MOV SBUF, A ; LOAD BYTE IN SERIAL BUFFER TXSPIT: JNB TI,TXSPIT ; WAIT FOR BYTE TO SHIFT OUT INC R0 ; INC DATA POINTER DJNZ B,SPITSS ; DECRIMENT CHARACTER COUNTER CLR TI SETB IE.4 ; ENABLE SERIAL INTERRUPT RET ; OUTTA HERE ;**************************************************************************** ;PURGE ;**************************************************************************** ; THIS ROUTINE WILL "PURGE" THE SERIAL BUFFER.(30-BYTE) ; START AT 80h AND FILL THE SERIAL RX BUFFER WITH ZEROS. ;**************************************************************************** PURGE: MOV R1, #80H ; GET THE START ADDRESS OF THE SERIAL BUFFER. MOV R2, #30d ; PUT 30 IN R2 TO COUNT OUR BYTES. MOV A, #20H ; CLEAR A SPACES. UPCHUK: MOV @R1, A ; PUT IT IN THE BUFFER. INC R1 ; NEXT ADDRESS PLEASE.. DJNZ R2, UPCHUK ; GO BACK AND DO IT AGAIN UNTIL WE GOT IT. MOV SERPNT, #80H ; RESET THE SERIAL BUFFER POINTER. RET ; OUTTA HERE JACK! ;**************************************************************************** ;RPMIT: ;********************************************************************************************** ; NO AVERAGING OR INTEGRATING IS TO BE DONE IN THIS ROUTINE. ; ; ; ; (INTFLAG) BIT ADDRESSABLE INTEGRATION FLAG ; BIT 0 = INTEGRATION STARTED, WAITING FOR 60 SECONDS ; BIT 1 = INITIAL 60 SECONDS HAS PASSED, NOW IN 30 SECOND MODE ; BIT 2 THRU 7 AVAILABLE. ; ; 24-BIT ROLLING PULSE COUNT ACCUMULATOR ; ; PULSE_CNTA ; PULSE_CNTB ; PULSE_CNTC ; 16-BIT ROLLING SECOND COUNTER ; SEC_CNTA ; SEC_CNTB ; ;********************************************************************************************** RPMIT: ;---------------------------------------------------------------------------------------------- ; FIRST: CALCULATE THE FREQ AND UPDATE THE ROLLING PULSE COUNTER ;---------------------------------------------------------------------------------------------- CALL GFREQ ; CALCULATE THE FREQ ; NOW OUR 24-BIT RESULT IS IN OP_0 TO OP_2, UPDATE OUR BUFFERS ; SO MULTIPLY THE FREQUENCY RESULT BY 60 TO MAKE RPMS MOV Mul_16byteA, #00h ; MS MOV Mul_16byteB, #00h ; MOV Mul_16byteC, #00h ; MOV Mul_16byteD, #60d ; LS CALL MUL_32 ; MULTIPLY ROUTINE ; I WANT TO LIMIT THE RPM DISPLAY TO 99,999.000 SO IF THE 10,000s OR 100,000s DECIMAL ; PLACE IS SET, DIVIDE RESULT BY 10 OR 100 AND MOVE THE DECIMAL POINT TO 1,000s PLACE ; THIS EXTRA TROUBLE PRESERVES THE PRECISION FOR PULSE COUNTS OVER 100++ MOV A, DECX ; GET THE VALUE CJNE A, #04d, RPMOKA ; IF NOT 4 THEN GO CHECK FOR 5 ; ELSE, IT'S 10,000s PLACE MOV Div_16byteA, #00h ; MS MOV Div_16byteB, #00h ; MOV Div_16byteC, #00h ; MOV Div_16byteD, #10d ; LS: DIVIDE BY 10 CALL Div_32 ; DO THE DIVISION MOV DECX, #03d ; SET THE DECIMAL FOR 1000s PLACE JMP DRPMOK ; JUMP AROUND AND DISPLAY RPMOKA: ; ELSE DIVIDE BY 10 AND CJNE A, #05d, DRPMOK ; IF NOT 5 THEN GO-AHEAD AND DISPLAY IT ; ELSE IT'S 100,000s PLACE MOV Div_16byteA, #00h ; MS MOV Div_16byteB, #00h ; MOV Div_16byteC, #00h ; MOV Div_16byteD, #100d ; LS: DIVIDE BY 100 CALL Div_32 ; DO THE DIVISION MOV DECX, #03d ; SET THE DECIMAL FOR 1000s PLACE DRPMOK: ; NOW THE OPERATIONS REGISTERS CONTAIN THE AVERAGE ; CONVERT TO BCD FOR DISPLAYING MOV BITED, OP_3 ; MSBYTE OF 32-BIT RESLULT MOV BITEC, OP_2 ; MSBYTE OF 24-BIT VALUE MOV BITEB, OP_1 ; MIDDLE BYTE MOV BITEA, OP_0 ; LSBYTE. MOV BITCNT, #32d ; FOR 24 BITS CALL BIN2BCD ; MAKE IT PACKED BCD. MOV DECI, DECX ; UPDATE THE DECIMAL VARIABLE CALL SURPZERO ; TURN OFF LEADING ZEROS ; LOAD THE DISPLAY REGISTERS MOV BCDAA, BCDA ; IF IT IS NOT ZERO, THEN THE MOV BCDBB, BCDB ; REST OF THE DIGITS MUST BE MOV BCDCC, BCDC ; DISPLAYED MOV BCDDD, BCDD RET ;********************************************************************************************** ;GFREQ: ;********************************************************************************************* ; CALCULATE THE FREQ - ASSUME ONE SECOND HAS PASSED AND WE HAVE PULSES IN COUNTER 2 ; REGISTERS. DIVIDE THIS VALUE BY THE BIN-NUMBER AT P0. SET BY DIP-SWITCHES ; ; FREQUENCY RETURNED IN OP_0 THRU OP_3 ; ;********************************************************************************************* GFREQ: ; FIRST: MULTIPLY IT BY 100 SINCE WE HAVE TWO DECIMAL PLACES ON THE DISPLAY MOV OP_0, TL2B ;LS ROLLING PULSE COUNT MOV OP_1, TH2B ; MOV OP_2, #00h ; MOV OP_3, #00h ;MS BYTE MOV OP_4, #00h ; MOV OP_5, #00h ; MOV OP_6, #00h ; MOV OP_7, #00h ; MS-BYTE ; DECIMAL PRECISION IS BASED ON THE DIP-SWITCH SETTINGS AND AS IS THE DECIMAL ; LOCATION ON THE DISPLAY. ; HERE WE READ THE DIP-SWITCH SETTINGS AT P0 AND SET THE MULTIPLIER AND DECIMAL ; PLACES ACCORDINGLY. HOLDS THE DECIMAL POSITION CHECKA: CLR C ; CLEAR THE CARRY (BORROW) FLAG MOV B, NCNT ; GET THE DISPSWITCH SETTINGS MOV A, #10d ; LOAD THE FIRST CHECK (A =< 10) SUBB A, B ; DO THE CHECK JC CHECKB ; IF CARRY WAS SET, A BORROW OCCURED ; SO A > 10, DO SECOND CHECK ; ELSE MULTIPLY BY 100 MOV Mul_16byteA, #00h ; MS MOV Mul_16byteB, #00h ; MOV Mul_16byteC, #00h MOV Mul_16byteD, #100d ; LS MOV DECX, #02d ; SET THE DECIMAL FOR 100s PLACE JMP CHECKED ; OK GO MULTIPLY CHECKB: CLR C ; CLEAR THE CARRY (BORROW) FLAG MOV B, NCNT ; GET THE DISPSWITCH SETTINGS MOV A, #100d ; LOAD THE FIRST CHECK (A =< 100) SUBB A, B ; DO THE CHECK JC CHECKC ; IF CARRY WAS SET, A BORROW OCCURED ; SO A > 100, DO THIRD CHECK ; ELSE MULTIPLY BY 1000 MOV Mul_16byteA, #00h ; MS MOV Mul_16byteB, #00h ; MOV Mul_16byteC, #03h MOV Mul_16byteD, #0E8h ; LS MOV DECX, #03d ; SET THE DECIMAL FOR 1000s PLACE JMP CHECKED ; OK GO MULTIPLY ; AT THIS POINT TO GAIN A LITTLE EXTRA PRECISION, WE CHECK FOR 100 < X < 201 CHECKC: ; CHECK FOR 100 < X < 201 CLR C ; CLEAR THE CARRY (BORROW) FLAG MOV B, NCNT ; GET THE DISPSWITCH SETTINGS MOV A, #200d ; LOAD THE FIRST CHECK (A =< 200) SUBB A, B ; DO THE CHECK JC CHECKD ; IF CARRY WAS SET, A BORROW OCCURED ; SO A > 200, GO AND SET UP THE MULTIPLIER ; ELSE MULTIPLY BY 10000 MOV Mul_16byteA, #00h ; MS MOV Mul_16byteB, #00h ; MOV Mul_16byteC, #27h MOV Mul_16byteD, #10h ; LS MOV DECX, #04d ; SET THE DECIMAL FOR 10,000s PLACE JMP CHECKED ; OK GO MULTIPLY CHECKD: MOV Mul_16byteA, #00h ; MS MOV Mul_16byteB, #01h ; MOV Mul_16byteC, #86h MOV Mul_16byteD, #0A0h ; LS MOV DECX, #05d ; ELSE, SET THE DECIMAL FOR 100,000s PLACE CHECKED: CALL MUL_32 ; MULTIPLY ROUTINE ; NEXT: DIVIDE THIS MULTIPLIED VALUE BY THE NUMBER READ FROM THE DIP-SWITCH CONNECTED ; TO PORT 0. (NUMBER OF PULSES PER CYCLE) MOV Div_16byteA,#00h ; MS MOV Div_16byteB,#00h ; MOV Div_16byteC,#00h ; MOV Div_16byteD,NCNT ; LS CALL Div_32 ; DO THE DIVISION RET ; BACK TO CALLER ;********************************************************************************************* ;SURPZERO: ;********************************************************************************************* ; THIS ROUTINE WILL SUPRESS ALL LEADING ZEROS AFTER 1s PLACE ; ROUTINE USES THE VARIABLE TO DO THIS ;********************************************************************************************* ; START WITH THE LAST DIGIT SURPZERO: MOV A, DECI ; GET THE 1s LOCATION VARIABLE CJNE A, #07h, NOTDMS ; NOT 7 SO GO A HEAD AND CHECK-IT JMP ITSALS ; IT'S THIS DIGIT SO JUMP AROUND CHECKING ; THE REST OF THE DIGITS SINCE THEY'RE OK NOTDMS: MOV A, BCDD ; GET THE PACKED BCD FOR 6 & 7 MOV B, A ; STASH IT FOR A MOMENT. ANL A, #0F0h ; MASK OFF LOWER NIBBLE JNZ ITNDM ; IF NOT ZERO, SKIP IT MOV A, B ; GET PACKED BCD AGAIN ORL A, #0F0h ; SET THE UPPER BCD DIGIT TO ALL ONE'S (OFF) MOV BCDD, A ; WRITE IT BACK JMP ISITDLS ;JUMP AROUND THIS STUFF ITNDM: ; HAD TO ADD THIS CAUSE JNZ OUT-OF-RANGE ERROR JMP ITSALS ISITDLS: MOV A, DECI ; GET THE 1s LOCATION VARIABLE CJNE A, #06h, NOTDLS ; NOT 6 SO GO A HEAD AND CHECK-IT JMP ITSALS ; IT'S THIS DIGIT SO JUMP AROUND CHECKING ; THE REST OF THE DIGITS SINCE THEY'RE OK NOTDLS: MOV A, BCDD ; GET THE PACKED BCD MOV B, A ; STASH IT FOR A MOMENT. ANL A, #0Fh ; CHECK THE LOWER DIGIT (CHAR 6) JNZ ITSALS ; IF THE RESULT IS NOT ZERO, CHECK CHAR 5 MOV A, B ; GET OUR BACKUP COPY ORL A, #0Fh ; SET ALL BITS OF LOWER NIBBLE HIGH MOV BCDD, A ; WRITE IT BACK ; NEXT TWO DIGITS ISITCMS: MOV A, DECI ; GET THE 1s LOCATION VARIABLE CJNE A, #05h, NOTCMS ; NOT 5 SO GO A HEAD AND CHECK-IT JMP ITSALS ; IT'S THIS DIGIT SO JUMP AROUND CHECKING ; THE REST OF THE DIGITS SINCE THEY'RE OK NOTCMS: MOV A, BCDC ; GET THE PACKED BCD FOR 4 & 5 MOV B, A ; STASH IT FOR A MOMENT. ANL A, #0F0h ; MASK OFF LOWER NIBBLE JNZ ITSALS ; IF NOT ZERO, SKIP IT MOV A, B ; GET PACKED BCD AGAIN ORL A, #0F0h ; SET THE UPPER BCD DIGIT TO ALL ONE'S (OFF) MOV BCDC, A ; WRITE IT BACK ISITCLS: MOV A, DECI ; GET THE 1s LOCATION VARIABLE CJNE A, #04h, NOTCLS ; NOT 4 SO GO A HEAD AND CHECK-IT JMP ITSALS ; IT'S THIS DIGIT SO JUMP AROUND CHECKING ; THE REST OF THE DIGITS SINCE THEY'RE OK NOTCLS: MOV A, BCDC ; GET THE PACKED BCD MOV B, A ; STASH IT FOR A MOMENT. ANL A, #0Fh ; CHECK THE LOWER DIGIT (CHAR 4) JNZ ITSALS ; IF THE RESULT IS NOT ZERO, CHECK CHAR 3 MOV A, B ; GET OUR BACKUP COPY ORL A, #0Fh ; SET ALL BITS OF LOWER NIBBLE HIGH MOV BCDC, A ; WRITE IT BACK ; NEXT TWO DIGITS 2 & 3 ISITBMS: MOV A, DECI ; GET THE 1s LOCATION VARIABLE CJNE A, #03h, NOTBMS ; NOT 3 SO GO A HEAD AND CHECK-IT JMP ITSALS ; IT'S THIS DIGIT SO JUMP AROUND CHECKING ; THE REST OF THE DIGITS SINCE THEY'RE OK NOTBMS: MOV A, BCDB ; GET THE PACKED BCD FOR 2 & 3 MOV B, A ; STASH IT FOR A MOMENT. ANL A, #0F0h ; MASK OFF LOWER NIBBLE JNZ ITSALS ; IF NOT ZERO, SKIP IT MOV A, B ; GET PACKED BCD AGAIN ORL A, #0F0h ; SET THE UPPER BCD DIGIT TO ALL ONE'S (OFF) MOV BCDB, A ; WRITE IT BACK ISITBLS: MOV A, DECI ; GET THE 1s LOCATION VARIABLE CJNE A, #02h, NOTBLS ; NOT 2 SO GO A HEAD AND CHECK-IT JMP ITSALS ; IT'S THIS DIGIT SO JUMP AROUND CHECKING ; THE REST OF THE DIGITS SINCE THEY'RE OK NOTBLS: MOV A, BCDB ; GET THE PACKED BCD MOV B, A ; STASH IT FOR A MOMENT. ANL A, #0Fh ; CHECK THE LOWER DIGIT (CHAR 2) JNZ ITSALS ; IF THE RESULT IS NOT ZERO, CHECK CHAR 1 MOV A, B ; GET OUR BACKUP COPY ORL A, #0Fh ; SET ALL BITS OF LOWER NIBBLE HIGH MOV BCDB, A ; WRITE IT BACK ; NEXT TWO DIGITS 0 & 1 ISITAMS: MOV A, DECI ; GET THE 1s LOCATION VARIABLE CJNE A, #01h, NOTAMS ; NOT 1 SO GO A HEAD AND CHECK-IT JMP ITSALS ; IT'S THIS DIGIT SO JUMP AROUND CHECKING ; THE REST OF THE DIGITS SINCE THEY'RE OK NOTAMS: MOV A, BCDA ; GET THE PACKED BCD FOR 0 & 1 MOV B, A ; STASH IT FOR A MOMENT. ANL A, #0F0h ; MASK OFF LOWER NIBBLE JNZ ITSALS ; IF NOT ZERO, SKIP IT MOV A, B ; GET PACKED BCD AGAIN ORL A, #0F0h ; SET THE UPPER BCD DIGIT TO ALL ONE'S (OFF) MOV BCDA, A ; WRITE IT BACK ITSALS: MOV BCDAA, BCDA ; UPDATE THE DISPLAY VARIABLES MOV BCDBB, BCDB ; FOR UPDATE: AND RETURN MOV BCDCC, BCDC ; MOV BCDDD, BCDD RET ;********************************************************************************************* ;CRUNCHP: ;**************************************************************************** ; THIS IS THE ROUTINE THAT WILL CONVERT OUR COUNT INTO MICROSECOND ; RESOLUTION FOR DISPLAYING AS PERIOD. ; ; MS_ACCA ; 0-255 * 10 mS ; MS_ACCB ; 256-65535 * 10 mS ; MS_ACCC ; 65536-16,777,215 * 10 mS ; ; Div_16byteA ; MS ; Div_16byteB ; LS ; ; 32-BIT ACC BYTES ; ; OP_0 ; LS ; OP_1 ; OP_2 ; OP_3 ; MS ; ; ;**************************************************************************** CRUNCHP: ; CONVERT 24-BITS OF THE ACC TO BCD FOR DISPLAYING. MOV BITEC, MS_ACCC ; MSBYTE OF 24-BIT VALUE MOV BITEB, MS_ACCB ; MIDDLE BYTE MOV BITEA, MS_ACCA ; LSBYTE. MOV BITED, #00h ; MSBYTE OF 32-BIT RESLULT MOV BITCNT, #32d ; FOR 24 BITS CALL BIN2BCD ; MAKE IT PACKED BCD. RET ; OUT OF HERE MAN! ;**************************************************************************** ;BIN2BCD ;**************************************************************************** ; BINARY TO BCD CONVERSION ; THIS ROUTINE I BORROWED FROM THAT GUY THAT WROTE ALL THEM PROGRAMS ; AT PHILLIPS. ; ; VARIABLES USED ; (BITEA), (BITEB), (BCDA), (BCDB) ; ; BINARY DATA IS PASSED TO THE ROUNTINE USING ; ; (BITEA) LOWER BYTE OF 16-BIT BINARY NUMBER. ; (BITEB) UPPER BYTE OF 16 BIT BINARY NUMBER. ; ; "PACKED" BCD NUMBERS ARE RETURNED USING ; ; (BCDA) LOWER NUMBERS OF CONVERSION IN COMPACT BCD. ; (BCDB) UPPER NUMBERS OF CONVERSION IN COMPACT BCD. ; ; EXAMPLE: ; BITEA = FFh ; BITEB = 0Fh ; ; AFTER CONVERSION: ; BCDA = 95h ; BCDB = 40h SO 0FFFh = 4095d. ; ;**************************************************************************** BIN2BCD: CLR A ; CLEAR OUT THE RESULT REGISTERS MOV BCDA, A ; MOV BCDB, A ; MOV BCDC, A ; USED IF DOING 32-BIT CONVERSIONS. MOV BCDD, A ; THIS VAR IS SET BY CALLING ROUTINE ; MOV BITCNT, #24 ; FOR 32BITS BCDLOOP: CLR C ; ROTATE SOURCE DATA UP ONE BIT. MOV A, BITEA ; SAME AS (DATA * 2) RLC A ; ROTATE CARRY INTO LS-BIT MOV BITEA, A ; STORE IT MOV A, BITEB ; SAME AS (DATA * 2) RLC A ; ROTATE CARRY INTO LS-BIT MOV BITEB, A ; STORE IT ; IF YOU WANTED TO DO A 32 BIT NUMBER YOU COULD INCLUDE THE COMITTED OUT ; STUFF. I AM ONLY INTERESTED IN 16-BIT AT THE MOMENT. MOV A, BITEC ; SAME AS (DATA * 2) RLC A ; ROTATE CARRY INTO LS-BIT MOV BITEC, A ; STORE IT MOV A, BITED ; SAME AS (DATA * 2) RLC A ; ROTATE CARRY INTO LS-BIT MOV BITED, A ; STORE IT MOV A, BCDA ; CONVER ONE BIT STARTING AT ADDC A, ACC ; THE BOTTOM RESULT DA A ; MOV BCDA, A ; MOV A, BCDB ; ADDC A, ACC ; DA A ; MOV BCDB, A ; ; AGAIN FOR 32-BIT CONVERSIONS. MOV A, BCDC ; ADDC A, ACC ; DA A ; MOV BCDC, A ; MOV A, BCDD ; ADDC A, ACC ; DA A ; MOV BCDD, A ; BCDEX: DJNZ BITCNT, BCDLOOP ; DONE? MOV SBCDA, BCDA ; PUT A COPY IN SERIAL BCD MOV SBCDB, BCDB ; MOV SBCDC, BCDC ; MOV SBCDD, BCDD ; RET ;**************************************************************************** ;**************************************************************************** ; THESE ARE THE 32-BIT MATH ROUTINES ;**************************************************************************** ;********************************************* ; Return the lower 16 bits of the OP registers ;********************************************* Low_16: MOV R6, OP_1 MOV R7, OP_0 RET ;********************************************** ; Return the middle 16 bits of the OP registers ;********************************************** Mid_16: MOV R6, OP_2 MOV R7, OP_1 RET ;******************************************** ; Return the high 16 bits of the OP registers ;******************************************** High_16: MOV R6, OP_3 MOV R7, OP_2 RET ;*********************************************************** ; Add the 32 bits supplied by the caller to the OP registers ;*********************************************************** Add_32: CLR C MOV A, OP_0 ADDC A, Add_32byteD ;lowest byte first MOV OP_0, A MOV A, OP_1 ADDC A, Add_32byteC ;mid-lowest byte + carry MOV OP_1, A MOV A, OP_2 ADDC A, Add_32byteB ;mid-highest byte + carry MOV OP_2, A MOV A, OP_3 ADDC A, Add_32byteA ;highest byte + carry MOV OP_3, A RET ;MUL_32: ;**************************************************************************** ; Multiply the 64 bit OP with the 32 bit value supplied ; 32-BIT MULTIPLIER GOES IN THESE BYTES ; ; Mul_16byteA ; MS ; Mul_16byteB ; MMS ; Mul_16byteC ; MLS ; Mul_16byteD ; LS ; ; 64-BIT ACC BYTES, RESULT RETURNED IN THESE BYTES ; < PUT THE COUNTER CONTNETS IN THESE BYTES PRIOR TO CALLING THIS ROUTINE > ; ; OP_0 ; LS ; OP_1 ; OP_2 ; OP_3 ; MS ; OP_4 ; OP_5 ; OP_6 ; OP_7 ; MMS ; ; 64-BIT TEMP REGISTERS USED. ; ; TMP_0 ; LS ; TMP_1 ; TMP_2 ; TMP_3 ; MS ; TMP_4 ; TMP_5 ; TMP_6 ; TMP_7 ; MMS ; ;**************************************************************************** MUL_32: MOV TMP_8, #0 MOV TMP_7, #0 ;clear out 64 bits MOV TMP_6, #0 MOV TMP_5, #0 MOV TMP_4, #0 MOV TMP_3, #0 MOV TMP_2, #0 MOV TMP_1, #0 MOV TMP_0, #0 ; FIRST WE MUL. THE LS-BYTE OF THE MULTIPLIER BY ALL OF THE BYTES OF THE ; MULTIPLICAND AND UPDATE THE TMP_X BYTES ;Generate the lowest byte of the result MOV B, OP_0 MOV A, Mul_16byteD MUL AB MOV TMP_0, A ;low-order result MOV TMP_1, B ;high_order result ;Now generate the next higher order byte MOV B, OP_1 MOV A, Mul_16byteD MUL AB ADD A, TMP_1 ;low-order result MOV TMP_1, A ; save MOV A, B ; get high-order result ADDC A, TMP_2 ; include carry from previous operation MOV TMP_2, A ; save JNC MUL_LOOPA INC TMP_3 ; propagate carry into TMP_3 MUL_LOOPA: MOV B, OP_2 ; MOV A, MUL_16byteD MUL AB ADD A, TMP_2 ; LOW-ORDER RESULT MOV TMP_2, A ; SAVE MOV A, B ; GET HIGH-ORDER RESULT ADDC A, TMP_3 ; INCLUDE CARRY FROM PREVIOUS OPERATION MOV TMP_3, A ; SAVE JNC MUL_LOOPB ; INC TMP_4 ; PROPAGATE CARRY INTO TMP_4 MUL_LOOPB: MOV B, OP_3 MOV A, Mul_16byteD MUL AB ADD A, TMP_3 ;low-order result MOV TMP_3, A ; save MOV A, B ; get high-order result ADDC A, TMP_4 ; include carry from previous operation MOV TMP_4, A ; save JNC MUL_LOOPC INC TMP_5 ; propagate carry into TMP_5 MUL_LOOPC: MOV B, OP_4 MOV A, Mul_16byteD MUL AB ADD A, TMP_4 ;low-order result MOV TMP_4, A ; save MOV A, B ; get high-order result ADDC A, TMP_5 ; include carry from previous operation MOV TMP_5, A ; save JNC MUL_LOOPD INC TMP_6 ; propagate carry into TMP_6 MUL_LOOPD: MOV B, OP_5 MOV A, Mul_16byteD MUL AB ADD A, TMP_5 ;low-order result MOV TMP_5, A ; save MOV A, B ; get high-order result ADDC A, TMP_6 ; include carry from previous operation MOV TMP_6, A ; save JNC MUL_LOOPE INC TMP_7 ; propagate carry into TMP_7 MUL_LOOPE: MOV B, OP_6 MOV A, Mul_16byteD MUL AB ADD A, TMP_6 ;low-order result MOV TMP_6, A ; save MOV A, B ; get high-order result ADDC A, TMP_7 ; include carry from previous operation MOV TMP_7, A ; save MOV B, OP_7 MOV A, Mul_16byteD MUL AB ADD A, TMP_7 ;low-order result MOV TMP_7, A ; save ; NEXT WE MUL. THE MLS-BYTE OF THE MULTIPLIER BY THE LOWER 6-BYTES MOV B, OP_0 MOV A, Mul_16byteC MUL AB ADD A, TMP_1 ;low-order result MOV TMP_1, A ; save MOV A, B ; get high-order result ADDC A, TMP_2 ; include carry from previous operation MOV TMP_2, A ; save JNC MUL_LOOPG INC TMP_3 ; propagate carry into TMP_3 MUL_LOOPG: MOV B, OP_1 MOV A, Mul_16byteC MUL AB ADD A, TMP_2 ;low-order result MOV TMP_2, A ; save MOV A, B ; get high-order result ADDC A, TMP_3 ; include carry from previous operation MOV TMP_3, A ; save JNC MUL_LOOPH INC TMP_4 ; propagate carry into TMP_4 MUL_LOOPH: MOV B, OP_2 MOV A, Mul_16byteC MUL AB ADD A, TMP_3 ;low-order result MOV TMP_3, A ; save MOV A, B ; get high-order result ADDC A, TMP_4 ; include carry from previous operation MOV TMP_4, A ; save JNC MUL_LOOPI INC TMP_5 ; propagate carry into TMP_5 MUL_LOOPI: MOV B, OP_3 MOV A, Mul_16byteC MUL AB ADD A, TMP_4 ;low-order result MOV TMP_4, A ; save MOV A, B ; get high-order result ADDC A, TMP_5 ; include carry from previous operation MOV TMP_5, A ; save JNC MUL_LOOPJ INC TMP_6 ; propagate carry into TMP_6 MUL_LOOPJ: MOV B, OP_4 MOV A, Mul_16byteC MUL AB ADD A, TMP_5 ;low-order result MOV TMP_5, A ; save MOV A, B ; get high-order result ADDC A, TMP_6 ; include carry from previous operation MOV TMP_6, A ; save JNC MUL_LOOPK INC TMP_7 ; propagate carry into TMP_7 MUL_LOOPK: MOV B, OP_5 MOV A, Mul_16byteC MUL AB ADD A, TMP_6 ;low-order result MOV TMP_6, A ; save MOV A, B ; get high-order result ADDC A, TMP_7 ; include carry from previous operation MOV TMP_7, A ; save MOV B, OP_6 MOV A, Mul_16byteC MUL AB ADD A, TMP_7 ;low-order result MOV TMP_7, A ; save ; NEXT WE MUL. THE MMS-BYTE OF THE MULTIPLIER BY THE LOWER 5-BYTES MUL_LOOPL: MOV B, OP_0 MOV A, Mul_16byteB MUL AB ADD A, TMP_2 ;low-order result MOV TMP_2, A ; save MOV A, B ; get high-order result ADDC A, TMP_3 ; include carry from previous operation MOV TMP_3, A ; save JNC MUL_LOOPM INC TMP_4 ; propagate carry into TMP_4 MUL_LOOPM: MOV B, OP_1 MOV A, Mul_16byteB MUL AB ADD A, TMP_3 ;low-order result MOV TMP_3, A ; save MOV A, B ; get high-order result ADDC A, TMP_4 ; include carry from previous operation MOV TMP_4, A ; save JNC MUL_LOOPN INC TMP_5 ; propagate carry into TMP_5 MUL_LOOPN: MOV B, OP_2 MOV A, Mul_16byteB MUL AB ADD A, TMP_4 ;low-order result MOV TMP_4, A ; save MOV A, B ; get high-order result ADDC A, TMP_5 ; include carry from previous operation MOV TMP_5, A ; save JNC MUL_LOOPO INC TMP_6 ; propagate carry into TMP_6 MUL_LOOPO: MOV B, OP_3 MOV A, Mul_16byteB MUL AB ADD A, TMP_5 ;low-order result MOV TMP_5, A ; save MOV A, B ; get high-order result ADDC A, TMP_6 ; include carry from previous operation MOV TMP_6, A ; save JNC MUL_LOOPP INC TMP_7 ; propagate carry into TMP_7 MUL_LOOPP: MOV B, OP_4 MOV A, Mul_16byteB MUL AB ADD A, TMP_6 ;low-order result MOV TMP_6, A ; save MOV A, B ; get high-order result ADDC A, TMP_7 ; include carry from previous operation MOV TMP_7, A ; save ; FINAL BYTE MOV B, OP_5 MOV A, Mul_16byteB MUL AB ADD A, TMP_7 ;low-order result MOV TMP_7, A ; save ; NEXT WE MUL. THE MS-BYTE OF THE MULTIPLIER BY THE LOWER 4-BYTES MUL_LOOPQ: MOV B, OP_0 MOV A, Mul_16byteA MUL AB ADD A, TMP_3 ;low-order result MOV TMP_3, A ; save MOV A, B ; get high-order result ADDC A, TMP_4 ; include carry from previous operation MOV TMP_4, A ; save JNC MUL_LOOPR INC TMP_5 ; propagate carry into TMP_5 MUL_LOOPR: MOV B, OP_1 MOV A, Mul_16byteA MUL AB ADD A, TMP_4 ;low-order result MOV TMP_4, A ; save MOV A, B ; get high-order result ADDC A, TMP_5 ; include carry from previous operation MOV TMP_5, A ; save JNC MUL_LOOPS INC TMP_6 ; propagate carry into TMP_6 MUL_LOOPS: MOV B, OP_2 MOV A, Mul_16byteA MUL AB ADD A, TMP_5 ;low-order result MOV TMP_5, A ; save MOV A, B ; get high-order result ADDC A, TMP_6 ; include carry from previous operation MOV TMP_6, A ; save JNC MUL_LOOPT INC TMP_7 ; propagate carry into TMP_7 MUL_LOOPT: MOV B, OP_3 MOV A, Mul_16byteA MUL AB ADD A, TMP_6 ;low-order result MOV TMP_6, A ; save MOV A, B ; get high-order result ADDC A, TMP_7 ; include carry from previous operation MOV TMP_7, A ; save ; FINAL BYTE MOV B, OP_4 MOV A, Mul_16byteA MUL AB ADD A, TMP_7 ;low-order result MOV TMP_7, A ; save ; Now we are all done, move the TMP values back into OP MOV OP_0, TMP_0 MOV OP_1, TMP_1 MOV OP_2, TMP_2 MOV OP_3, TMP_3 MOV OP_4, TMP_4 MOV OP_5, TMP_5 MOV OP_6, TMP_6 MOV OP_7, TMP_7 MOV OP_8, TMP_8 RET ;**************************************************************************** ; This divides the 64 bit OP register by the 32-BIT value supplied ;**************************************************************************** Div_32: MOV R7, #0 MOV R6, #0 ;zero out partial remainder MOV R5, #0 MOV R4, #0 MOV TMP_0, #0 MOV TMP_1, #0 MOV TMP_2, #0 MOV TMP_3, #0 MOV TMP_4, #0 MOV TMP_5, #0 MOV TMP_6, #0 MOV TMP_7, #0 MOV R3, Div_16byteA ;load divisor MOV R2, Div_16byteB MOV R1, Div_16byteC MOV R0, Div_16byteD MOV B, #64 ;#32 ;loop count ;This begins the loop Div_loop32: CALL Shift_D32 ;shift the dividend and return MSB in C MOV A, R4 ;shift carry into LSB of partial remainder RLC A MOV R4, A MOV A, R5 RLC A MOV R5, A MOV A, R6 RLC A MOV R6, A MOV A, R7 RLC A MOV R7, A ;now test to see if R7:R6:R5:R4 >= R3:R2:R1:R0 CLR C MOV A, R7 ;subtract R3 from R7 to see if R3 < R7 SUBB A, R3 ; A = R7 - R3, carry set if R7 < R3 JC Cant_sub32 ;at this point R7>R3 or R7=R3 JNZ Can_sub32 ;jump if R7>R3 ;if R7 = R3, test for R6>=R2 CLR C MOV A, R6 SUBB A, R2 ; A = R6 - R2, carry set if R6 < R2 JC Cant_sub32 ;at this point R6>R2 or R6=R2 JNZ Can_sub32 ;jump if R7>R3 ;if R6 = R2, test for R5>=R1 CLR C MOV A, R5 SUBB A, R1 ; A = R5 - R1, carry set if R5 < R1 JC Cant_sub32 ;at this point R5>R1 or R5=R1 JNZ Can_sub32 ;jump if R5>R1 ;if R5 = R1, test for R4>=R0 CLR C MOV A, R4 SUBB A, R0 ; A = R4 - R0, carry set if R4 < R0 JC Cant_sub32 Can_sub32: ;subtract the divisor from the partial remainder CLR C MOV A, R4 SUBB A, R0 ; A = R4 - R0 MOV R4, A MOV A, R5 SUBB A, R1 ; A = R5 - R1 - Borrow MOV R5, A MOV A, R6 SUBB A, R2 ; A = R6 - R2 MOV R6, A MOV A, R7 SUBB A, R3 ; A = R7 - R3 - Borrow MOV R7, A SETB C ; shift a 1 into the quotient JMP Quot32 Cant_sub32: ;shift a 0 into the quotient CLR C Quot32: ;shift the carry bit into the quotient CALL Shift_Q32 ; Test for competion DJNZ B, Div_loop32 ; Now we are all done, move the TMP values back into OP MOV OP_0, TMP_0 MOV OP_1, TMP_1 MOV OP_2, TMP_2 MOV OP_3, TMP_3 MOV OP_4, TMP_4 MOV OP_5, TMP_5 MOV OP_6, TMP_6 MOV OP_7, TMP_7 RET Shift_D32: ;shift the dividend one bit to the left and return the MSB in C CLR C MOV A, OP_0 RLC A MOV OP_0, A MOV A, OP_1 RLC A MOV OP_1, A MOV A, OP_2 RLC A MOV OP_2, A MOV A, OP_3 RLC A MOV OP_3, A MOV A, OP_4 RLC A MOV OP_4, A MOV A, OP_5 RLC A MOV OP_5, A MOV A, OP_6 RLC A MOV OP_6, A MOV A, OP_7 RLC A MOV OP_7, A RET Shift_Q32: ;shift the quotent one bit to the left and shift the C into LSB MOV A, TMP_0 RLC A MOV TMP_0, A MOV A, TMP_1 RLC A MOV TMP_1, A MOV A, TMP_2 RLC A MOV TMP_2, A MOV A, TMP_3 RLC A MOV TMP_3, A MOV A, TMP_4 RLC A MOV TMP_4, A MOV A, TMP_5 RLC A MOV TMP_5, A MOV A, TMP_6 RLC A MOV TMP_6, A MOV A, TMP_7 RLC A MOV TMP_7, A RET ;**************************************************************************** ;TRANS: ;**************************************************************************** ; USES INTERNAL ROM STRINGS. ; THIS ROUTINE WILL SEND A MESSAGE OUT OF THE SERIAL PORT. ; TWO VARIABLES WILL BE PASSED TO THIS ROUTINE. ; REGISTER (R4) WILL CONTAIN THE NUMBER OF CHARACTERS TO BE SENT OUT ; REGISTER (DPTR) WILL CONTAIN THE POINTER TO THE STRING LOCATION IN MEMORY. ;**************************************************************************** TRANS: CLR IE.4 ; DISABLE SERIAL INTERRUPT MOV B, R4 ; MOVE INTO B THE CHARACTER COUNT TRANSS: CLR A MOVC A, @A+DPTR ; MOVE CONTINTS AT THE DATA POINTER TO A CLR TI ; CLEAR THE TRANSMIT INTERRUPT BIT MOV SBUF, A ; LOAD BYTE IN SERIAL BUFFER TXWAIT: JNB TI,TXWAIT ; WAIT FOR BYTE TO SHIFT OUT INC DPTR ; INC DATA POINTER DJNZ B,TRANSS ; DECRIMENT CHARACTER COUNTER CLR TI MOV SBUF,#0DH ; SEND CARRIAGE RETURN CRWAIT: JNB TI,CRWAIT CLR TI MOV SBUF,#0AH ; SEND LINE FEED LFWAIT: JNB TI, LFWAIT CLR TI SETB IE.4 ; ENABLE SERIAL INTERRUPT RET ; OUTTA HERE ;**************************************************************************** ;THE TIME DELAYS ;**************************************************************************** ; THIS IS A 27.25 MICRO SEC. TIME DELAY (22.1184Mhz OSC.) 45.21nS OSC. CYCLE. ;**************************************************************************** SD: MOV R5,#18H ; MOVE 18H INTO R5 ( 12 OSC. CYCLES ) SSTAY: DJNZ R5,SSTAY ; 24 OSC. CYCLES * 25 = 27.25uS RET ; 24 OSC. CYCLES ;**************************************************************************** ; THIS IS A 277 MICRO SEC. ;**************************************************************************** TD: MOV R5,#0FFH ; MOVE 0ffH INTO R5 ( 12 OSC. CYCLES ) STAY: DJNZ R5,STAY ; 24 OSC. CYCLES * 255 = 276.7uS RET ; 24 OSC. CYCLES ;**************************************************************************** ; THIS IS A 17.92 MILLI SEC. DELAY. ;**************************************************************************** LTD: MOV R6,#40H ; 17mS ( 12 OSC. CYCLES ) STAYY: CALL TD ; 24 OSC. CYCLES DJNZ R6,STAYY ; (24 OSC. CYCLES * 64) = 69.760uS ; + 64 * (276.7uS + 1.09uS) = 17.78mS. RET ; = 17.85 mS + 69.760uS FOR THE RET = 17.92mS. ;**************************************************************************** ; THIS IS A 35.84 MILLI SEC. DELAY ;**************************************************************************** LLTD: MOV R7,#2 ; APPROX 1 TO 2 SECONDS STAYYY: CALL LTD ; 24 OSC. CYCLES DJNZ R7,STAYYY ; (24 OSC. CYCLES * 2) = 2.18uS. RET ; + (2 * 17.92mS) + 2.18uS FOR RET = 35.84mS. ;**************************************************************************** ;**************************************************************************** ; THIS IS A 1.0 SEC. DELAY ;**************************************************************************** LLLTD: MOV R0,#5 ; APPROX 1 SECOND STAYYYY: CALL LLTD ; 24 OSC. CYCLES DJNZ R0,STAYYYY ; (24 OSC. CYCLES * 2) = 2.18uS. RET ; + (2 * 17.92mS) + 2.18uS FOR RET = 35.84mS. ;**************************************************************************** ;HEXLO:, HEXHI: ;**************************************************************************** ; TABLE USED FOR CONVERTING ASCII HEX TO "REAL" HEX. ; THE REASON THAT WE NEED AN OFF SET IS BECAUSE AN ASCII 41h "A" - 30h = 11h ; NOT 10h. SO THAT IS THE REASON FOR THE OFFSET. GET IT? ;**************************************************************************** ORG 1000H HEXLO: DB 00h,01h,02h,03h DB 04h,05h,06h,07h DB 08h,09h,09h,09h ; OFFSETS DB 09h,09h,09h,09h ; OFFSETS DB 0Ah,0Bh,0Ch,0Dh DB 0Eh,0Fh ORG 1030H HEXHI: DB 00h,10h,20h,30h DB 40h,50h,60h,70h DB 80h,90h,90h,90h ; OFFSETS DB 90h,90h,90h,90h ; OFFSETS DB 0A0h,0B0h,0C0h,0D0h DB 0E0h,0F0h ORG 1050H KEYS: DB 00h, 01h, 02h, 03h DB 04h, 05h, 06h, 07h DB 08h, 09h, 10h, 11h DB 12h, 13h, 14h, 15h ;**************************************************************************** ;**************************************************************************** ; THESE ARE SOME MESSAGES THAT I'M A GONNA USE FOR DEBUG AND INSTANT ; SATISFACTION! ;**************************************************************************** ORG 1100H MEBAD: DB ' THIS IS A TEST ' EOSOK: DB ' ' ;**************************************************************************** END