;PIC BGM 12F683-10 2音タイプ 2013.03.22 ;計算上のタイマ 0 の設定値は、256-32=224 であるが実測 39.6μs となった。 ;231 に設定すると 実測値は 31.6 μs となり、OSCTUNE を 11110 にすると丁度 32 μs になった。 ;GP0:入力 (未使用) ;GP1:入力 起動押ボタン ;GP2:出力 全電圧出力 ;GP3:入力 (未使用) ;GP4:出力 半値電圧出力 ;GP5:出力 演奏中LED ;**** アセンブラに指示 **** LIST P=12F683 __CONFIG _FCMEN_OFF &_IESO_OFF &_BOD_ON &_CPD_OFF &_CP_OFF &_MCLRE_OFF &_PWRTE_ON &_WDT_OFF &_INTOSCIO INCLUDE "P12F683.INC" ERRORLEVEL -302 ;バンク注意のコメントを出さない ;音長設定 TEMPO110=1 ; 70、80、90、100、110、120、130 のどれかをラベルとして記入 ;レジスタ定義 WTAIHI EQU 20H ;Wレジスタ退避先 STAIHI EQU 21H ;STATUSレジスタ退避先 STABFLG EQU 25H ;主音テーブルフラグ SDPOINT EQU 26H ;主音データポインタ SONMEI EQU 27H ;主音名 SONMEIC EQU 28H ;主音カウンタ SKYUFU EQU 29H ;主音 休符フラグ FONMEI EQU 3EH ;副音名 FONMEIC EQU 3FH ;副音カウンタ FHIGH EQU 40H ;副音出力 HIGH フラグ FKYUFU EQU 41H ;副音 休符フラグ SONCHO EQU 47H ;主音長 SHIGH EQU 48H ;主音出力 HIGH フラグ SFCHFG EQU 55H ;出力変化フラグ ;音名カウント数定義 KYF EQU D'01' ;01は休符 FIN EQU D'255' ;255は終わり FA2 EQU D'179' ;2ファ FA2# EQU D'169' ;2ファ# SO2 EQU D'159' ;2ソ SO2# EQU D'150' ;2ソ# RA2 EQU D'142' ;2ラ RA2# EQU D'134' ;2ラ# SI2 EQU D'127' ;2シ DO3 EQU D'119' ;3ド DO3# EQU D'113' ;3ド# RE3 EQU D'106' ;3レ RE3# EQU D'100' ;3レ# MI3 EQU D'95' ;3ミ FA3 EQU D'89' ;3ファ FA3# EQU D'84' ;3ファ# SO3 EQU D'80' ;3ソ SO3# EQU D'75' ;3ソ# RA3 EQU D'71' ;3ラ RA3# EQU D'67' ;3ラ# SI3 EQU D'63' ;3シ DO4 EQU D'60' ;4ド(真中のド) DO4# EQU D'56' ;4ド# RE4 EQU D'53' ;4レ RE4# EQU D'50' ;4レ# MI4 EQU D'47' ;4ミ FA4 EQU D'45' ;4ファ FA4# EQU D'42' ;4ファ# SO4 EQU D'40' ;4ソ SO4# EQU D'38' ;4ソ# RA4 EQU D'36' ;4ラ (基準 440Hz、1/2周期 1136μs/32μs=35.5) RA4# EQU D'34' ;4ラ# SI4 EQU D'32' ;4シ DO5 EQU D'30' ;5ド DO5# EQU D'28' ;5ド# RE5 EQU D'27' ;5レ RE5# EQU D'25' ;5レ# MI5 EQU D'24' ;5ミ FA5 EQU D'22' ;5ファ FA5# EQU D'21' ;5ファ# ここからは範囲外 SO5 EQU D'20' ;5ソ SO5# EQU D'19' ;5ソ# RA5 EQU D'18' ;5ラ RA5# EQU D'17' ;5ラ# SI5 EQU D'16' ;5シ DO6 EQU D'15' ;6ド DO6# EQU D'14' ;6ド# ;音長カウント数定義 IFDEF TEMPO70 ;4分音符=70 LZ EQU D'245' ;全音符 L2 EQU D'122' ;2分音符 L4 EQU D'61' ;4分音符 (基準 857ms/14ms=61.2) L8 EQU D'31' ;8分音符 L16 EQU D'15' ;16分音符 L32 EQU D'8' ;32分音符 ENDIF IFDEF TEMPO80 ;4分音符=80 LZ EQU D'214' ;全音符 L2 EQU D'107' ;2分音符 L4 EQU D'54' ;4分音符 (基準 750ms/14ms=53.6) L8 EQU D'27' ;8分音符 L16 EQU D'13' ;16分音符 L32 EQU D'7' ;32分音符 ENDIF IFDEF TEMPO90 ;4分音符=90 LZ EQU D'190' ;全音符 L2 EQU D'95' ;2分音符 L4 EQU D'48' ;4分音符 (基準 667ms/14ms=47.6) L8 EQU D'24' ;8分音符 L16 EQU D'12' ;16分音符 L32 EQU D'6' ;32分音符 ENDIF IFDEF TEMPO100 ;4分音符=100 LZ EQU D'171' ;全音符 L2 EQU D'86' ;2分音符 L4 EQU D'43' ;4分音符 (基準 600ms/14ms=42.9) L8 EQU D'21' ;8分音符 L16 EQU D'11' ;16分音符 L32 EQU D'5' ;32分音符 ENDIF IFDEF TEMPO110 ;4分音符=110 LZ EQU D'156' ;全音符 L2 EQU D'78' ;2分音符 L4 EQU D'39' ;4分音符 (基準 545ms/14ms=38.9) L8 EQU D'19' ;8分音符 L16 EQU D'10' ;16分音符 L32 EQU D'5' ;32分音符 ENDIF IFDEF TEMPO120 ;4分音符=120 LZ EQU D'143' ;全音符 L2 EQU D'71' ;2分音符 L4 EQU D'36' ;4分音符 (基準 500ms/14ms=35.7) L8 EQU D'18' ;8分音符 L16 EQU D'9' ;16分音符 L32 EQU D'4' ;32分音符 ENDIF IFDEF TEMPO130 ;4分音符=130 LZ EQU D'132' ;全音符 L2 EQU D'66' ;2分音符 L4 EQU D'33' ;4分音符 (基準 462ms/14ms=33) L8 EQU D'16' ;8分音符 L16 EQU D'8' ;16分音符 L32 EQU D'4' ;32分音符 ENDIF ;** アセンブラに指示終了 ** ;**** メインプログラム **** ORG 00H ;リセットベクタ GOTO INITIAL ;初期設定後 MAINへ ORG 04H ;TMR0割込ベクタ GOTO INTR ;割込処理へ MAIN PBCHK ;押ボタンチエック BTFSC GPIO,1 ;ON=0 THEN SKIP GOTO MAIN LOOP0 ;主音取得 BTFSC STABFLG,F ;0 THEN SKIP GOTO CONT1 CALL TABLE1 ;主音名データ1取得 GOTO CONT2 CONT1 CALL TABLE2 ;主音名データ2取得 CONT2 MOVWF SONMEI ;主音名データ仮格納 MOVWF SONMEIC ;主音名カウンタ仮格納 INCF SONMEI,W ;終わり(FINE=0FFH)かチエック BTFSS STATUS,Z ;0 THEN SKIP GOTO CONT3 GOTO SYURYO CONT3 DECF SONMEI,W ;休符(01H)かチエック BTFSS STATUS,Z ;0 THEN SKIP GOTO CONT4 BSF SKYUFU,F ;主音休符フラグセット CLRF SONMEI ;主音名データクリア CLRF SONMEIC ;主音名カウンタクリア CONT4 BSF SHIGH,F ;主音=HIGH ;副音取得 BTFSC STABFLG,F ;0 THEN SKIP GOTO CONT5 CALL TABLE3 ;副音名データ1取得 GOTO CONT6 CONT5 CALL TABLE4 ;主音名データ2取得 CONT6 MOVWF FONMEI ;副音名データ仮格納 MOVWF FONMEIC ;副音名カウンタ仮格納 DECF FONMEI,W ;休符(01H)かチエック BTFSS STATUS,Z ;0 THEN SKIP GOTO CONT7 BSF FKYUFU,F ;音休符フラグセット CLRF FONMEI ;副音名データクリア CLRF FONMEIC ;副音名カウンタクリア CONT7 BSF FHIGH,F ;副音=HIGH ;音長取得 BTFSC STABFLG,F ;0 THEN SKIP GOTO CONT8 CALL TABLE5 ;主音長データ1取得 GOTO CONT9 CONT8 CALL TABLE6 ;主音長データ2取得 CONT9 MOVWF SONCHO ;音長カウンタ格納 INCF SDPOINT,F ;ポインタ+1 MOVLW D'241' SUBWF SDPOINT,W ;ポインタ-241 BTFSS STATUS,Z ;241 THEN SKIP GOTO CONT10 BSF STABFLG,F ;主音テーブルフラグセット CLRF SDPOINT ;主音データポインタリセット CONT10 BSF INTCON,GIE ;TMR0 ON MOVLW D'231' ;TMR0 プリセット MOVWF TMR0 ;TMR0 起動 MOVLW 0A0H ;TMR1L プリセット 65536-28000=37536=92A0H MOVWF TMR1L MOVLW 92H ;TMR1H プリセット MOVWF TMR1H BSF T1CON,TMR1ON ;TMR1 起動 BSF GPIO,5 ;LED ON ;音出力 SOUND1 BTFSS SFCHFG,F ;出力変化フラグ=1 THEN SKIP GOTO CONT11 BTFSS SHIGH,F ;主音=1 THEN SKIP GOTO SOUND2 BTFSS FHIGH,F ;主音=1,副音=1 THEN SKIP GOTO SOUND3 BCF GPIO,4 ;2.5V OFF NOP BSF GPIO,2 ;5V ON GOTO SOUND5 SOUND2 BTFSS FHIGH,F ;主音=0、副音=1 THEN SKIP GOTO SOUND4 SOUND3 ;主音=1、副音=0、主音=0、副音=1 BCF GPIO,2 ;5V OFF NOP BSF GPIO,4 ;2.5V ON GOTO SOUND5 SOUND4 ;主音=0,副音=0 BCF GPIO,2 ;5V OFF NOP BCF GPIO,4 ;2.5V OFF SOUND5 CLRF SFCHFG ;出力変化フラグリセット CONT11 ;音長カウント BTFSS PIR1,TMR1IF ;TMR1 オーバーフロー=1 THEN SKIP GOTO CONT12 BCF PIR1,TMR1IF ;TMR1オーバーフローフラグリセット MOVLW 0A0H ;TMR1L プリセット 65536-28000=37536=92A0H MOVWF TMR1L MOVLW 92H ;TMR1H プリセット MOVWF TMR1H DECF SONCHO,F ;音長−1 BTFSS STATUS,Z ;0 THEN SKIP GOTO CONT12 ;1音終了 CLRF SKYUFU ;主音休符フラグリセット CLRF FKYUFU ;副音休符フラグリセット CLRF SHIGH ;主音出力 HIGH リセット CLRF FHIGH ;副音出力 HIGH リセット CLRF SFCHFG ;出力変化フラグリセット BCF INTCON,GIE ;TMR0 OFF BCF T1CON,TMR1ON ;TMR1 OFF BCF GPIO,2 ;出力 OFF NOP BCF GPIO,4 ;出力 OFF GOTO LOOP0 ;次の音へ CONT12 ;他にプログラムがあればここに書く、340 バイト以下、TMR1 を見ているので、WAIT は不可 GOTO SOUND1 SYURYO ;曲終了、オールリセット CLRF STABFLG ;主音テーブルフラグ CLRF SDPOINT ;主音データポインタ CLRF SONMEI ;主音名 CLRF SONMEIC ;主音カウンタ CLRF SKYUFU ;主音 休符フラグ CLRF SHIGH ;主音出力 HIGH フラグ CLRF FONMEI ;副音名 CLRF FONMEIC ;副音カウンタ CLRF FHIGH ;副音出力 HIGH フラグ CLRF FKYUFU ;副音 休符フラグ CLRF SONCHO ;主音長 CLRF SFCHFG ;出力変化フラグ BCF INTCON,GIE ;TMR0 OFF BCF T1CON,TMR1ON ;TMR1 OFF BCF GPIO,2 ;出力 OFF NOP BCF GPIO,4 ;出力 OFF NOP BCF GPIO,5 ;LED OFF GOTO MAIN ;押ボタンチエックへ ;**** 割込処理 **** INTR MOVWF WTAIHI ;レジスタ退避 SWAPF STATUS,W MOVWF STAIHI NOP ;LED ON 割込みインターバル計測用で本番では NOP にする。 BCF INTCON,T0IF ;TMR0 割り込みフラグクリア MOVLW D'231' ;TMR0 起動 MOVWF TMR0 NOP ;LED OFF 割込みインターバル計測用で本番では NOP にする。 BTFSC SKYUFU,F ;主音が休符でない=0 THEN SKIP GOTO FONOFF DECF SONMEIC,F ;主音名-1 BTFSS STATUS,Z ;0 THEN SKIP GOTO FONOFF SONOFF ;出力反転 BTFSC SHIGH,F ;0 THEN SKIP GOTO SONOFF1 BSF SHIGH,F ;出力HIGH GOTO SONOFF2 SONOFF1 BCF SHIGH,F ;出力LOW; SONOFF2 MOVF SONMEI,W MOVWF SONMEIC ;カウンタ再設定 BSF SFCHFG,F ;出力変化フラグセット FONOFF BTFSC FKYUFU,F ;副音が休符でない=0 THEN SKIP GOTO INTREND DECF FONMEIC,F ;副音名-1 BTFSS STATUS,Z ;0 THEN SKIP GOTO INTREND ;出力反転 BTFSC FHIGH,F ;0 THEN SKIP GOTO FONOFF1 BSF FHIGH,F ;出力HIGH GOTO FONOFF2 FONOFF1 BCF FHIGH,F ;出力LOW FONOFF2 MOVF FONMEI,W MOVWF FONMEIC ;カウンタ再設定 BSF SFCHFG,F ;出力変化フラグセット INTREND;割込処理終了 SWAPF STAIHI,W ;レジスタ復帰 MOVWF STATUS SWAPF WTAIHI,F SWAPF WTAIHI,W RETFIE ;**** 初期設定 **** INITIAL ;内部OSC 8 MHz BANKSEL OSCCON MOVLW B'01110001' ;-,IRCF2=1,IRCF1=1,IRCF0=1, X,X,X,SCS=1 MOVWF OSCCON BANKSEL OSCTUNE MOVLW B'00011110' ;-,-,-,TUN4=1,TUN3=1,TUN2=1, TUN0=1,TUN0=0 MOVWF OSCTUNE ;GPIO BANKSEL CMCON0 ;コンパレータ不使用 MOVLW B'00000111' ;X,X,X,X, X,CM2=1,CM1=1,CM0=1 MOVWF CMCON0 BANKSEL ANSEL ;すべてデジタル I/O CLRF ANSEL BANKSEL TRISIO ;I/O MOVLW B'00001011' ;-, -, GP5=0,GP4=0, GP3=1,GP2=0,GP1=1,GP0=1 (1:入力) MOVWF TRISIO ;タイマ0 BANKSEL INTCON ; MOVLW B'00100000' ;GIE=0,PEIE=0,T0IE=1,INTEG=0, GPIE=0,T0IF=0,INTF=0,GPIF=0 GIE で起動させるので初期は0 MOVWF INTCON ;タイマ1 BANKSEL T1CON ;プリスケーラ 1 MOVLW B'00000100' ;T1GINV=0,TMR1GE=0,T1CKPS1=0,T1CKPS2=0, T1OSCEN=0,T1SYNC=1,TMR1CS=0,TMR1ON=0 TMR1ONで起動させるので初期は0 MOVWF T1CON ;CCP BANKSEL CCP1CON ;CCP禁止 MOVLW B'00000000' ;-,-,DC1B1=0,DC1B0=0, CCP1M3=0,CCP1M2=0,CCP1M1=0,CCP1M0=0 MOVWF CCP1CON ;オプション BANKSEL OPTION_REG ;プルアップする、タイマ 0 プリスケーラ 2 MOVLW B'00000000' ;GPPU=0,INTEG=0,T0CS=0,T0SE=0, PSA=0,PS2=0,PS1=0,PS0=0 MOVWF OPTION_REG ;プルアップ BANKSEL WPU MOVLW B'00000011' ;-,-,WPU5=0,WPU4=0, -,WPU2=0,WPU1=1,WPU0=1 MOVWF WPU ;BANK=0に戻す BANKSEL GPIO ;レジスタ、出力クリア CLRF STABFLG ;主音テーブルフラグ CLRF SDPOINT ;主音データポインタ CLRF SONMEI ;主音名 CLRF SONMEIC ;主音カウンタ CLRF SKYUFU ;主音 休符フラグ CLRF SONCHO ;主音長 CLRF SHIGH ;主音出力 HIGH フラグ CLRF FONMEI ;副音名 CLRF FONMEIC ;副音カウンタ CLRF FHIGH ;副音出力 HIGH フラグ CLRF FKYUFU ;副音 休符フラグ CLRF SFCHFG ;出力変化フラグ BCF GPIO,2 ;音出力 OFF NOP BCF GPIO,4 ;音出力 OFF NOP BCF GPIO,5 ;LED OFF GOTO MAIN ;200 H まで( )バイト ;**** 音符データ **** ;大きな栗の木下で データ ;主音名データ1 ORG 0200H ;データ数は 16×15=240個とする。FIN(曲終了)はどこかに必要。 TABLE1 ; MOVLW 02H ;データアドレス 200H から MOVWF PCLATH ; MOVF SDPOINT,W ADDWF PCL,F ;SPOINT(0から)+PCL番地のデータをWに入れてリターン ;1 DT DO4,DO4,RE4 ;4 DT MI4,SO4,DO5,RE5 ;8 DT MI5,KYF,RE5,KYF ;12 DT DO5,KYF ;14 DT DO4,DO4,RE4 ;17 DT MI4,MI4,SO4 ;20 DT MI4,MI4,RE4,RE4 ;24 DT DO4,DO4,KYF,KYF ;28 DT MI4,MI4,FA4 ;31 DT SO4,DO5 ;33 DT RA4,DO5 ;35 DT SO4,KYF ;37 DT DO5,DO5 ;39 DT SI4,SO4 ;41 DT RA4,RA4,RA4,RA4 ;45 DT SO4,KYF ;47 DT DO4,DO4,RE4 ;50 DT MI4,MI4,SO4 ;53 DT MI4,MI4,RE4,RE4 ;57 DT DO4,KYF ;59 DT FIN ;主音名データ2 ORG 0300H ;データ数は 16×15=240 個とする。 TABLE2 ; MOVLW 03H ;データアドレス 300H から MOVWF PCLATH ; MOVF SDPOINT,W ADDWF PCL,F DT DO4 ;241-480 ;副音名データ1 ORG 0400H ;データ数は 16×15=240 個とする。 TABLE3 ; MOVLW 04H ;データアドレス 400H から MOVWF PCLATH ; MOVF SDPOINT,W ADDWF PCL,F ;SPOINT(0から)+PCL番地のデータをWに入れてリターン ;1 DT MI3,MI3,RE3 ;4 DT KYF,KYF,MI3,FA3 ;8 DT SO3,KYF,SO2,KYF ;12 DT MI3,KYF ;14 DT MI3,SO3,SO3 ;17 DT SO2,SO2,DO4 ;20 DT DO3,DO3,FA3,FA3 ;24 DT MI3,SO2,RA2,SI2 ;28 DT DO3,DO4,DO4 ;31 DT DO4,MI4 ;33 DT FA2,FA3 ;35 DT DO3,MI3 ;37 DT RA2,MI3 ;39 DT MI3,SI3 ;41 DT FA2,FA2,FA3,FA3 ;45 DT SI2,KYF ;47 DT MI3,SO3,SO3 ;50 DT SO2,SO2,DO4 ;53 DT DO3,DO3,FA3,FA3 ;57 DT MI3,KYF ;59 DT FIN ;副音名データ2 ORG 0500H ;データ数は 16×15=240 個とする。 TABLE4 ; MOVLW 05H ;データアドレス 500H から MOVWF PCLATH ; MOVF SDPOINT,W ADDWF PCL,F DT DO3 ;241-480 ;音長データ1 ORG 0600H ;データ数は1 〜 16×15=240 までにする。 TABLE5 ; MOVLW 06H ;データアドレス 600H から MOVWF PCLATH ; MOVF SDPOINT,W ADDWF PCL,F ;SPOINT(0から)+PCL番地のデータをWに入れてリターン ;1 DT L4,L8,L8 ;4 DT L8,L8,L8,L8 ;8 DT L8,L8,L8,L8 ;12 DT L4,L4 ;14 DT L4,L8,L8 ;17 DT L8,L8,L4 ;20 DT L8,L8,L8,L8 ;24 DT L8,L8,L8,L8 ;28 DT L4,L8,L8 ;31 DT L4,L4 ;33 DT L4,L4 ;35 DT L4,L4 ;37 DT L4,L4 ;39 DT L4,L4 ;41 DT L8,L8,L8,L8 ;45 DT L4,L4 ;47 DT L4,L8,L8 ;50 DT L8,L8,L4 ;53 DT L8,L8,L8,L8 ;57 DT L4,L4 ;59 DT FIN ;音長データ2 ORG 0700H ;データ数は1 〜 16×15=240 までとする。 TABLE6 ; MOVLW 07H ;データアドレス 700H から MOVWF PCLATH ; MOVF SDPOINT,W ADDWF PCL,F DT L4 ;241-480 END ;プログラム終わり