  ; WRITTEN BY:           TOM SCARFF
       ; DATE:                 28/2/2000
       ; ITERATION:            1.0
       ; FILE SAVED AS:        drm_vel2.ASM
       ; FOR:                  PIC16F877
       ; CLOCK:                4.00 MHz CRYSTAL                                        
       ; INSTRUCTION CLOCK:    1.00 MHz  T= luS
       ; PROGRAMME FUNCTION:   To read trigger i/p's on PORTB
       ;		       A/D data in for 8 i/p's
       ;                       and to transmit it to MIDI out.


	list p=16F877           ; tells the assembler which PIC
	#include "p16F877.inc"  ; general register file

;********************************
;      Constant Assignments
;********************************
RCIF          equ    05h

;********************************
;  Variable Assignment Addresses
;***t****************************
                       ;      20h      Start of General purpose registers
AD_DATA EQU     21h
ADRES   EQU     22h
dlyreg2 equ     23h
dlyreg3 equ     24h
drum    equ     25h
vel1    equ     26h
vel2    equ     27h
value1  equ	28h
count	equ	29h
max_cnt equ	2Ah
val1 	equ	2Bh
val2	equ	2Ch
val3	equ	2Dh
val4	equ	2Eh
val5	equ	2Fh
val6	equ	30h
val7	equ	31h
val8	equ	32h
base_addr equ	33h
LED	equ	34h
drum_sel  equ	35h
select	equ	36h
max	equ	37h
sens_flag equ	38h
sens	equ	39h

		       ;       7fh      end of data area

       ;************************************
       ;       PROGRAMME Reset Point
       ;************************************
              org     00               ; reset vector
              goto    init

;************************************
;	Switch Debounce Delay (100mS)
;************************************

sw_dbnc	movlw 80h	; Delay routine
	movwf dlyreg2
debnce	call delay3
	decfsz dlyreg2
	goto debnce
	return

;*************************************
;	 Delay Subroutine (770uS)
;*************************************
delay3    movlw .255
          movwf dlyreg3
dly3      decfsz dlyreg3
          goto dly3
          nop
          return



;******************************************
;       Receive Data  subroutine
;******************************************

rxchar btfss   PIR1,RCIF   ; test for incoming data
               goto     $-1
               movfw    RCREG
               return

;******************************************
;       transmission complete subroutine
;***************+**************************

txchar   bsf       STATUS,RP0
                   btfss TXSTA,1   ; test for end of transmission
                   goto  $-1
                   bcf   STATUS,RP0
                   return

;*********************************************
;       Start A/D conversion Subroutine
;*********************************************
   
convert bsf ADCON0,2     ;set GO/DONE Bit
loop1   btfsc ADCON0,2
        goto loop1
        rrf     ADRESH,W
        andlw   07Fh
        movwf   AD_DATA
        return
   
;*********************************#***
;       Output MIDI note-on data
;**************************************
  
noteon  movlw    099h    ; Note-on Channel 10
        movwf   TXREG   ; send chazacter from W
        call    txchar
   
        movf    drum,W
        movwf   TXREG   ; send character from W
        call    txchar
  
        movf    vel1,W
        movwf   TXREG   ; send character from W
        call    txchar
        return

;*********************************#***
;       Output MIDI note-off data
;**************************************
  
noteoff  movlw    089h    ; Note-off Channel 10
        movwf   TXREG   ; send chazacter from W
        call    txchar
   
        movf    drum,W
        movwf   TXREG   ; send character from W
        call    txchar
  
        movf    vel1,W
        movwf   TXREG   ; send character from W
        call    txchar
        return
   
   
;*********************************************
;       Detect Peak value of Drum hit
;*+*******************************************
  
 
peak    clrf vel1
	movlw .20
	movwf max_cnt

   
peak0   call convert
	call convert
        movf AD_DATA,W
        movwf vel2
        subwf vel1,W ; (f) - (W)--> (dest)
        btfsc STATUS,C  ; Skip if result -Ve. ie f<W
        goto $+3
        movf AD_DATA,W ;swap if AD_DATA > vel1
        movwf vel1         		 
	decfsz max_cnt
	goto peak0    
        return

