PICマイコンで圧電スピーカーを鳴らしてみた【PIC16F1938】

スピーカーの駆動原理

前回はLEDの電子ホタルプログラムを書きました。今回も全く同様な手段でスピーカーを鳴らしてみます。使用しているPICはPIC16F1938です。

音とは

音とは、空気の振動を人間が感知したもののことを言います(それはそう)。振動が早ければ早いほど音は高くなります。

大事な概念として周波数があります。これは、1秒間に何回振動するかということですね。これの逆数を取ると、周期になります。これは、1回の振動に何秒かかるかを表します。PICでは、__delay_us()関数を使った方が楽なので、周期を使います。

圧電スピーカーの使い方

圧電スピーカーとは、電圧をかけると内部の板が変形するスピーカーです。電圧のオンオフを高速で繰り返せば、この板が振動し、音として聞こえます。

今回は秋月電子通商の圧電スピーカー(圧電サウンダ)SPT08 (2個入)を使いました。これ以外のスピーカーであっても、これから紹介するプログラムで動かすことができます。

上記の写真のように圧電スピーカーには極性があり、プラスをPICへ、マイナスをGNDへ繋ぎます。ただし、直接PICに繋ぐとうるさいのでお勧めしません。間に500Ω程度の抵抗を挟むといいでしょう。

下の画像のように、ワイヤーの芯を露出させ、ジャンパワイヤに繋ぐと今後工作がしやすくなるのでお勧めです。(これをしないとブレッドボードに刺さらない)今後も使うので、ジャンパワイヤに巻いてそこをはんだ付けするといいでしょう。

音階を作る

「ド」の音を作る

「ド」の音を作ってみましょう。ドに当たる音の周期はこちらのサイトによると3.82ms、つまり3820μsとなります。一回の振動のうち、スピーカーがオンになっているのはその半分の1908μsです。つまり、以下のようにすれば1回板が振動して、ドの音が瞬間的に出ることになります。


      RA1 = 1;    //RA1(スピーカーがつながっているピン)をオン
      __delay_us(1908);
      RA1 = 0;    //スピーカーをオフ
      __delay_us(1908);
    

これでは瞬間的にしか音が出ないので、これをfor文で繰り返しましょう。ここで、1秒間「ド」を鳴らすようにしてみましょう。一周に3820μsかかるので、1秒間に1/3820μs回=261回繰り返せばいいですね。


void do1(){
    for(long i = 1;i<261;i++){
        RA1 = 1;
        __delay_us(1908);
        RA1 = 0;
        __delay_us(1908);
    }
}
    

多くの時間繰り返せるようにiはlongにしました。今回はここまで必要ないので、intでもいいでしょう。なんと、これでドの音は完成です!main関数にdo1();と記述し、確かめてみてください。

PICへの書き込み方法はこちら PICにプログラムを書き込んでみよう

ドレミファソラシドを鳴らす

ここまでくれば簡単です。先程ご紹介したサイトを頼りに、他の音階も作ればいいのです。全く同じ手順を踏むので、割愛させていただきます。

下のコードではRA1ではなくsoundという変数を使っています。これは、冒頭で


      #define sound RA1
    

としているだけです。スピーカーがつながっているピンを変えたいときは、この記述を変えれば全て置き換わるので便利です。


      void do1(){
          for(long i = 1;i<261;i++){
              sound = 1;
              __delay_us(1908);
              sound = 0;
              __delay_us(1908);
          }
      }
      void re1(){
          for(long i = 1;i<294;i++){
              sound = 1;
              __delay_us(1700);
              sound = 0;
              __delay_us(1700);
          }
      }
      void mi1(){
          for(long i = 1;i<330;i++){
              sound = 1;
              __delay_us(1515);
              sound = 0;
              __delay_us(1515);
          }
      }
      void fa1(){
          for(long i = 1;i<349;i++){
              sound = 1;
              __delay_us(1432);
              sound = 0;
              __delay_us(1432);
          }
      }
      void so1(){
          for(long i = 1;i<392;i++){
              sound = 1;
              __delay_us(1275);
              sound = 0;
              __delay_us(1275);
          }
      }
      void ra1(){
          for(long i = 1;i<440;i++){
              sound = 1;
              __delay_us(1136);
              sound = 0;
              __delay_us(1136);
          }
      }
      void si1(){
          for(long i = 1;i<494;i++){
              sound = 1;
              __delay_us(1012);
              sound = 0;
              __delay_us(1012);
          }
      }
      void do2(){
          for(long i = 1;i<523;i++){
              sound = 1;
              __delay_us(956);
              sound = 0;
              __delay_us(956);
          }
      }
    

