I2Cで音楽演奏

  1. 音楽演奏


    1. 機能

      I2Cから音階データを受け取り、小型スピーカで再生する。スレーブの数だけ同時演奏可能です。音階データやプログラムの詳細はここを参照してください。

  2. マスター


    1. マスター回路

      LEDのI2Cマスター回路と同じです。

    2. マスタープログラム

      音階データを適当な速度(500mS)でスレーブにおくります。

      //I2CLedMst88.c
      // I2Cマスターテストプログラム      //  
      //音階を送る
      //PC0:テスト用LED
      
      #include <16f873a.h>
      
      #fuses HS,NOWDT,NOLVP
      #use delay(CLOCK=20000000) //クロック20MHz
      #use i2c(MASTER,sda=PIN_C4,scl=PIN_C3)
      
      //メイン関数/////////////////////////////////////////
      #define sounddva 0x80
      
      int num;
      int flag;
         
      //メロディ 
      int melody[30]={0,2,3,5,7,8,10,12,14,15,17,19,20,22,24,26,27,0xff};
      int melody1[30]={0,2,3,5,7,8,10,12,14,15,17,19,20,22,24,26,27,0xff};
      int i,oto;
      
      void main(){
      
       num=30;//melody[]配列の音符の数     
      
       while(1){
         for(i=0;i<num;i++){
           output_toggle(pin_c0);
           oto=melody[i];
           if(oto==255) break;//1曲終了
      
          i2c_start();  //I2Cで送る
          i2c_write(sounddva);
          i2c_write(oto ); 
          i2c_stop();
      
           delay_ms(500);
         }
         delay_ms(500);//次の音符までの時間
        }//while
      }

  3. スレーブ


    1. スレーブ回路

       PC0にコンデンサを介してスピーカを接続します。他は、LEDのI2Cスレーブ回路と同じです。

    2. スレーブプログラム


      //i2cLEDSlv873.c
      //i2cから音階データを受け取り演奏する:PC1出力
      //I2Cアドレス0x80
      //PC0:割り込みトグル
      
      #include <16F873A.h>
      #fuses HS,NOWDT,NOPROTECT,NOLVP,NOBROWNOUT
      #use delay(clock = 20000000) 
      #use I2c(slave,sda=PIN_C4,scl=PIN_C3,address=0x80,force_hw)
      
      int flag;
      //音階の周期 ラ ラ# シ ド ド# レ レ# ミ ファ ファ# ソ ソ# ラ ラ# シ ド  ド# レ レ#
      //           0     2   3     5      7  8         10     12    14  15     17
      unsigned long onkai[30]=
              {62695,62854,63005, 63147,63281,63407,63527,63639,
              63746,63847,63941,64031,64115,64195,64270,64341,
              64408,64471,64531,64587,64641,64691,64738,64783,
              64825,64865,64903,64938};
      unsigned long prd;
      
      int oto;
      int state;
      
      #INT_SSP
      void ssp_interupt (){
          
         state=i2c_isr_state();
         output_toggle(PIN_A0);
         
         if(state>=0x80){//addrs match with master read         
                //i2c_write(0);//return  value
          }
          else if(state >0){//adrs match with master write
           output_toggle(pin_c0);
                 oto=i2c_read();//1:ack,default 0:nack
           if(oto==255) prd=0;//低い音を出す
           prd=onkai[oto];
             //output_toggle(PIN_B1);
          }
      }
      
      //タイマー割り込み関数
      #int_timer1
      void timer1_isr()
      {
          output_bit(PIN_C1,flag);//C1にパルスを発生する
          if (flag==1) flag=0; else flag=1;
          set_timer1(prd);
      }
      
      void main (){
              
         setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
         set_timer1(0);
      
          enable_interrupts(INT_TIMER1); //タイマ0割込み許可
          enable_interrupts(INT_SSP);     //SSP割り込みを許可
          enable_interrupts(GLOBAL);      //全ての割り込みを許可
         
           while (1) {
      
          }              
      }