;*********************************************************************** ;* ;* Project: "metronoom.asm" ;* OH, ma 2000 ;* ;* ;*********************************************************************** .nolist .include "1200def.inc" .list ; ---- define I/O ---- ; ; PORTD[0..6] = LED segment control ; [0..3]: BCD code (0d..9d) ; [4..6]: Segment # (Segment 0 is NOT USED!) ; PORTB[0..2] = metronome beats ; PORTB[3..7] = Speed keys up/down/preselects .equ DIR_PORTB = 0b00000011 .equ DIR_PORTD = 0b11111111 .equ O_BEAT = PINB0 .equ O_BEAT2 = PINB1 .equ I_SPDUP = PINB2 .equ I_SPDDOWN = PINB3 .equ I_SPDPRE1 = PINB4 .equ I_SPDPRE2 = PINB5 .equ I_SPDPRE3 = PINB6 .equ I_MEASURE = PINB7 .equ C_PRESEL1 = -97 ;RSPEED FOR 60 beats/min (correct) .equ C_PRESEL2 = -49 ;RSPEED FOR 120 beats/min (- 1 (0.5dd) ) .equ C_PRESEL3 = -32 ;RSPEED FOR 180 beats/min (+ 3 (3.0dd) ) .equ C_LEDDELAY = 45 ; ; --- Register defines --- ; These registers are for the main program. ; exclusive registers are used in the ; timer-routine & cannot be changed in ; subroutines... ; .def RSTACK = r15 ;[* EXCLUSIVE] for timer-interupt routine .def RTEMP = r16 .def RLED = r16 .def RTEMP2 = r18 .def RBUSY = r19 ;'Activate key' only when key is REALEASED .def RCYCLE = r20 ;[* EXCLUSIVE] Inner speed (for 10 ms resolution ) .def RSPEED = r21 ;[* EXCLUSIVE] Outer speed .def RSTACK_TEMP = r22 ;[* EXCLUSIVE] Temp used in timer .def RMEASURE = r23 ;[* EXCLUSIVE] measure 1:4, 2:4, 3:4 , 4:4 ; ; ::: Interupt vectors ::: ; rjmp RESET ;Reset rjmp RESET ;IRQ0 (n/a) rjmp TIMER0 ;used for beat rjmp RESET ;Analg Comparator (n/a) ; ; ::: TIMER ROUTINE ::: ; ; Tone generatie: Every ( ( (1MHz)/speed)/1024 )/10 = 97.56 Hz = 0.01024 sec ; Rspeed = timer counter ; RCYCLE = 10 (or 11) ; div 1024 = done by timer settings (*: infra) ; Range (Hz)..... : 0.38 Hz (Spd:255) .. 0.76 Hz (Spd:128) .. 3.61 Hz (Spd:27) ; " (beats/min)..: 22.8 .. 45.6 .. 216 ; TIMER0: in RSTACK, SREG ; Save basic regs ; --- clear output sbi PORTB, O_BEAT ; OUTPUT ZERO sbi PORTB, O_BEAT2 ; OUTPUT ZERO to measure (1,2,3,4:4) ; --- inner cycle (master beat) inc RCYCLE mov RSTACK_TEMP,RCYCLE andi RSTACK_TEMP,0x0f cpi RSTACK_TEMP,10 ; TIMER0 op CY/1024= 1 msec, sample==10 dus ; Resolutie= 0.01 sec brne TIMER1_C ; Inner cycle is not yet completed.. andi RCYCLE,0xf0 ;Reset inner counter cbi PORTB, O_BEAT ; --- outer cycle (measure) swap RCYCLE inc RCYCLE ; mov RSTACK_TEMP,RCYCLE ; andi RSTACK_TEMP,0x0f --high nibble should be zero !! ; cp RSTACK_TEMP,RMEASURE ; cp RCYCLE,RMEASURE ; outer cycle (measure) brne TIMER0_C ; Outer cycle is not yet completed.. clr RCYCLE cbi PORTB, O_BEAT2 TIMER0_C: swap RCYCLE TIMER1_C: out TCNT0, RSPEED out SREG, RSTACK reti ;*************************************************************************** ;* ;* "div16u" - 16/16 Bit Unsigned Division ;* ;* This subroutine divides the two 16-bit numbers ;* "dd8uH:dd8uL" (dividend) and "dv16uH:dv16uL" (divisor). ;* The result is placed in "dres16uH:dres16uL" and the remainder in ;* "drem16uH:drem16uL". ;* ;*************************************************************************** .def RREML =r4 .def RREMH =r5 .def RRESL =r16 .def RRESH =r17 .def RDDDL =r16 .def RDDDH =r17 .def RDIVL =r18 .def RDIVH =r6 .def RCNT =r19 .def RBIN =r16 ;8-bit binary value .def RBCDL =r16 ;BCD result MSD .def RBCDH =r17 ;BCD result LSD ;***** Code displayspeed: ldi RDDDH,high(5859) ;Operation = (1Mhz/1024/10) / RSPEED = 5859/Rspeed ldi RDDDL,low(5859) mov RDIVL,RSPEED ;RSPEED is NEGATIEF ! neg RDIVL clr RDIVH div16u: clr RREML ;clear remainder Low byte sub RREMH,RREMH ;clear remainder High byte and carry ldi RCNT,17 ;init loop counter d16u_1: rol RDDDL ;shift left dividend rol RDDDH dec RCNT ;decrement counter breq disp_bcd ;if done... convert to BCD and output in LED DISPLAY rol RREML ;shift dividend into remainder rol RREMH sub RREML,RDIVL ;remainder = remainder - divisor sbc RREMH,RDIVH ; brcc d16u_3 ;if result negative add RREML,RDIVL ; restore remainder adc RREMH,RDIVH clc ; clear carry to be shifted into result rjmp d16u_1 ;else d16u_3: sec ; set carry to be shifted into result rjmp d16u_1 disp_bcd: ; --- convert RRESL to BCD ; IN: RBIN = RRESL ;bin2bcd8: clr RBCDH ;clear result MSD bBCD8_1:subi RBIN,10 ;input = input - 10 (digit) brcs bBCD8_2 ;abort if carry set inc RBCDH ;inc MSD rjmp bBCD8_1 ;loop again bBCD8_2:subi RBIN,-10 ;compensate extra subtraction ; --- must SAVE RBCDH !! ; mov RLED,RBCDL ; swap RLED ori RLED,0x10 rcall ledshow ; --- same as above (bin to BCD) but switch BCD_HIGH and BCD_LOW !!! clr RBCDL ;clear result MSD bBCD8_3:subi RBCDH,10 ;input = input - 10 (digit) brcs bBCD8_4 ;abort if carry set inc RBCDL ;inc MSD rjmp bBCD8_3 ;loop again bBCD8_4:subi RBCDH,-10 ;compensate extra subtraction ; --- RBCDL = hondertallen (segment 3) ; mov RLED,RBCDL ; swap RLED ori RLED,0x30 rcall ledshow ; --- RBCDH = tientallen (segment 2) mov RLED,RBCDH ; swap RLED ori RLED,0x20 rcall ledshow ret ;*************************************************************************** ;* ;* " Visualise one LED segment " ;* RLED: LSN = BCD value ;* MSN = #LED (1..4), 4=measure ;* ;* EERST : digit select DAN: select+value DAN: value alleen ;* ;* ;*************************************************************************** ledshow: mov RTEMP2,RLED ;segment select ONLY ! andi RTEMP2,0xf0 out PORTD,RTEMP2 ldi RTEMP2,C_LEDDELAY ;wait... led_delay1: dec RTEMP2 brne led_delay1 mov RTEMP2,RLED ;show segment select AND LED value out PORTD,RTEMP2 ldi RTEMP2,C_LEDDELAY led_delay2: dec RTEMP2 brne led_delay2 mov RTEMP2,RLED ;only value (segment# OFF = store value) andi RTEMP2,0x0f out PORTD,RTEMP2 ldi RTEMP2,C_LEDDELAY led_delay3: dec RTEMP2 brne led_delay3 ret ; :::::::::::::::::::::::::::: ; ::::: Main program ::::::::: ; :::::::::::::::::::::::::::: RESET: ; ; --- init i/o - ports --- ; ldi RTEMP, DIR_PORTB ;PORTB, out DDRB, RTEMP clr RTEMP out PORTB, RTEMP ;init output B ldi RTEMP, DIR_PORTD ;PORTD, out DDRD, RTEMP clr RTEMP out PORTD, RTEMP ;init output D ; --- INIT µP TIMER --- ; pre: RTEMP = 00 out GIMSK, RTEMP ;external interupts out TIFR, RTEMP ;overflow flag reset ldi RTEMP, 0x02 ;overflow int enable out TIMSK, RTEMP ldi RTEMP, 0x01 ; 1:CY 2:CY/8 3:CY/64 4:CY/256 5:CY/1024 Clock divider ; ldi RTEMP, 0x05 ; CY/1024 clock divider (%^&) out TCCR0, RTEMP ; --- init speed,measure and LEDs ldi RLED,0x40 ;"reset display" rcall ledshow ; is done in the book, BUT WHY ?? ldi RLED,0x30 rcall ledshow ldi RLED,0x20 rcall ledshow ldi RLED,0x10 rcall ledshow clr RLED ;NOOOO IDEA WHY THIS IS GOOD ... rcall ledshow ;LED0 is supposed to be empty ldi RSPEED,-73 out TCNT0, RSPEED ; UP COUNTER for TIMER rcall displayspeed clr RCYCLE ; Init cycle counter ldi RMEASURE,2 ; Init outer cycle counter (2:4) mov RLED,RMEASURE ;low nibble = led BCD contents ; swap RLED ori RLED,0x40 ;LED 4 = Measure rcall ledshow sei ; glob int enable ; ; ------ MAIN LOOP ----- ; clr RBUSY ; ---- Input SPEED UP --- CTRL_MAIN: sbis PINB, I_SPDUP ;'Speed Up' is still pressed, set flag and cont'd rjmp CTRL1_PSH ;Action on key release ? cpi RBUSY,0x01 brne CTRL1_Ctd ;was depressing the correct key ?? inc RSPEED inc RSPEED rcall displayspeed clr RBUSY ;reset key status rjmp CTRL1_Ctd CTRL1_PSH: ldi RBUSY, 0x01 CTRL1_Ctd: ; ---- Input SPEED DOWN --- sbis PINB, I_SPDDOWN ;'Speed Down' is still pressed, set flag and cont'd rjmp CTRL2_PSH ;Action on key release ? cpi RBUSY,0x02 brne CTRL2_Ctd ;was depressing the correct key ?? dec RSPEED dec RSPEED rcall displayspeed clr RBUSY ;reset key status rjmp CTRL2_Ctd CTRL2_PSH: ldi RBUSY, 0x02 CTRL2_Ctd: ; ---- Input MEASURE 1..4:4 --- sbis PINB, I_MEASURE ;'Measure select' is still pressed, set flag and cont'd rjmp CTRL3_PSH ;Action on key release ? cpi RBUSY,0x03 brne CTRL3_Ctd ;was depressing the correct key ?? andi RMEASURE,0b00000011 ;1,2,3,4 -> 1,2,3,0 inc RMEASURE ; -> 2,3,4,1 andi RCYCLE,0x0f ;Reset outer counter (=measure) mov RLED,RMEASURE ;high nibble = led BCD contents ; swap RLED ori RLED,0x40 ;LED 4 = Measure rcall ledshow clr RBUSY ;reset key status rjmp CTRL3_Ctd CTRL3_PSH: ldi RBUSY, 0x03 CTRL3_Ctd: ; ---- Speed preselect --- sbis PINB, I_SPDPRE1 ;'Speed preselect' (speed = 60 , RSPEED:=97) rjmp CTRL4_PSH ;Action on key release ? cpi RBUSY,0x04 brne CTRL4_Ctd ;was depressing the correct key ?? ldi RSPEED, C_PRESEL1 clr RBUSY ;reset key status rjmp CTRL4_Ctd CTRL4_PSH: ldi RBUSY, 0x04 CTRL4_Ctd: ; ---- Speed preselect --- sbis PINB, I_SPDPRE2 ;'Speed preselect' (speed = 120 , RSPEED:=49) rjmp CTRL5_PSH ;Action on key release ? cpi RBUSY,0x05 brne CTRL5_Ctd ;was depressing the correct key ?? ldi RSPEED, C_PRESEL2 clr RBUSY ;reset key status rjmp CTRL5_Ctd CTRL5_PSH: ldi RBUSY, 0x05 CTRL5_Ctd: ; ---- Speed preselect --- sbis PINB, I_SPDPRE3 ;'Speed preselect' (speed = 180 , RSPEED:=32) rjmp CTRL6_PSH ;Action on key release ? cpi RBUSY,0x06 brne CTRL6_Ctd ;was depressing the correct key ?? ldi RSPEED, C_PRESEL3 clr RBUSY ;reset key status rjmp CTRL6_Ctd CTRL6_PSH: ldi RBUSY, 0x06 CTRL6_Ctd: ; ; --------- MAIN LOOP ------- ; rjmp CTRL_MAIN