完成したプログラム

基本の設定等はここと変わらないので、コピペで行けます。一応下に全文載せておきます。


    // PIC16F1938 Configuration Bit Settings

    // 'C' source line config statements

    // CONFIG1
    #pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
    #pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
    #pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
    #pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
    #pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
    #pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
    #pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
    #pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
    #pragma config IESO = OFF       // Internal/External Switchover (Internal/External Switchover mode is disabled)
    #pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)

    // CONFIG2
    #pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
    #pragma config VCAPEN = OFF     // Voltage Regulator Capacitor Enable (All VCAP pin functionality is disabled)
    #pragma config PLLEN = OFF// PLL Enable (4x PLL disabled)
    #pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
    #pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
    #pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)

    // #pragma config statements should precede project file includes.
    // Use project enums instead of #define for ON and OFF.

    #include <xc.h>
    #define _XTAL_FREQ 8000000L
    #define sound RA1
    void PICinit(){
      OSCCON = 0b01110000;
      ANSELA = 0b00000000;
      ANSELB = 0b00000000;
      TRISA  = 0b00000000;
      TRISB  = 0b00000000;
      TRISC  = 0b00000000;
      PORTA  = 0b00000000;    //2進数で書いた場合
      PORTB  = 0x00;          //16進数で書いた場合
      PORTC  = 0;            //10進数で書いた場合
    }


    void do1(){
        for(long i = 1;i<261;i++){
            sound = 1;
            __delay_us(1908);
            sound = 0;
            __delay_us(1908);
        }
    }
    void re1(){
        for(long i = 1;i<294;i++){
            sound = 1;
            __delay_us(1700);
            sound = 0;
            __delay_us(1700);
        }
    }
    void mi1(){
        for(long i = 1;i<330;i++){
            sound = 1;
            __delay_us(1515);
            sound = 0;
            __delay_us(1515);
        }
    }
    void fa1(){
        for(long i = 1;i<349;i++){
            sound = 1;
            __delay_us(1432);
            sound = 0;
            __delay_us(1432);
        }
    }
    void so1(){
        for(long i = 1;i<392;i++){
            sound = 1;
            __delay_us(1275);
            sound = 0;
            __delay_us(1275);
        }
    }
    void ra1(){
        for(long i = 1;i<440;i++){
            sound = 1;
            __delay_us(1136);
            sound = 0;
            __delay_us(1136);
        }
    }
    void si1(){
        for(long i = 1;i<494;i++){
            sound = 1;
            __delay_us(1012);
            sound = 0;
            __delay_us(1012);
        }
    }
    void do2(){
        for(long i = 1;i<523;i++){
            sound = 1;
            __delay_us(956);
            sound = 0;
            __delay_us(956);
        }
    }
    int main(void){
      PICinit();      //PICを初期化
      while(1){
          do1();
          re1();
          mi1();
          fa1();
          so1();
          ra1();
          si1();
          do2();
      }


      return 0;
    }
  

次回

次回は、このドレミを使った簡単な曲を演奏してみます。次回

「PICマイコンで圧電スピーカーを鳴らしてみた【PIC16F1938】」に5件のコメントがあります

  1. ピンバック: Wak-tech » PIC16F1938で「ようこそジャパリパークへ」を演奏してみた

  2. ピンバック: Wak-tech » PICで電子ホタルを作る

  3. ピンバック: ESP32で圧電スピーカーを動かしてみた【wak-tech Advent Calender 2018】 | Wak-tech

  4. ピンバック: PICマイコンに素数を計算させてみた | Wak-tech

  5. ピンバック: 動けばいい人のためのPICマイコン入門 | Wak-tech

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です