目次

音出し(割込み活用)

 音を出すには音源を複数用意して、切り替える方法もあります。
 ブロック図でみると、以下。




 複数の音源を用意して、アナログマルチプレクサで切り替えれば
 チャイムや警報音を出力できます。

 この方式で回路を考えました。




 PICからアナログマルチプレクサに2ビットのパターンを与えると
 対応した周波数の音がスピーカから出力される方式。

 音を出すためにPICが担当する役割は、以下の2点。

 周波数選択
 出力時間決定

 出力時間は、タイマー割込みで2msを刻んで
 システムタイマーを作り、関数で時間幅を調整
 すればよいでしょう。

 割込みによるシステムタイマーの定義は、以下。

typedef unsigned long ULONG ;

ULONG xcnt ;

void interrupt(void)
{
  /* generate 2ms */
  if ( INTCON.TMR0IF == ON ) {
    /* clear flag */
    INTCON.TMR0IF = OFF ;
    /* 256 - 250 = 6 */
    TMR0 = 6 ;
    /* increment */
    xcnt++ ;
  }
}

 1msの割込みで、システムタイマーカウンタxcntをインクリメント
 しておき、時間幅はdelay_ms、delayで生成します。

typedef unsigned char UBYTE ;
typedef unsigned int  UWORD ;

void delay_ms(UWORD x)
{
  ULONG last ;
  /* calculate target */
  last = xcnt + (x >> 1);
  /* wait */
  while ( xcnt < last ) ;
}

void delay(UBYTE x)
{
  UWORD i ;
  UBYTE last ;
  /* last count */
  last = x ;
  /* wait */
  for ( i = 0 ; i < last ; i++ ) {
    delay_ms(1000);
  }
}

 最下位でハードウエアを動かす関数を定義します。
 周波数と時間幅をパラメータにして関数snd_outを定義。

#define SND_A    0
#define SND_B    1
#define SND_C    2
#define SND_D    3
#define SND_NONE 7

void snd_out(UBYTE which,UWORD tx)
{
  /* judge sound number */
  if ( which > SND_NONE ) return ;
  /* send sound number */
  PORTA = which & 7 ;
  /* delay (1 second x N) */
  delay( tx );
}

 チャイムを鳴らすような場合、プッシュボタンを利用して
 トリガーを与えます。
 トリガーが来たかを判断するのは、入力ピンの論理値が
 0から1、1から0の変化をとらえます。



 PIC16F627では、ポートBの0ビット目が外部割込みの入力
 ピンになっているので、ここにプッシュボタンを接続して
 トリガーを扱えるようにします。



 外部割込みを使うと、割込みハンドラに対応するコードを追加。

void interrupt(void)
{
  /* generate 1ms */
  if ( INTCON.TMR0IF == ON ) {
    /* clear flag */
    INTCON.TMR0IF = OFF ;
    /* 256 - 250 = 6 */
    TMR0 = 6 ;
    /* increment */
    xcnt++ ;
  }
  /* external interrupt */
  if ( INTCON.INTF == ON ) {
    /* clear flag */
    INTCON.INTF = OFF ;
    /* set event flag */
    EFLAG = ON ;
  }
}

 割込み関連レジスタの該当フラグを見て、セットされていた
 ならば、クリア後、イベント通知フラグをセット。

 イベント通知フラグをとらえて、チャイムを鳴らすシーケンスを
 起動してみればよいでしょう。

    if ( EFLAG == ON ) {
      /* clear flag */
      EFLAG = OFF ;
      /* start */
      snd_out(SND_A,1);
      snd_out(SND_B,3);
      snd_out(SND_C,2);
      snd_out(SND_D,5);
      snd_out(SND_C,3);
      snd_out(SND_B,2);
      snd_out(SND_A,3);
    }

 2つの割込みを使えるように、初期化処理を定義。

  /* initialize timer 0 */
  {
    /*
       4MHz/4 = 1MHz (Fosc)
       Fosc/4 = 250kHz
       250kHz/2 = 125kHz prescaler = 1:2
    */
    OPTION_REG = 0x00 ;
    /* 256 - 250 = 6 */
    TMR0 = 6 ;
    /* enable timer0 overflow interrupt */
    INTCON.TMR0IE = ON ;
  }
  /* external interrupt */
  {
    /* select edge manner */
    OPTION_REG.INTEDG = ON ;
    /* enable */
    INTCON.INTE = ON ;
  }
  /* enable general interrupt */
  INTCON.GIE = ON ;

 ソースコードをまとめると、以下。

#define OFF 0
#define ON  OFF+1

typedef unsigned char  UBYTE ;
typedef unsigned int   UWORD ;
typedef unsigned long  ULONG ;

#define SND_A    0
#define SND_B    1
#define SND_C    2
#define SND_D    3
#define SND_NONE 7

volatile UBYTE EFLAG ;
volatile ULONG xcnt ;

/* prototype */
void  usr_init(void);
void  snd_out(UBYTE which,UWORD tx);
void  delay_ms(UWORD x);
void  delay(UBYTE x);

void main(void)
{
  /* initialize */
  usr_init();
  /* endless loop */
  while (ON) {
    if ( EFLAG == ON ) {
      /* clear flag */
      EFLAG = OFF ;
      /* start */
      snd_out(SND_A,1);
      snd_out(SND_B,3);
      snd_out(SND_C,2);
      snd_out(SND_D,5);
      snd_out(SND_C,3);
      snd_out(SND_B,2);
      snd_out(SND_A,3);
    }
  }
}

void usr_init(void)
{
  /* initialize PORT values */
  PORTA = 0x00 ;
  PORTB = 0x00 ;
  /* set directions */
  TRISA = 0x00 ;
  TRISB = 0xfe ;
  /* initialize timer 0 */
  {
    /*
       4MHz/4 = 1MHz (Fosc)
       Fosc/4 = 250kHz
       250kHz/2 = 125kHz prescaler = 1:2
    */
    OPTION_REG = 0x00 ;
    /* 256 - 250 = 6 */
    TMR0 = 6 ;
    /* enable timer0 overflow interrupt */
    INTCON.TMR0IE = ON ;
  }
  /* external interrupt */
  {
    /* select edge manner */
    OPTION_REG.INTEDG = ON ;
    /* enable */
    INTCON.INTE = ON ;
  }
  /* enable general interrupt */
  INTCON.GIE = ON ;
  /* others */
  EFLAG = OFF ;
  xcnt = 0 ;
  snd_out(SND_NONE,0);
}

void  snd_out(UBYTE which,UWORD tx)
{
  /* judge sound number */
  if ( which > SND_NONE ) return ;
  /* send sound number */
  PORTA = which & 7 ;
  /* delay (1 second x N) */
  delay( tx );
}

void delay_ms(UWORD x)
{
  ULONG last ;
  /* calculate target */
  last = xcnt + (x >> 1);
  /* wait */
  while ( xcnt < last ) ;
}

void delay(UBYTE x)
{
  UWORD i ;
  UBYTE last ;
  /* last count */
  last = x ;
  /* wait */
  for ( i = 0 ; i < last ; i++ ) {
    delay_ms(1000);
  }
}

 PIC16F627は、切替え器を構成していると言えます。

 すべての機能をマイコンに持たせないで、固定した専用回路で
 実現できることは任せた方が、わかりやすいこともあります。


目次

inserted by FC2 system