device pic16c54,xt_osc,wdt_on,protect_off ; midi metronome for pic16c54 ; variable equates ORG 8 tick DS 1 ;incomming midi clock tick count beat DS 1 ;current beat of this measure meter DS 1 ;beats per measure, from dipswitch value DS 1 ;incomming midi byte value bits DS 1 ;bit count for serial port flags DS 1 ;flag byte run EQU 0 ;running flag, run=1, stop=0 PPQN EQU 24 ;pulses per quarter note clock rate ; port RA pin assignments MIDI EQU 0 ;midi serial input GREEN EQU 1 ;green led output RED EQU 2 ;red led output FLASH EQU 3 ;output, flashes on every beat ; reset vector reset init org 0 ;start of program cright retw 'Copyright (c), Paul Messick, 1992-1998' init mov !ra,#11110001b ;set ra1-3 as outputs setb ra.GREEN ;turn off leds setb ra.RED clrb ra.FLASH clr rtcc mov !option,#00000010b ;options:prescaler on rtcc, rtcc/8 clr tick ;initialize registers clr beat mov !rb,#00001111b ;set rb4-7 as outputs clr rb ;force floating input low nop nop mov !rb,#11111111b ;set rb4-7 as inputs nop nop mov w,rb ;read dipswitch and w,#11110000b ;mask trash mov meter,w ;put in bpm swap meter ;put in lower nibble inc meter ;one greater setb flags.run ;set running flag exec clr wdt jb ra.midi,exec ;wait until start bit clr bits ;bit counter clr rtcc ;reset timer start cjb rtcc,#4,start ;wait for 48 us (start bit) clr rtcc ;reset timer for next bit clc ;start with carry clear btfsc ra.midi ;if midi in is zero, leave alone stc ;midi is 1 rr value ;put bit into value inc bits ;next bit b_loop cjb rtcc,#3,b_loop ;wait for next bit time nop nop clr rtcc ;reset timer for next bit clc ;start with carry clear btfsc ra.MIDI ;if midi in is zero, leave alone stc ;midi is 1 rr value ;put bit into value inc bits ;next bit cjb bits,#8,b_loop ;read all bits yet? cje value,#0f8h,clock ;is it a clock? cje value,#0fah,cstart ;is it a start command? cje value,#0fbh,continue ;is it a continue command? cje value,#0fch,cstop ;is it a stop command? jmp exec ;no, skip it clock jnb flags.run,exec ;is the clock able to run? inc tick ;yes, tick the clock cjne tick,#1,chk_1a ;if it's the first tick cjne beat,#0,chk_1a ;of the first beat clrb ra.RED ;flash the red led setb ra.FLASH jmp exec chk_1a cjne tick,#PPQN,v_f8 ;is tick equal to ppqn? clr tick ;yes, clear tick inc beat ;next beat cjne meter,beat,chk_g ;is beat=bpm (end of measure?) clr beat ;yes, reset beat jmp exec chk_g clrb ra.GREEN ;flash green led setb ra.FLASH jmp exec v_f8 cjne tick,#PPQN/4,exec ;is tick equal to ppqn/4? setb ra.GREEN ;turn off leds setb ra.RED clrb ra.FLASH jmp exec cstart clr tick ;its a start, clear tick clr beat ;and beat mov !rb,#00001111b ;set rb4-7 as outputs clr rb ;force floating input low nop nop mov !rb,#11111111b ;set rb4-7 as inputs nop nop mov w,rb ;read dipswitch and w,#11110000b ;mask trash mov meter,w ;put in bpm swap meter ;put in lower nibble inc meter ;one greater continue mov !ra,#11110001b ;set ra1-3 as outputs setb ra.GREEN ;turn off leds setb ra.RED setb flags.run ;set the run flag jmp exec cstop mov !ra,#11110001b ;set ra1-3 as outputs setb ra.GREEN ;turn off leds setb ra.RED clrb flags.run ;clear the run flag jmp exec end