;*********************************************
;       Detect Sensitivity of 1st Drum hit
;*+*******************************************

sens_piezo	movlw 07Fh
		movwf max
		movf vel1,W
		subwf max,W	; max-W-->W
		andlw 07Fh
		movwf sens
		bcf sens_flag,0
		return


;************************************
;	EEPROM Read
;************************************


ee_read	bcf STATUS,RP0
	bsf STATUS,RP1	; bank 2
	movwf EEADR
	bsf STATUS,RP0
	bsf STATUS,RP1	; bank 3
	bsf EECON1,RD
r1	btfsc EECON1,RD ; Wait to finish read.
	goto r1
	bcf STATUS,RP0	; now bank 2
	movf EEDATA,W
	andlw 07Fh	; prevent value >127
	bcf STATUS,RP1	; now bank 0
	return


  

;*****************************************************
;	Table to convert drum sound
;*****************************************************

drm_type   movlw 01h
	subwf select,W
	btfsc STATUS,Z
	goto sel1

	movlw 02h
	subwf select,W
	btfsc STATUS,Z
	goto sel2
	
	movlw 03h
	subwf select,W
	btfsc STATUS,Z
	goto sel3

	movlw 04h
	subwf select,W
	btfsc STATUS,Z
	goto sel4

	movlw 05h
	subwf select,W
	btfsc STATUS,Z
	goto sel5

	movlw 06h
	subwf select,W
	btfsc STATUS,Z
	goto sel6

	movlw 07h
	subwf select,W
	btfsc STATUS,Z
	goto sel7

	movlw 08h
	subwf select,W
	btfsc STATUS,Z
	goto sel8

	retlw 00h

sel1	movf val1,W
	movwf drum
	return

sel2	movf val2,W
	movwf drum
	return

sel3	movf val3,W
	movwf drum
	return

sel4	movf val4,W
	movwf drum
	return

sel5	movf val5,W
	movwf drum
	return

sel6	movf val6,W
	movwf drum
	return

sel7	movf val7,W
	movwf drum
	return

sel8	movf val8,W
	movwf drum
	return

;*****************************************************
;	Table to select A/D Channel
;*****************************************************

channel	  addwf PCL
	  retlw 00h	; dummy 00 not used in 'count'
	  retlw B'01000001' ; channel 0
          retlw B'01001001' ; channel 1
          retlw B'01010001' ; channel 2
          retlw B'01011001' ; channel 3
          retlw B'01100001' ; channel 4
          retlw B'01101001' ; channel 5
          retlw B'01110001' ; channel 6
          retlw B'01111001' ; channel 7
          retlw 00h

;****************************
;       initalise software
;****************************
    
init    bcf     STATUS,RP0      ;page 0
        clrf    PORTA
        clrf    PORTB
        clrf    PORTC
        clrf    PORTD
        clrf    PORTE


       
   
;Set up A/D Converter
  
        bsf STATUS,RP0
        bcf STATUS,RP1
        movlw 0FFh
        movwf TRISD		;all inputs
        movlw 0FFh
        movwf TRISA             ;all inputs
        movlw 07h
        movwf TRISE

	movlw 0FFh	; all inputs
	movwf TRISB
    
        bcf STATUS,RP0          ; return to page 0
   
        bsf STATUS,RP0
        clrf ADCON1
        bcf     STATUS,RP0        ; return to page 0
   
   ; Set up USART
   
           bsf     STATUS,RP0      ; goto page 1
           movlw   b'10001000'     ; RC7 is RX input
           movwf   TRISC	   ; RC3 is Prog. Sw.
           movlw   01h             ; 31250 baud for MIDI
           movwf   SPBRG
           movlw   b'00100000'     ; async tx 8 bit
           movwf   TXSTA
           bcf     STATUS,RP0              ; return to page 0
           movlw   b'10010000'     ; async rx 8 bit
           movwf   RCSTA
   
            bsf STATUS,RP0
            movlw 07h        ; rtcc/256
            movwf OPTION_REG
            bcf STATUS,RP0

