; WRITTEN BY: TOM SCARFF ; DATE: 24/09/2002 ; ITERATION: 1.0 ; Now PORTB,7 and NOT 0 ; FILE SAVED AS: snd2midi.ASM ; FOR: PIC16F877 ; CLOCK: 4.00 MHz CRYSTAL ; INSTRUCTION CLOCK: 1.00 MHz T= luS ; PROGRAMME FUNCTION: To read A/D data in for 1 i/p ; and to transmit MIDI out. list p=16F877 ; tells the assembler which PIC #include "p16F877.inc" ; general register file __CONFIG _CP_ALL & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _XT_OSC & _WRT_ENABLE_OFF & _LVP_OFF & _DEBUG_OFF & _CPD_OFF ; '__CONFIG' directive is used to embed configuration data within .asm file. ; The lables following the directive are located in the respective .inc file. ; See respective data sheet for additional information on configuration word. ;******************************** ; Constant Assignments ;******************************** RCIF equ 05h MSB equ .07 ;******************************** ; 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 midich equ 28h ctrller equ 29h count equ 2Ah note1 equ 2Bh note2 equ 2Ch note equ 2Dh ;cal_vel equ 2Eh oct_val equ 2Fh temp_lo equ 30h temp_hi equ 31h note_lo equ 32h note_hi equ 33h octave equ 34h vel_off equ 35h vel_on equ 36h ; 7fh end of data area ;************************************ ; PROGRAMME Reset Point ;************************************ org 00 ; reset vector goto init ;************************************ ; Switch Debounce Delay (50mS) ;************************************ sw_dbnc movlw 080h ; Delay routine movwf count debnce call delay3 decfsz count goto debnce return ;********************************** ; Delay Subroutine (770uS) ;********************************* delay3 movlw .255 movwf dlyreg3 dly3 call delay2 decfsz dlyreg3 goto dly3 nop return delay2 movlw .1 movwf dlyreg2 dly2 decfsz dlyreg2 goto dly2 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 done? btfsc ADCON0,2 goto done? rrf ADRESH,W andlw 07Fh movwf AD_DATA return ;********************************************* ; A/D Amplitude On level check ;********************************************* amp_det_on movlw B'01000001' ; channel 0 movwf ADCON0 conv_on call convert call convert movlw .20 subwf AD_DATA,W ; (f) - (W)--> (dest) btfsc STATUS,C ; Skip if zesult -Ve. ie f than .20 goto conv_on ;********************************************* ; A/D Amplitude Off level check ;********************************************* amp_det_off movlw B'01000001' ; channel 0 movwf ADCON0 conv_off call convert call convert movlw .18 subwf AD_DATA,W ; (f) - (W)--> (dest) btfss STATUS,C ; Skip if result +Ve. ie f>W return ;if AD_DATA < than .20 goto conv_off ;************************************************* ; Detect Peak value ;************************************************** cal_vel clrf vel1 ; Find first -ve going value ; or equal value 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 vel1 movwf vel1 goto peak0 leave1 return ;*************************************************** ; Calculate Octave ; Enter: note_hi,note_lo = 16 bit count ; Return: oct_val = octave value ; note_lo = note value (30 to 61) ;*************************************************** cal_oct clrf oct_val oct? bcf STATUS,C rrf note_lo ; 16-bit divide by 2 bcf STATUS,C rrf note_hi btfsc STATUS,C bsf note_lo,MSB clrw ; zero reached? subwf note_hi,W btfss STATUS,Z goto cont movlw .30 subwf note_lo,W btfss STATUS,C return cont incf oct_val,F goto oct? ;************************************** ; Calculate MIDI Note value ; Enter: note_lo (30 to 61)/2 ; Return: W = note value ;************************************** cal_note rlf note_lo movlw .57 subwf note_lo,W btfsc STATUS,C ; skip if -ve retlw 00 movlw .54 subwf note_lo,W btfsc STATUS,C ; skip if -ve retlw .01 movlw .51 subwf note_lo,W btfsc STATUS,C ; skip if -ve retlw .02 movlw .48 subwf note_lo,W btfsc STATUS,C ; skip if -ve retlw .03 movlw .46 subwf note_lo,W btfsc STATUS,C ; skip if -ve retlw .04 movlw .43 subwf note_lo,W btfsc STATUS,C ; skip if -ve retlw .05 movlw .41 subwf note_lo,W btfsc STATUS,C ; skip if -ve retlw .06 movlw .38 subwf note_lo,W btfsc STATUS,C ; skip if -ve retlw .07 movlw .36 subwf note_lo,W btfsc STATUS,C ; skip if -ve retlw .08 movlw .34 subwf note_lo,W btfsc STATUS,C ; skip if -ve retlw .09 movlw .32 subwf note_lo,W btfsc STATUS,C ; skip if -ve retlw .10 movlw .30 subwf note_lo,W btfsc STATUS,C ; skip if -ve retlw .11 retlw 00 ;***************************************************** ; Table to select MIDI Octave ;***************************************************** oct_tab addwf PCL retlw .10 ;0 retlw .9 ;1 retlw .8 ;2 retlw .7 ;3 retlw .6 ;4 retlw .5 ;5 retlw .4 ;6 retlw .3 ;7 retlw .2 ;8 retlw .1 ;9 retlw .0 ;10 retlw .00 retlw 00 ;***************************************************** ; Table to select MIDI Octave value ;***************************************************** oct_midi addwf PCL retlw .120 ;0 retlw .108 ;1 retlw .96 ;2 retlw .84 ;3 retlw .72 ;4 retlw .60 ;5 retlw .48 ;6 retlw .36 ;7 retlw .24 ;8 retlw .12 ;9 retlw .0 ;10 retlw 00 ;************************************ ; Output MIDI Note-on data ;************************************** noteon movf midich,W addlw 090h ; Note-on ch.1-16 movwf TXREG ; send chazacter from W call txchar movf note,W movwf TXREG ; send character from W call txchar movf vel_on,W movwf TXREG ; send character from W call txchar return ;************************************ ; Output MIDI Note-off data ;************************************** noteoff movf midich,W addlw 080h ; Note-off ch.1-16 movwf TXREG ; send chazacter from W call txchar movf note,W movwf TXREG ; send character from W call txchar ;;;;;;movlw 07Fh ;;;;;;;;;AD_DATA,W movf vel_off,W movwf TXREG ; send character from W call txchar return ;************************************** ; Measure timer count ; Input: PORTB,7 ;************************************** frq_cnt btfss PORTB,7 ; high? wait for transition goto $-1 btfsc PORTB,7 ; low? goto $-1 btfss PORTB,7 ; high? goto $-1 clrf TMR1L clrf TMR1H nop btfsc PORTB,7 ; low? goto $-1 btfss PORTB,7 ; high? goto $-1 movf TMR1L,W movwf note_lo movf TMR1H,W movwf note_hi return ;------------------------------------- get_note call cal_oct movf oct_val,W call oct_tab movwf octave call cal_note ; calculate note andlw 07Fh movwf note movf oct_val,W call oct_midi addwf note,F ; note=midi note number return ;------------------------------------------------------- ; *************************** ; initalise software ;**************************** init bcf STATUS,RP0 ;page 0 clrf PORTA clrf PORTB clrf PORTC clrf PORTD clrf PORTE bsf STATUS,RP0 ; disable weak pull-up resistors movlw 0FFh ; and TMR0 set to 1:256 movwf OPTION_REG ; Option Register bcf STATUS,RP0 clrf PORTB movlw 0FFh ; 1111 1111 TRIS PORTB ;MAKE PORTB all I/P'S ;Set up A/D Converter bsf STATUS,RP0 bcf STATUS,RP1 movlw 001h movwf TRISD movlw 0FFh movwf TRISA ;all inputs movlw 07h movwf TRISE 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'10001111' ; RC7, 0-3 I/P's rest O/P's movwf TRISC 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 PORTC,6 ; set MIDI out high movf PORTC,W andlw 0Fh movwf midich movlw b'00010001' ; set timer1 on at prescale=2 movwf T1CON ;************************************* ; Main Programme ;************************************* main call amp_det_on ; detect amplitude level movf AD_DATA,W movwf vel_on ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ call frq_cnt call get_note movf note,W movwf note1 call frq_cnt call get_note movf note,W movwf note2 movf note1,W subwf note2,W btfss STATUS,Z ; skip if note1=note2 goto main ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ call cal_vel ; calculate velocity movf AD_DATA,W addlw .35 andlw 07Fh movwf vel_on call noteon call amp_det_off ; detect amplitude level movf AD_DATA,W movwf vel_off call noteoff goto main end