2015-03-18

PICで電子オルゴール

久々に電子工作をしました。
母校の小学校がとうとう閉校になるので、何か記念になるものを残しておこうと思い校歌を電子オルゴールにしてみました。
PICマイコン12F629と圧電スピーカ、電池といった簡単な構成でできます。
写真にあるものは、CDSをつけて明るくなると鳴り出すように作ったので部品がCDSと抵抗2本が増えています。


開発はmikroBASICを使いました。
ライターはPICKit2。

MikroBasicのライブラリーにSOUNDがあり、音程と長さを指定して音を鳴らすことができます。
PIC12F629にはEEPROMがあります。このEEPROMに音程長さを記憶させておき順に読み込み音楽を演奏させています。
そのままでは音程と長さで4バイト必要になりますが、プログラム内部でドレミと音符の長さのテーブルを持ち、EEPROMにはその番号のみで上位4ビットで長さ、下位4ビットで音程の番号を表現させました。

EEPROMの内容は校歌なので載せてもと思い、ソースのみを公開します。
休符の扱いがわからずDelayで表現しています。
Delayはライブラリーで実装されておらず、パラメータに変数が使えないので4分休符のみのコーディングです。
調子に乗ってコーディングしていたら、プログラムエリアが足りなくなりました。
SOUNDとEEPROMのライブラリーで結構メモリーを食ってしまっているようです。



program MUSIC
'                             0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
'                             R   C   C#  D   D#  E   F   F#  G   G#  A   A#  B   C   C#  D
  const doremi as word[16]= (  0,262,277,294,311,330,349,370,392,415,440,466,494,523,554,587)
'                 tempo=120
'                              0    1    2    3    4    5    6    7    8  9
'                              1    2.   2    4.   4    8.   8   16.   16
  const onpu   as word[9]= (2000,1500,1000,0750,0500,0375,0250,0188,0125)

' Declarations section
sub procedure init_rtn
  GPIO = 0
  CMCON = 000111
  TRISIO = 000000
  'ANSEL = 000000

  Sound_Init(GPIO, 2)

end sub

main:

  dim eromdt as byte
  dim takapt as byte
  dim nagapt as byte
  dim takasa as word
  dim nagasa as word
  dim yasumi as word
  dim i as byte

  init_rtn

  while true
    i=0                         'EPROM READ POINTER
    while < 127                 'EPROM MAC ADDRESS 128
      eromdt = EEPROM_Read(i)   'DATA READ FROM EPROM
      if eromdt = $FF then      'DATA VALUE FF is END of DATA
        i =128                  'Exit Loop When set 128
      else
        takapt = eromdt and $0f 'DATA low4bit is SOUND Pitch
        nagapt = eromdt >> 4    'DATA High4bit is SOUND Length
        if takapt = 0 then
          'select case nagapt
          '  case 4
              Delay_ms(500)
          '  case 2
          '    delay_ms(1000)
          '  case 0
          '    delay_ms(2000)
          'end select
        else
          takasa = doremi[takapt]'Pitch Table
          nagasa = onpu[nagapt]
          Sound_Play(takasa,nagasa)
          Delay_ms(16)
        end if
      end if
      i=i+1
    wend
    
    'ENTRY SLEEP '
     GPIO =0
     OPTION_REG = 000000
     INTCON = %10001000'
     NOP
     NOP
     asm
       sleep
     end asm
     NOP
     NOP
    'RESUME SLEEP
     INTCON = 000000

  wend

end.



0 件のコメント: