目次

D/A converter

 8ピンのPIC12F1501には、D/A変換器が含まれてます。

 PICではD/A変換器を内蔵しているチップは少ないので
 これを機会に使い方をマスターしようと考えました。

 D/A変換器は、VCO(Voltage Controlled Oscillator)で
 利用する、バリキャップの逆電圧を制御してみます。

 D/A変換器の出力を安定させるため、OPアンプを
 使った電圧フォロワを入れておきます。



 D/A変換器に関する情報を、データシートから抜出して
 みると、次のようになっています。



 D/A変換器を使うためには、レジスタDACCON0のDACENビットを
 1に設定します。さらに、D/A変換器の出力をどこにするかを
 指定します。また、リファレンス電圧を電源電圧にするのか
 Vref入力を使うのかをブロック図を見て指定します。



 今回は、DACOUT1を使います。

 D/A変換器の出力は、次の3角波とします。



  D/A変換器の設定値は0から31なので、カウンタで
 0から31、31から0を生成し、レジスタに書込みます。

 0から31、31から0を生成するのは、タイマー割込みで
 ステートマシンを動かし、ステートをインクリメントして
 いきます。

 ステートは0から63とし、このステート値をデコーダに
 いれて、0から31、31から0を生成します。

 D/A変換器の制御は、2関数に担当させます。

 初期化
  リファレンス電圧、D/A変換値出力を指定後、D/A変換
  モジュールを使うと宣言します。

void  dac_init(void)
{
  /* reference Vdd */
  DACCON0.DACPSS = OFF ;
  /* enable DAC output #1 */
  DACCON0.DACOE1 = ON ;
  /* use DAC */
  DACCON0.DACEN = ON ;
}

 値出力
  D/A変換器の設定値は0から31なので、その範囲になるよう
  レンジチェックして出力します。

void  dac_write(UBYTE x)
{
  DACCON1 = (0x1f & x);
}

 タイマー割込みを使うので、タイマー0のオーパーフロー割込み
 を使います。割込みハンドラは、次のように定義します。

void interrupt(void)
{
  /* generate 500Hz(2ms) */
  if ( INTCON.T0IF == ON ) {
    /* clear flag */
    INTCON.T0IF = OFF ;
    /* initialize */
    TMR0 = CNTBEGIN ;
    /* increment */
    timcnt++ ;
    /* judge */
    if ( timcnt == CNTMAX ) {
      /* clear */
      timcnt = 0 ;
      /* set flag */
      eflag = ON ;
    }
  }
}

 2ms周期で、D/A変換器の出力値を更新します。

 MikroCを利用したソースコードは、以下。

typedef unsigned char  UBYTE ;
typedef unsigned short UWORD ;

#define OFF 0
#define ON  OFF+1

#define CNTBEGIN 6
#define CNTMAX   32

volatile UWORD timcnt ;
volatile UBYTE eflag ;
volatile UBYTE state ;
volatile UBYTE tmp ;

/* function prototype */
void  init_usr(void);
void  dac_write(UBYTE x);
void  dac_init(void);

/* interrupt handler */
void interrupt(void)
{
  /* generate 500Hz(2ms) */
  if ( INTCON.T0IF == ON ) {
    /* clear flag */
    INTCON.T0IF = OFF ;
    /* initialize */
    TMR0 = CNTBEGIN ;
    /* increment */
    timcnt++ ;
    /* judge */
    if ( timcnt == CNTMAX ) {
      /* clear */
      timcnt = 0 ;
      /* set flag */
      eflag = ON ;
    }
  }
}

void main(void)
{
  /* initialize */
  init_usr() ;
  /* endless loop */
  while ( ON ) {
    /* event handling */
    if ( eflag == ON ) {
      /* clear flag */
      eflag = OFF ;
      /* impress */
      tmp = state ;
      if ( state > 31 ) { tmp = 31 - state ; }
      dac_write( tmp ) ;
      /* increment */
      state++ ;
      /* judge */
      if ( state & 0x40 ) {
        state = 0 ;
      }
    }
  }
}

/* define function body */
void init_usr(void)
{
  /* select 4MHz */
  OSCCON = (0x0d << 3) | 0x03 ;
  /* disable A/D converter */
  ADCON0.ADON = OFF ;
  ADCON2      = 0 ;
  /* initialize D/A converter */
  dac_init();
  /* disable compare module */
  CM1CON0.C1ON = OFF ;
  CM1CON0.C1OE = OFF ;
  /* I/O state */
  LATA = 0 ;
  /* I/O directions */
  TRISA = 0xf8 ; /* bit0,1,2 as output , others as input */
  /* pull-up */
  WPUA = 0x30 ;
  /* initialize Timer 0 */
  {
    /*
       4MHz/4 = 1MHz -> 1MHz/8 = 125kHz prescaler = 1:8
    */
    OPTION_REG = 0x02 ;
    /* 256 - 6 = 250 */
    TMR0 = CNTBEGIN ;
    /* enable timer0 overflow interrupt */
    INTCON.TMR0IE = ON ;
  }
  /* enable general interrupt */
  INTCON.GIE = ON ;
  /* clear flag */
  eflag = OFF ;
  /* initialize variables */
  timcnt = 0 ;
  state = 0 ;
}

void  dac_write(UBYTE x)
{
  DACCON1 = (0x1f & x);
}

void  dac_init(void)
{
  /* reference Vdd */
  DACCON0.DACPSS = OFF ;
  /* enable DAC output #1 */
  DACCON0.DACOE1 = ON ;
  /* use DAC */
  DACCON0.DACEN = ON ;
}

 D/A変換器の出力には、OPアンプによるバッファを入れるよう
 データシートに記載があるので、次の回路をバッファで入れ
 ます。



 テストに利用した基板は、以下。




目次

inserted by FC2 system