;**************************************
;	Main Programme Start
;**************************************

;**************************************
; Programme EEPROM if Prog. Sw. selected
;**************************************

main0     btfsc PORTC,3 ; is prog. sw. pressed?
	  goto main1  

	call sw_dbnc
	

	bsf STATUS,RP0
        bcf STATUS,RP1
        movlw 00h
        movwf TRISD	; all outputs for LED's
	bcf STATUS,RP0  ; return to page 0
   

	movlw 00h
	movwf base_addr
 	movlw 08h
	movwf count
	movlw 0FEh ; 1111 1110
	movwf LED
	  

loop0	  movf LED,W 	;turn on next/LED
	  movwf PORTD

	movf PORTB,W	; read 8-way switch
	andlw 07Fh	; 0 to 127! only
	movwf drum_sel
	
	movf base_addr,W; start addr. EEPROM
	bsf STATUS,RP1	; bank 2
	movwf EEADR

	bcf STATUS,RP1	; bank 0
	movf drum_sel,W		
	andlw 07Fh
	bsf STATUS,RP1	; bank 2
	movwf EEDATA
	
	bsf STATUS,RP0 ;writing to eeprom, bank 3
;;;;;;	bcf INTCON,GIE
	bsf EECON1,WREN
	movlw 55h
	movwf EECON2
	movlw 0AAh
	movwf EECON2
	bsf EECON1,WR	
	
test_wr	btfsc EECON1,WR; is write finished?
	goto test_wr
	bcf STATUS,RP0
	bcf STATUS,RP1 ; now bank 0
;;;;;;;	bsf INTCON,GIE

	btfss PORTC,3 ; is prog. sw. released?
	goto $-1
	call sw_dbnc

	btfsc PORTC,3 ; is prog. sw. pressed?
	goto $-1
	call sw_dbnc


	incf base_addr

	bsf STATUS,C
	rlf LED,F  ; from 0 to 7

	decfsz count ;from 8 to 1
	goto loop0


;**************************************
;	Main Programme Start
;  Read EEPROM and write to val1 to 8
;**************************************


main1   clrf base_addr	; start addr. of EEPROM at 00h?

	movf base_addr,W
	call ee_read
	movwf val1
	incf base_addr,F

	movf base_addr,W
	call ee_read
	movwf val2
	incf base_addr,F

	movf base_addr,W
	call ee_read
	movwf val3
	incf base_addr,F

	movf base_addr,W
	call ee_read
	movwf val4
	incf base_addr,F

	movf base_addr,W
	call ee_read
	movwf val5
	incf base_addr,F

	movf base_addr,W
	call ee_read
	movwf val6
	incf base_addr,F

	movf base_addr,W
	call ee_read
	movwf val7
	incf base_addr,F

	movf base_addr,W
	call ee_read
	movwf val8
	incf base_addr,F


;-----------------------------------------

	bsf STATUS,RP0  ; set PORTD for i/p's
        bcf STATUS,RP1
        movlw 0FFh
        movwf TRISD	; all inputs for drums
	bcf STATUS,RP0  ; return to page 0

	bsf sens_flag,0	; set to 0000 0001
	clrf sens
   

	clrf PORTD
main	movf PORTD,W
	movwf value1
	comf value1,F	
	btfsc STATUS,Z ; is any i/p 'low'?
	goto main

	movlw 00h
	movwf count
drum?	incf count,F
	rrf value1
	btfss STATUS,C
	goto drum?

	movf count,W
	movwf select
	call drm_type ; returns with drum-type in 'drum'	

	movf count,W
	call channel ; returns a/d channel

	movwf ADCON0
	call convert
	call convert
	call peak	; returns with velocity=vel1

;	btfsc sens_flag,0
;	call sens_piezo

;	movf sens,W
;	addwf vel1,F	; W+vel1-->vel1
;	movf vel1,W
;	btfsc vel1,7	; test MSB, >127?
;	movlw 07Fh	; yes then set to 127	
;	movwf vel1		; no

	call noteon
	call delay3
	call delay3
	call delay3
	call delay3

	call noteoff

	goto main

	end	
 
