***** * * This file contains all Examples for section 10 of the User's Manual * ***** ** Equates - Registers will be addressed with Ind,X mode * REGBAS EQU $1000 Starting address for register block PORTB EQU $04 Output port B OC1M EQU $0C OC1M7,OC1M6,OC1M5,OC1M4;OC1M3,-,-,- OC1D EQU $0D OC1D7,OC1D6,OC1D5,OC1D4;OC1D3,-,-,- TCNT EQU $0E Free running counter (16-bit) TIC1 EQU $10 IC1 register (16-bit) TOC1 EQU $16 OC1 register (16-bit) TOC2 EQU $18 OC2 register (16-bit) TOC3 EQU $1A OC3 register (16-bit) TCTL1 EQU $20 OM2,OL2,OM3,OL3;OM4,OL4,OM5,OL5 TCTL2 EQU $21 -,-,EDG1B,EDG1A;EDG2B,EDG2A,EDG3B,EDG3A TMSK1 EQU $22 OC1I,OC2I,OC3I,OC4I;OC5I,IC1I,IC2I,IC3I TFLG1 EQU $23 OC1F,OC2F,OC3F,OC4F;OC5F,IC1F,IC2F,IC3F TMSK2 EQU $24 TOI,RTII,PAOVI,PAII;-,-,PR1,PR0 TFLG2 EQU $25 TOF,RTIF,PAOVF,PAIF;-,-,-,- *** EVB Routine Addresses & Pseudo Vector Equates .OUTA EQU $FFB8 Print character in A-reg .OUTCRL EQU $FFC4 Output .OUTSTO EQU $FFCA Output Msg seg (no ) .OUTSTR EQU $FFC7 Output Msg w/ leading PVIC1 EQU $00E8 EVB Pseudo Vector for IC1 PVTOF EQU $00D0 EVB Pseudo Vector for TOF PVOC2 EQU $00DC EVB Pseudo Vector for OC2 PVOC1 EQU $00DF EVB Pseudo Vector for OC1 *** RAM Variable Assignments ORG $D000 Start variables in EVB RAM (upper half) HDLY RMB 2 Half-cycle delay (in 0.5µS increments) PWMP1P RMB 1 1% of PWM period (1 to 256 cycles) Ex 10-7 PWMDC1 RMB 1 Duty cycle for PWM signal at OC2 pin PWMDC2 RMB 1 Duty cycle for PWM signal at OC3 pin IC1DUN RMB 1 flag: 0-not done,1-pulse measured IC1MOD RMB 1 s/w mode flag: FF-off,0-1st,1-last edge OVCNT1 RMB 1 Overflow count (upper 8-bits of result) RES1 RMB 2 Pulse Width in cycles (16-bits) HTEMP RMB 3 Temp for H6TOD8 (3 bytes) FRSTE RMB 2 Time of first edge (16-bits) PERC RMB 2 Period in cycles (16-bits) TEMP1 RMB 2 Temp for conversion (16-bits) FREQH RMB 2 Freq in Hex (16-bits) HPW RMB 2 Pulse Width (16-bits hex) DBUFR RMB 8 Decimal result buffer (8 bytes ASCII) * Some routines use only first 5 bytes of DBUFR PWMPER RMB 2 Period of PWM signals in (cycles) OFFHI RMB 2 OC2 high offset (calculated) OFFLO RMB 2 OC2 low offset (calculated) ORG $C000 Prog starts in EVB RAM at $C000 *** * TIMER EXAMPLE 10-1a Measuring Period with Input Capture * * Uses polling rather than interrupts. * Measures period between two rising edges at IC1 pin. * Overflows not considered so max period is 65,535 cyc * Min period measurable with this program is about 27 cyc * * This program runs on an EVB board and displays results * on the EVB terminal display. *** PERTOP LDS #$0047 Top of User's stack area on EVB LDX #REGBAS Point to register block LDAA #%00010000 STAA TCTL2,X EDG1B:EDG1A = 0:1, rising edges LDAA #$04 STAA TFLG1,X Clear any old OC1 flag * Ready to detect first rising edge BRCLR TFLG1,X $04 * Loop here until edge * First edge detected LDD TIC1,X Read time of first edge STD FRSTE Save first capture value LDAA #$04 STAA TFLG1,X Clear IC1F before next edge * Ready to capture time of second edge BRCLR TFLG1,X $04 * Loop here until edge * Second edge detected LDD TIC1,X Read time of second edge SUBD FRSTE 2nd - 1st -> D STD PERC Save result (period in cycles) * The period of the signal at the PA2/IC1 pin has been measured * and the time is stored at "PERC" as a 16-bit hex number * representing the number of CPU bus cycles that elapsed * between two rising edges. *** * TIMER EXAMPLE 10-1b Changing Period to Frequency * * The period found in example 10-1a is expressed as a number * of bus cycles (@E=2MHz, 1 bus cycle=0.5µS) and it is * currently in the D-reg and at "PERC". Values < or = $20 * will be considered too small (freq too high) to be * accurately measured with this program and will be trapped * out to make the period to frequency conversion program easier. * $0021 corresponds to 60,606 Hz, $FFFF is 30.5 Hz. *** LDX PERC Period in cycles (16-bits) CPD #32 ($20) Check against min allowed BHI OKP Skip if OK JMP OUTRNG Else go say it was too small OKP LDD #32 X=period; D=32 FDIV D/X -> X; r -> D STX TEMP1 (Freq*16)Ö1,000,000; radix left of MSB * * We now have frequency but it isn't in a good displayable * form yet. If we move the binary radix 16 places to the right * we would have a 16-bit integer representing * [(2**20)/(10**6) x freq] or [((1,048,576)/(1,000,000))*freq]. * By adding and subtracting binary multiples of the freq we * will arrive at [((1,000,000)/(1,000,000))*freq] * * 1,048,576 16-bit starting value ((2**20)freq)Ö(10**6) * - 32,768 2**15 * - 16,384 2**14 * + 512 2**9 * + 64 2**6 * =1,000,000 * freq * * The limitation of 33 ($21) cycles min was selected so * (1,048,576/1,000,000)*freq would fit in 16-bits so we would * only need 1 FDIV. Although it is pretty easy to extend the * precision of an FDIV. * * The partial results which are added and subtracted in this * program may have an error of ±1 LSB ea. because I trunkated * rather than rounding. * LDD TEMP1 (2**20)f; where f=freqÖ(10**6) LSRD LSRD LSRD A=(2**9)f; D=(2**17)f CLR FREQH Clear upper half of hex freq location STAA FREQH+1 FREQH is a temp = 512f LSRD LSRD now D=(2**15)f or 32,768f STD TEMP1 Needs to be in mem for 16-bit subtract XGDX D=(2**20)f; X=(2**15)f SUBD TEMP1 First subtraction (-32K) XGDX Working result -> X; D=(2**15)f LSRD A=(2**6)f; D=(2**14)f STD TEMP1 Put in mem so you can subtract ADDA FREQH+1 (512+64)f STAA FREQH+1 Update low half of FREQH XGDX D=1,015,808*f; X=junk SUBD TEMP1 999,424*f ADDD FREQH 1,000,000*f = frequency STD FREQH Save the 16-bit binary result * * Since most of us don't think in hexidecimal, let's change to * decimal before printing. The subroutine (HTODP) is shown at * the end of this listing. * * The display will look like... * *ppppp Cyc fffff Hz ---or like--- *Freq. is too high * * where ppppp is period in cycles & fffff is freq. (decimal) * * EVB subroutines will be used and when done we will jump * back to the beginning and repeat continuously. * JSR .OUTCRL Print a LDX #PERC Point at hex period JSR HTOD Convert to 5 digit decimal JSR P5DEC Print 5 digi decimal (not leading 0s) LDX #MSGCYC Point at " Cycles " JSR .OUTSTO Print message segment LDX #FREQH Point at hex frequency JSR HTOD Convert to 5 digit decimal JSR P5DEC Print 5 digi decimal (not leading 0s) LDX #MSGHZ Point at " Hz" JSR .OUTSTO Print message segment JTOP JMP PERTOP Go back to top & measure another period OUTRNG LDX #MSGER1 Point at "Freq. is too high" JSR .OUTSTR Print message w/ leading BRA JTOP Go back to top & measure another period * ***** END Ex 10-1b *** * TIMER EXAMPLE 10-2 Measuring Pulses With Input Capture * * Uses interrupts. * Measures time between a rising edge and a falling edge * (period of a positive pulse) at the IC1 pin. * Overflows not considered so max is 65,536 cyc * Min time measurable with this program is about __ cyc * * This program runs on an EVB board and displays results * on the EVB terminal display. *** * Initialization Portion * PWINZ LDS #$0047 Top of User's stack area on EVB LDAA #$7E Jump (extended) Opcode STAA PVIC1 IC1 Pseudo Vector LDX #SV2IC1 Address of IC1 service routine STX PVIC1+1 Finish jump instruc to IC1 routine * Main Program Portion of Pulse Width program * PWTOP LDX #REGBAS Point to register block LDAA #%00010000 Top of Main for PW24 prog STAA TCTL2,X EDG1B:EDG1A = 0:1, IC1 rising edges LDAA #$FF STAA IC1MOD FF-IC1 off; 0-1st edge; 1-last edge CLR IC1DUN Signal pulse not done BCLR TFLG1,X $FB clear IC1F (if any) BSET TMSK1,X $04 enable IC1 interrupts CLI Enable Interrupts WAITL2 LDAA IC1DUN Sets after pulse done BEQ WAITL2 Tight loop till pulse has been timed SEI Pulse done, disable interrupts * Display pulse width as xx,xxx microseconds (32,768 max) JSR .OUTCRL Begin printing result LDD HPW number of cyc (0.5µS/cyc) LSRD 16-bit Ö2 to change to µS BCC ARNUP2 ? need to round result ? ADDD #1 yes; round up ARNUP2 STD HPW Update hex Pulse width LDX #HPW Point at hex pulse width JSR HTOD Convert to 5 digit decimal JSR P5DEC Print 5 digi decimal (not leading 0s) LDX #MSGMS Point at rest of display line JSR .OUTSTO Print " millieconds" BRA PWTOP Goto top of main & repeat * * END of Main Program Portion *** * SV2IC1 - Input Capture 1 service routine * * Called first when a rising edge is detected and again when * a falling edge is detected. *** SV2IC1 LDX #REGBAS point at top of register block INC IC1MOD $FF->0 at 1st edge; 0->1 at 2nd BNE NO1ST2 if not 0, this is trailing edge * Process leading edge of pulse LDD TIC1,X read time of first edge STD FRSTE save till next capture * Reconfigure IC1 for trailing falling edge BCLR TCTL2,X $30 EDG1B:EDG1A->0:0 BSET TCTL2,X $20 EDG1B:EDG1A->1:0 BRA OU2IC1 done processing first edge * Process trailing edge of pulse NO1ST2 LDD TIC1,X get time of trailing edge SUBD FRSTE time of last minus time of first STD HPW update result BCLR TCTL2,X $30 disable IC1 LDAA #1 STAA IC1DUN signal pulse measured OU2IC1 BCLR TFLG1,X $FB clear IC1F RTI ** Return from IC1 service ** * ***** END Ex 10-2 *** * * TIMER EXAMPLE 10-3 Measuring Long Periods with IC * * Uses interrupts. * Measures period between two rising edges at the IC1 pin. * Overflows are counted so max is 16,777,215 cyc (~8.38 Sec) * Min time measurable with this program is about 70 cyc * * This program runs on an EVB board and displays results * on the EVB terminal display. *** * Initialization Portion * P24INZ LDS #$0047 Top of User's stack area on EVB LDAA #$7E Jump (extended) Opcode STAA PVTOF TOF Pseudo Vector see manual text STAA PVIC1 IC1 Pseudo Vector LDX #SV3TOF Address of TOF service routine STX PVTOF+1 Finish jump instruc to TOF routine LDX #SV3IC1 Address of IC1 service routine STX PVIC1+1 Finish jump instruc to IC1 routine * Main Program Portion of PER24 program * PER24T LDX #REGBAS Point to register block LDAA #%00010000 Top of Main for PER24 prog STAA TCTL2,X EDG1B:EDG1A = 0:1, IC1 rising edges LDAA #$FF STAA IC1MOD FF-IC1 off; 0-1st edge; 1-last edge CLR IC1DUN Signal period not done BCLR TFLG1,X $FB clear IC1F (if any) BCLR TFLG2,X $7F clear TOF (if any) BSET TMSK1,X $04 enable IC1 interrupts BSET TMSK2,X $80 enable TOF interrupts CLI Enable Interrupts WAITL3 LDAA IC1DUN Sets after pulse done BEQ WAITL3 Tight loop till pulse has been timed SEI Pulse done, disable interrupts * Display period as x.xxxxxx Seconds (to nearest µS) LDX #OVCNT1 Point at upper byte of 6 digit hex LSR 0,X 24-bit Ö2 to change to µS ROR 1,X (1cyc=0.5µS) ROR 2,X RORs include carry BCC ARNUP3 ? need to round result ? INC 2,X yes; round up BNE ARNUP3 carry to middle byte ? INC 1,X yes BNE ARNUP3 carry to high byte ? INC 0,X yes ARNUP3 JSR H6TOD8 Convert to 8 digit decimal JSR .OUTCRL Begin printing result LDX #DBUFR+1 Start at 2nd digit (1st is 0) LDAA 0,X Seconds digit JSR .OUTA Print LDAA #'.' ASCII period JSR .OUTA Print DUMPLP INX Advance pointer to next digt LDAA 0,X get digit JSR .OUTA Print it CPX #DBUFR+7 Was that the last ? BNE DUMPLP If not continue LDX #MSGSEC Point at rest of display line JSR .OUTSTO Print " Seconds" BRA PER24T Goto top of main & repeat * * END of Main Program Portion *** * SV3TOF - Timer Overflow service routine * * Called whenever any timer overflow is detected. If the IC1 * pulse measurement is in progress (IC1MOD positive) then * the overflow counter (upper 8-bits of period) is incremented. *** SV3TOF TST IC1MOD if 0 or 1, IC1 active so count TOFs BMI OU3TOF if neg, IC1 not active INC OVCNT1 increment IC1 overflow count OU3TOF LDAA #$80 STAA REGBAS+TFLG2 Clear overflow flag RTI ** Return from TOF service ** *** * SV3IC1 - Input Capture 1 service routine * * Called first when a rising edge is detected and again when * another rising edge is detected. *** SV3IC1 LDX #REGBAS point at top of register block INC IC1MOD $FF->0 at 1st edge; 0->1 at 2nd BNE NO1ST3 if not 0, this is second edge * Process first edge of pulse CLR OVCNT1 Zero the overflow count LDD TIC1,X Read time of first edge STD RES1 Save till next capture BMI OU3IC1 Done if IC was before any overflow LDAA TFLG2,X Check for TOF in MSB BPL OU3IC1 If no overflow, you're done DEC OVCNT1 This TOF shouldn't count * decrement OVCNT1 to -1, TOF svc routine will inc to zero BRA OU3IC1 Done processing first edge * Process second edge of pulse NO1ST3 LDD TIC1,X Get time of second edge BMI ARNOV1 If MSB=1, skip TOF check TST TFLG2,X Check for overflow BPL ARNOV1 If no TOF, skip increment INC OVCNT1 TOF was before edge so count it ARNOV1 SUBD RES1 Time of last minus time of first STD RES1 Update result BCC RES1OK Check for borrow DEC OVCNT1 If borrow, fix overflow count RES1OK BCLR TCTL2,X $30 Disable IC1 LDAA #1 STAA IC1DUN Signal pulse measured OU3IC1 BCLR TFLG1,X $FB Clear IC1F RTI ** Return from IC1 service ** * ***** END Ex 10-3 *** * * TIMER EXAMPLE 10-4 Simple Output Compare Example * * Ex10-4 uses polled mode. * Generate a 10mS period like you would use to time an EE write * but rather than wearout the EEPROM just change an output pin * * Example 10-4 runs on an EVB board and drives PB0 high for * 10mS once every 30mS so you can see on an oscilloscope. *** INZA LDX #REGBAS Point to register block LDAA #$80 STAA TFLG1,X Clear any pending OC1F flag CLR PORTB,X Initialize port B to zeros TOP4A LDAA #1 Top of Ex10-4a STAA PORTB,X Set LSB of port B * This is where the 10mS delay part actually starts * LDD TCNT,X Get current timer count ADDD #20000 What will count be in 10mS? STD TOC1,X Set OC1 to trigger then LP1 BRCLR TFLG1,X $80 LP1 Loop here till OC1F=1 * *Delay is actually done here; rest is just support BCLR TFLG1,X $7F Clear OC1F CLR PORTB,X Clear PB0 pin LDY #5710 5710*(7~/loop)= about 20mS DLP1 DEY Top of software delay loop BNE DLP1 Loop 'till Y is zero BRA TOP4A Repeat continuously for O-scope * ***** END Ex 10-4 *** * * TIMER EXAMPLE 10-5 Square wave using Output Compare * * Ex10-5 uses interrupts. * Generate a square wave at the PA6 output pin using OC2 * * This program runs on an EVB board. The half-cycle delay * time is entered into the double byte variable "HDLY" at * $D000,D001 with a memory modify before going to the program. *** TOP5 LDS #$0047 Top of User's stack area on EVB LDAA #$7E Jump (extended) Opcode STAA PVOC2 OC2 Pseudo Vector see manual text LDX #SV5OC2 Address of OC2 service routine STX PVOC2+1 Finish jump instruc to TOF routine LDX #REGBAS Point to register block LDAA #%01000000 OM2:OL2 = 0:1 STAA TCTL1,X Setup OC2 for toggle on each compare STAA TFLG1,X Clear any pending OC2F STAA TMSK1,X Enable OC2 interrupts CLI Enable Interrupts BRA * Interrupt driven; so twiddle thumbs *** * SV5OC2 - Output Compare 2 service routine * * Called at each OC2 interrupt. *** SV5OC2 LDD HDLY Get delay time for 1/2 cycle ADDD TOC2,X Add to last compare value STD TOC2,X Update OC2 (schedule next edge) BCLR TFLG1,X $BF Clear OC2F RTI ** Return from OC2 service ** * ***** END Ex 10-5 *** * TIMER EXAMPLE 10-6 * OC1, OC2, and OC3 used together to produce 2 PWM signals * * OC1 controls two pins of port A in conjunction with OC2 and OC3 * OC1 drives the period and the scheduling of OC2 and OC3 * OC2 & OC3 automatically control pins but don't generate interrupts * Set "PWMP1P", "PWMDC1" & "PWMDC2" manually before running this example * "PWMP1P" sets size of a 1% segment of PWM period (cycles) * min PWMP1P for this program is 2 (period = 200 cycles) * "PWMDC1" sets Duty cycle for OC2 pin in % (0 to $64 hex) * "PWMDC2" sets Duty cycle for OC3 pin in % (0 to $64 hex) * Duty cycle (%) will be translated into a # of cycles offset * and period will be calculated as (100 * PWMP1P) at prog start * PA4 pin will toggle at each OC1 compare as a scope reference signal * * Produces high going PWM signals of the period and duty cycle specified. * Note actually only produces PWMs of 50% to 100% because spec'd duty of * 0 to 50% is changed to low going PWM w/ duty cyc = [100% - spec(0-50)] * * This program runs on an EVB board and drives output pins. * An oscilloscope is used to study the results. *** INZ6 LDS #$0047 Top of User's stack area on EVB LDAA #$7E Jump (extended) Opcode STAA PVOC1 OC1 Pseudo Vector see manual text LDX #SV6OC1 Address of OC1 service routine STX PVOC1+1 Finish jump instruc to OC1 routine LDX #REGBAS Point to register block LDAA #%01010000 OMx:OLx = 0:1 for toggle STAA TCTL1,X OC2 and OC3 for toggle LDAA #%01110000 OC1M6,5, & 4 = 1 STAA OC1M,X To control OC2/PA6, OC3/PA5, & PA4 CLRB Build OC1D initial value in B LDAA PWMDC1 Check for OC2 duty > or = 50% CMPA #50 BLS ARNZ61 If <50% OC1 drives low, OC2 toggles high ADDB #%01000000 else OC1 drives high, OC2 toggles low ARNZ61 LDAA PWMDC2 Check for OC3 duty > or = 50% CMPA #50 BLS ARNZ62 If <50% OC1 drives low, OC3 toggles high ADDB #%00100000 else OC1 drives high, OC3 toggles low ARNZ62 STAB OC1D,X Store starting value for OC1D * Calculate period & duty cycle as cycle count offsets LDAA PWMP1P 1% of period LDAB #100 MUL 100 * PWMP1P = PWMPER STD PWMPER Store period STD TOC1,X Start first PWM period at TCNT=PWMPER LDAA PWMDC1 Calculate offset for OC2 BSR CALOFF Adj duty as needed and calc offset STD TOC2,X Schedule first OC2 toggle LDAA PWMDC2 Calculate offset for OC3 BSR CALOFF Adj duty as needed and calc offset STD TOC3,X Schedule first OC3 toggle * Finish initialization LDAA #$80 STAA TFLG1,X OC1F=1 to clear any old OC1 flag STAA TMSK1,X then OC1I=1 to enable OC1 interrupt CLI BRA * From now on OC1 interrupt runs PWMs *** Local subroutine for changing duty cycle to an offset count * If duty < 50% ($32) change to 100-duty * If duty >100% ($64) force to $64 * Finally mult by 1% of period (cyc) * Enter with PWMDCx duty in A-reg, Return offset in D-reg CALOFF CMPA #50 Check for 0-49% BHS ARN6A Around fixup TAB If < 50% - set to 100 - duty cycle LDAA #100 SBA A-B to A ARN6A CMPA #100 Check for > 100% BLS ARN6B LDAA #100 If > 100% - set to 100% ARN6B LDAB PWMP1P MUL PWMP1P * adjusted duty cycle = OFFOCx RTS ** Return from CALOFF ** * ** *** * SV6OC1 - Output Compare 1 service routine *** SV6OC1 LDX #REGBAS Point to register block LDAA OC1D,X Make PA4 change state at next OC1 compare EORA #%00010000 Inverts OC1D4 bit (PA4 pin control) STAA OC1D,X Update next OC1 automatic pattern LDD TOC2,X Get last OC2 compare value ADDD PWMPER Add count equiv to period STD TOC2,X Update OC2 (schedule next OC2) LDD TOC3,X Get last OC3 compare value ADDD PWMPER Add count equiv to period STD TOC3,X Update OC3 (schedule next OC3) LDD TOC1,X Get last OC1 compare value ADDD PWMPER Add count equiv to period STD TOC1,X Update OC1 (schedule next OC1) BCLR TFLG1,X $7F Clear OC1F RTI ** Return from OC1 service ** * ***** END Ex 10-6 *** * TIMER EXAMPLE 10-7 * OC2 used alone to produce one PWM signal * * OC2 controls period and duty cycle of one port A pin * Set "PWMP1P" & "PWMDC1" manually before running this example * "PWMP1P" sets size of a 1% segment of PWM period (cycles) * "PWMDC1" sets Duty cycle for OC2 pin in % - NOTE: This program will * not work properly with values of duty cycle too near 0 or 100% * Refer to User's Manual text for discussions * Program calculates "OFFHI" and "OFFLO" at start * * This program runs on an EVB board and drives the PA6/OC2 pin. * An oscilloscope is used to study the results. *** INZ7 LDS #$0047 Top of User's stack area on EVB LDAA #$7E Jump (extended) Opcode STAA PVOC2 OC2 Pseudo Vector LDX #SV7OC2 Address of OC2 service routine STX PVOC2+1 Finish jump instruc to OC2 routine LDX #REGBAS Point to register block LDAA PWMDC1 Calculate OC2 high time LDAB PWMP1P 1% of period MUL PWMP1P * duty cycle = high part of period STD OFFHI Save high offset LDAA PWMP1P 1% of period LDAB #100 MUL 100 * PWMP1P = period SUBD OFFHI period - high time = low time STD OFFLO Store low offset * Finish initialization LDAA #%11000000 OM2:OM1 = 1:1 for set pin high STAA TCTL1,X First OC2 starts first high time LDD #$0000 STD TOC2,X Start first PWM period at TCNT=$0000 LDAA #$40 STAA TFLG1,X OC2F=1 to clear any old OC2 flag STAA TMSK1,X then OC2I=1 to enable OC2 interrupt CLI BRA * From now on OC2 interrupt runs PWM *** * SV7OC2 - Output Compare 2 service routine *** SV7OC2 LDX #REGBAS Point to register block BRCLR TCTL1,X %01000000 ADDLO See which half of cyc LDD OFFHI High part so we will add OFFHI to OC2 BRA UPOC2 ADDLO LDD OFFLO Low part so we will add OFFLO to OC2 UPOC2 ADDD TOC2,X Add to last compare value STD TOC2,X Update OC2 (schedule next edge) LDAA TCTL1,X Change OL2 to setup for next edge EORA #%01000000 Inverts OL2 bit STAA TCTL1,X Update control reg BCLR TFLG1,X $BF Clear OC2F RTI ** Return from OC2 service ** * ***** END Ex 10-7 *** * General purpose subroutines *** *** * P5DEC - Subroutine to display a five digit decimal number at "DBUFR". * Prints in the form "xx,xxx" with leading zeros suppressed. * Prints 6 columns, leading spaces, units always prints (0-9) * * Calls EVB routine ".OUTA" * Calls "SKP1" with BSR to advance X and print a leading space * SKP1 subroutine immediately follows P5DEC * All registers are unchanged upon return from P5DEC *** P5DEC PSHX Save registers PSHB PSHA LDX #DBUFR Point at decimal (MS character) LDAA #$30 Chk for leading 0s (ASCII) CMPA 0,X Check 10,000s digit BNE P10K Start at 10k digit BSR SKP1 INX & print a space CMPA 0,X Check 1,000s digit (a still=ASCII) BNE P1K Start at 1k digit BSR SKP1 INX & print a space BSR SKP1 INX & print a space (extra 1 for ,) DEX just wanted the so back up 1 CMPA 0,X Check 100s digit BNE P100 Start at 100s digit BSR SKP1 INX & print a space CMPA 0,X Check 10s digit BNE P10 Start at 10s digit BSR SKP1 INX & print a space BRA P1 Start at 1s digit (default) P10K LDAA 0,X 10,000s digit JSR .OUTA Print 10,000s digit INX Advance pointer to next digt P1K LDAA 0,X 1,000s digit JSR .OUTA Print it LDAA #',' ASCII comma JSR .OUTA Print INX Advance pointer to next digt P100 LDAA 0,X 100s digit JSR .OUTA Print it INX Advance pointer to next digt P10 LDAA 0,X 10s digit JSR .OUTA Print it INX Advance pointer to next digt P1 LDAA 0,X 1s digit JSR .OUTA Print it PULA Restore registers PULB PULX RTS ** Return from P5DEC ** *** Local SKP1 subroutine (called from above with BSRs) SKP1 PSHA Save A INX Advance X LDAA #$20 ASCII JSR .OUTA Print the PULA Restore A RTS ** Return from SKP1 ** *** * HTOD - Subroutine to convert a 16-bit hex number to a * 5 digit decimal number. * * Uses 5 byte variable "DBUFR" for decimal ASCII result * On entry X points to hex value to be converted & displayed * All registers are unchanged upon return *** HTOD PSHX Save registers PSHB PSHA LDD 0,X D=hex value to be converted LDX #10000 IDIV freqÖ10,000 -> X; r -> D XGDX Save r in X; 10,000s digit in D (A:B) ADDB #$30 Convert to ASCII STAB DBUFR Store in decimal buffer XGDX r back to D LDX #1000 IDIV rÖ1,000 -> X; r -> D XGDX Save r in X; 1,000s digit in D (A:B) ADDB #$30 Convert to ASCII STAB DBUFR+1 Store in decimal buffer XGDX r back to D LDX #100 IDIV rÖ100 -> X; r -> D XGDX Save r in X; 100s digit in D (A:B) ADDB #$30 Convert to ASCII STAB DBUFR+2 Store in decimal buffer XGDX r back to D LDX #10 IDIV rÖ10 -> X; r in D (B is units digit) ADDB #$30 Convert to ASCII STAB DBUFR+4 Store to units digit XGDX 10s digit to D (A:B) ADDB #$30 Convert to ASCII STAB DBUFR+3 Store in decimal buffer PULA Restore registers PULB PULX RTS ** Return ** *** * H6TOD8 - Subroutine to convert a 24-bit hex number to an * 8 digit decimal number. * * Uses 3 byte variable "HTEMP" for hex working value * Uses 8 byte variable "DBUFR" for decimal ASCII result * On entry X points to hex value to be converted & displayed * All registers are unchanged upon return *** H6TOD8 PSHY Save registers PSHX PSHB PSHA LDD 1,X Move hex to HTEMP for conversion STD HTEMP+1 Two lower bytes moved LDAA 0,X Upper byte STAA HTEMP LDY #DBUFR Point at MS digit of decimal buffer LDX #CON10M Point at first 24-bit constant HTDLP CLRA A keeps track of # of subtractions HLPIN INCA Inner loop; once per subtraction LDAB HTEMP+2 Start 24-bit subtract SUBB 2,X STAB HTEMP+2 Update low byte LDAB HTEMP+1 Middle byte SBCB 1,X Sub with carry STAB HTEMP+1 Update middle byte LDAB HTEMP High byte SBCB 0,X STAB HTEMP Update high byte BCC HLPIN If no borrow; subtract again LDAB HTEMP+2 Last subtract too far; add back ADDB 2,X STAB HTEMP+2 Update low byte LDAB HTEMP+1 Middle byte ADCB 1,X Sub with carry STAB HTEMP+1 Update middle byte LDAB HTEMP High byte ADCB 0,X STAB HTEMP Update high byte ADDA #$2F Convert digit to ASCII STAA 0,Y Store to decimal buffer INY Point to next decimal digit INX Point to next 24-bit const INX INX CPX #CONEND See if done yet BNE HTDLP If not done, do nxt digit LDAA HTEMP+2 Get 1s digit ADDA #$30 Convert to ASCII STAA 0,Y Store to last decimal digit PULA Restore registers PULB PULX PULY RTS ** Return from H6TOD8 ** * * Display Messages & Constants * MSGCYC FCC ' Cycles ' FCB $04 End-of-message mark MSGHZ FCC ' Hz' FCB $04 End-of-message mark MSGER1 FCC 'Freq. is too high' FCB $04 End-of-message mark MSGMS FCC ' microseconds' FCB $04 End-of-message mark MSGSEC FCC ' Seconds' FCB $04 End-of-message mark CON10M FCB $98,$96,$80 = 24-bit equiv of 10,000,000 FCB $0F,$42,$40 = 24-bit equiv of 1,000,000 FCB $01,$86,$A0 = 24-bit equiv of 100,000 FCB $00,$27,$10 = 24-bit equiv of 10,000 FCB $00,$03,$E8 = 24-bit equiv of 1,000 FCB $00,$00,$64 = 24-bit equiv of 100 FCB $00,$00,$0A = 24-bit equiv of 10 CONEND EQU * Don't need 1s const * END OF FILE