人気ブログランキング | 話題のタグを見る

信号発生器の作成①

電子工作を行う上で、ある程度の計測器が必要になります。
今回は信号発生器を作りました。ファンクションジェネレーターです。



【はじめに】
テスターは買うしかないです。電圧可変の安定化電源は簡単に作れますな。
オシロはヤフオクとかで安い中古の物を入手できます。
回路図CADとかを動かすパソコンもwinxp出たての頃の中古品が数千円で買えます。

さて、オシロを入手したら、信号発生器があれば便利です。世の中には色々な方式の信号発生器がありますが、良くある方式じゃなくて面白い構成にチャレンジしてみました。頭の体操も兼ねた訳です。

【構成】
どういう方式を選択したかの考察は省きますが、下図の様な構成で作りました。
PIC16F84Aを信号発生器にしますが、DDSじゃなくてクロック周波数をLTC1799で可変するという禁じ手の方法です。表示はPIC16F648Aでやってみました。
ちょっと間違って図ではLT1799ですが正しくはLTC1799です。
信号発生器の作成①_e0298562_166283.png

使用したPICの品種は手持ちの物を消費する為に選択しました。最適じゃないです。
波形選択の所の4bitカウンタですが、使っているうちに面倒になったのでロータリー式のディップスイッチに変更したままです。
4bitパラレルにした理由は16F84Aの動作がLTC1799の周波数に依存しシリアル入力が不可だからです。
16F648Aの方も面倒なので同じ設定で動かせるパラレル入力にしました。
LTC1799とかほとんどの部品は秋月で入手できます。
電源はノイズが出ない様にデカップリングとか定電圧回路をしっかり作ります。

【動作】
16F84AはポートBの波形をループで出力するだけです。
通常は「波形反映」でリセットされ、最初に読んだ「波形選択」のビットに応じて
正弦波とかノコギリ波を出力します。
ただしパルス波形を選択した時は「波形選択」のビットでパルス幅が可変可能。
表示の方も「波形/デューティ」をLOにしてパルス幅を画面に出します。
16F648Aは周波数カウンタと、波形名称の画面表示、パルス幅の表示です。

【回路図】
縮小され見にくいですが、このブログは画像のクリックで原寸表示する様です。
信号発生器の作成①_e0298562_16374626.png


【16F648A側のソース】
ちょっと長いですがそこは勘弁して下さい。
このブログはタブが消える様で、しょうがなく全角スペースに置き換えています。
あとこのブログでは<lcd_lib_port_a0-a3.c>を半角の<>にすると非表示?

CCSのコンパイラを使ってます。
LCDドライバは有名な後閑さんのやつが元で、ポート変更して使ってます。
以下はソースです。

//
//周波数カウンタ
//

#include <16f648a.h>
#fuses HS,NOWDT,NOPROTECT,PUT,NOLVP,NOMCLR
#use delay(clock=10000000)

#define mode 0
#define input_x input_A  //3つともポートAにしてください。
#define output_x output_A
#define set_tris_x set_tris_A
#define stb PIN_B4
#define rs PIN_B5
#include <lcd_lib_port_a0-a3.c>  //A0〜A3ポート用のLCDドライバ

#byte bport=6

long f_count=0;
int i=0,j,k=19;
float freq;

#int_timer0  //内部クロックのカウント
void int_count()
{
  k--;
  if(k==0)
  {  
    f_count=get_timer1();
    j=i;
    set_timer1(0);
    i=0;
    k=19;
  }
}

#int_timer1  //外部入力パルスのカウント
void ext_count()
{
  i++;
}

void main()
{
  byte n;      // ポートBをバイトごと読む
  set_tris_b(0x4f);    //入力端子設定
  set_tris_a(0x10);

  lcd_init();      //LCD初期化
  lcd_clear();      //LCD全消去

  setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256);
  set_timer0(0);

  setup_timer_1(T1_EXTERNAL | T1_DIV_BY_1);
  set_timer1(0);

  enable_interrupts(int_timer0);
  enable_interrupts(int_timer1);
  enable_interrupts(GLOBAL);

  while (1)
  {
    freq=(f_count+j*65536)*2.0077354;  //周波数計算
          //10MHz÷4÷256÷256÷19=2.0077354
    lcd_cmd(0xC0);    //2行目の先頭へ
    printf(lcd_data,"%9.1fHz ",freq);
    delay_ms(200);

    n=(~bport & 0x0f);  // nに代入。ポートBの反転とビットマスク
    lcd_cmd(0x02);    //1行目の先頭へ
    if(input(pin_A4))  //ポートA4がHIなら波形名の表示
    {
      if(n==1)
      printf(lcd_data,"sinwave 6step ");
      if(n==2)
      printf(lcd_data,"sinwave 18step ");
      if(n==3)
      printf(lcd_data,"sinwave 33step ");
      if(n==4)
      printf(lcd_data,"sinwave 66step ");
      if(n==5)
      printf(lcd_data,"sinwave 132step ");
      if(n==6)
      printf(lcd_data,"sawwave 4step ");
      if(n==7)
      printf(lcd_data,"sawwave 8step ");
      if(n==8)
      printf(lcd_data,"sawwave 16step ");
      if(n==9)
      printf(lcd_data,"sawwave 32step ");
      if(n==10)
      printf(lcd_data,"sawwave 64step ");
      if(n==11)
      printf(lcd_data,"sawwave 128step ");
      if(n==12)
      printf(lcd_data,"sawwave 256step ");
      if(n==13)
      printf(lcd_data," pulse _|_|_");
      if(n==14)
      printf(lcd_data," pulse -|-|-");
      if(n==15)
      printf(lcd_data," burst -4-4-");
      if(n==0)
      printf(lcd_data,"random noise ");
    }
    else  //ポートA4がLOならパルス幅の表示
    {
    printf(lcd_data,"%u ",n);  // パルス幅設定を上書き表示 //
    }
  }

}


【16F84A側のソース】
テーブルを作ってループさせるだけです。
ポイントは乱数発生の所です。けっこう苦労しました。

// 16f84A波形発生器
//

#include <16f84a.h>
#fuses HS,NOWDT,NOPROTECT  // HSとする。RCだと25MHz以上で不安定
#use delay(clock=20000000)
#byte bport=6
#byte aport=5

void main()
{
  byte j;      //ポートAをバイトごと読む
  int i=0,m;

  set_tris_A(0x0f);  // ポートA0〜3は入力。ポートA4は出力
  set_tris_B(0x00);  // ポートBは全出力

  j=(~aport & 0x0f);  // jに代入。ポートAの反転とビットマスク

  output_high(pin_A4);

  if(j==2)  // j が1ならsine1までスキップ
  goto sine2 ;

  if(j==3)
  goto sine3 ;

  if(j==4)
  goto sine4 ;

  if(j==5)
  goto sine5 ;


  if(j==6)
  {
  i=64;      //階段の高さ(インクリメントの数値)
  goto sawwave ;
  }

  if(j==7)
  {
  i=32;      //数値がでかいと255まで上がるのが早い
  goto sawwave ;
  }

  if(j==8)
  {
  i=16;      //数値が小さいと255までちょっとずつ上がる
  goto sawwave ;
  }

  if(j==9)
  {
  i=8;
  goto sawwave ;
  }

  if(j==10)
  {
  i=4;
  goto sawwave ;
  }

  if(j==11)
  {
  i=2;
  goto sawwave ;
  }

  if(j==12)
  {
  i=1;
  goto sawwave ;
  }

  if(j==13)
  {
  output_low(pin_A4);
  goto pulse1 ;
  }

  if(j==14)
  {
  output_low(pin_A4);
  goto pulse2 ;
  }

  if(j==15)
  {
  output_low(pin_A4);
  goto burst ;
  }

  if(j==0)
  goto noisewave ;


//  sine1 : ;
  while(1)   //テーブルをループしているだけ
  {
    bport=64 ;
    bport=191 ;
    bport=255 ;
    bport=191 ;
    bport=64 ;
    bport=0 ;
  }

  sine2 : ;
  while(1)
  {
    bport=8 ;
    bport=30 ;
    bport=64 ;
    bport=105;
    bport=150 ;
    bport=191 ;
    bport=225 ;
    bport=247 ;
    bport=255 ;
    bport=247 ;
    bport=225 ;
    bport=191 ;
    bport=150 ;
    bport=105 ;
    bport=64 ;
    bport=30 ;
    bport=8 ;
    bport=0 ;
  }

  sine3 : ;
  while(1)
  {
    bport=5 ;
    bport=14 ;
    bport=27 ;
    bport=44 ;
    bport=64 ;
    bport=86 ;
    bport=109 ;
    bport=134 ;
    bport=158 ;
    bport=180 ;
    bport=201 ;
    bport=220 ;
    bport=235 ;
    bport=246 ;
    bport=253 ;
    bport=255 ;
    bport=253 ;
    bport=246 ;
    bport=235 ;
    bport=220 ;
    bport=201 ;
    bport=180 ;
    bport=158 ;
    bport=134 ;
    bport=109 ;
    bport=86 ;
    bport=64 ;
    bport=44 ;
    bport=27 ;
    bport=14 ;
    bport=5 ;
    bport=0 ;
  }

  sine4 : ;
  while(1)
  {
    bport=1 ;
    bport=2 ;
    bport=5 ;
    bport=9 ;
    bport=14 ;
    bport=20 ;
    bport=27 ;
    bport=35 ;
    bport=44 ;
    bport=54 ;
    bport=64 ;
    bport=75 ;
    bport=86 ;
    bport=97 ;
    bport=109 ;
    bport=121 ;
    bport=134 ;
    bport=146 ;
    bport=158 ;
    bport=169 ;
    bport=180 ;
    bport=191 ;
    bport=201 ;
    bport=211 ;
    bport=220 ;
    bport=228 ;
    bport=235 ;
    bport=241 ;
    bport=246 ;
    bport=250 ;
    bport=253 ;
    bport=254 ;
    bport=255 ;
    bport=254 ;
    bport=253 ;
    bport=250 ;
    bport=246 ;
    bport=241 ;
    bport=235 ;
    bport=228 ;
    bport=220 ;
    bport=211 ;
    bport=201 ;
    bport=191 ;
    bport=180 ;
    bport=169 ;
    bport=158 ;
    bport=146 ;
    bport=134 ;
    bport=121 ;
    bport=109 ;
    bport=97 ;
    bport=86 ;
    bport=75 ;
    bport=64 ;
    bport=54 ;
    bport=44 ;
    bport=35 ;
    bport=27 ;
    bport=20 ;
    bport=14 ;
    bport=9 ;
    bport=5 ;
    bport=2 ;
    bport=1 ;
    bport=0 ;
  }

  sine5 : ;
  while(1)
  {
    bport=0 ;
    bport=0 ;
    bport=1 ;
    bport=1 ;
    bport=1 ;
    bport=2 ;
    bport=4 ;
    bport=5 ;
    bport=7 ;
    bport=9 ;
    bport=12 ;
    bport=14 ;
    bport=17 ;
    bport=20 ;
    bport=24 ;
    bport=27 ;
    bport=31 ;
    bport=35 ;
    bport=40 ;
    bport=44 ;
    bport=49 ;
    bport=54 ;
    bport=59 ;
    bport=64 ;
    bport=69 ;
    bport=75 ;
    bport=80 ;
    bport=86 ;
    bport=92 ;
    bport=97 ;
    bport=103 ;
    bport=109 ;
    bport=115 ;
    bport=121 ;
    bport=128 ;
    bport=134 ;
    bport=140 ;
    bport=146 ;
    bport=152 ;
    bport=158 ;
    bport=163 ;
    bport=169 ;
    bport=175 ;
    bport=180 ;
    bport=186 ;
    bport=191 ;
    bport=196 ;
    bport=201 ;
    bport=206 ;
    bport=211 ;
    bport=215 ;
    bport=220 ;
    bport=224 ;
    bport=228 ;
    bport=231 ;
    bport=235 ;
    bport=238 ;
    bport=241 ;
    bport=243 ;
    bport=246 ;
    bport=248 ;
    bport=250 ;
    bport=251 ;
    bport=253 ;
    bport=254 ;
    bport=254 ;
    bport=254 ;
    bport=255 ;
    bport=255 ;
    bport=255 ;
    bport=254 ;
    bport=254 ;
    bport=254 ;
    bport=253 ;
    bport=251 ;
    bport=250 ;
    bport=248 ;
    bport=246 ;
    bport=243 ;
    bport=241 ;
    bport=238 ;
    bport=235 ;
    bport=231 ;
    bport=228 ;
    bport=224 ;
    bport=220 ;
    bport=215 ;
    bport=211 ;
    bport=206 ;
    bport=201 ;
    bport=196 ;
    bport=191 ;
    bport=186 ;
    bport=180 ;
    bport=175 ;
    bport=169 ;
    bport=163 ;
    bport=158 ;
    bport=152 ;
    bport=146 ;
    bport=140 ;
    bport=134 ;
    bport=128 ;
    bport=121 ;
    bport=115 ;
    bport=109 ;
    bport=103 ;
    bport=97 ;
    bport=92 ;
    bport=86 ;
    bport=80 ;
    bport=75 ;
    bport=69 ;
    bport=64 ;
    bport=59 ;
    bport=54 ;
    bport=49 ;
    bport=44 ;
    bport=40 ;
    bport=35 ;
    bport=31 ;
    bport=27 ;
    bport=24 ;
    bport=20 ;
    bport=17 ;
    bport=14 ;
    bport=12 ;
    bport=9 ;
    bport=7 ;
    bport=5 ;
    bport=4 ;
    bport=2 ;
    bport=1 ;
    bport=1 ;
    bport=1 ;
    bport=0 ;
  }


  sawwave : ;
  while(1)
  {
    bport=bport+i;

  }

  pulse1 : ;
  while(1)
  {
    bport=255;
    bport=0;
    j=(~aport & 0x0f);
    m=j+1;    //バイトjによってパルス幅設定する
    while(m>1)
    {
      m--;
      delay_us(1);
    }

  }

  pulse2 : ;
  while(1)
  {
    bport=255;
    bport=1;
    bport=127;
    j=(~aport & 0x0f);
    m=j+1;
    while(m>1)
    {
      m--;
      delay_us(1);
    }
  }

  burst : ;
  while(1)   //トーンバーストのテーブル
  {
    bport=134 ;
    bport=158 ;
    bport=180 ;
    bport=201 ;
    bport=220 ;
    bport=235 ;
    bport=246 ;
    bport=253 ;
    bport=255 ;
    bport=253 ;
    bport=246 ;
    bport=235 ;
    bport=220 ;
    bport=201 ;
    bport=180 ;
    bport=158 ;
    bport=134 ;
    bport=109 ;
    bport=86 ;
    bport=64 ;
    bport=44 ;
    bport=27 ;
    bport=14 ;
    bport=5 ;
    bport=1 ;
    bport=5 ;
    bport=14 ;
    bport=27 ;
    bport=44 ;
    bport=64 ;
    bport=86 ;
    bport=109 ;
    bport=134 ;
    bport=158 ;
    bport=180 ;
    bport=201 ;
    bport=220 ;
    bport=235 ;
    bport=246 ;
    bport=253 ;
    bport=255 ;
    bport=253 ;
    bport=246 ;
    bport=235 ;
    bport=220 ;
    bport=201 ;
    bport=180 ;
    bport=158 ;
    bport=134 ;
    bport=109 ;
    bport=86 ;
    bport=64 ;
    bport=44 ;
    bport=27 ;
    bport=14 ;
    bport=5 ;
    bport=1 ;
    bport=5 ;
    bport=14 ;
    bport=27 ;
    bport=44 ;
    bport=64 ;
    bport=86 ;
    bport=109 ;
    bport=134 ;
    bport=158 ;
    bport=180 ;
    bport=201 ;
    bport=220 ;
    bport=235 ;
    bport=246 ;
    bport=253 ;
    bport=255 ;
    bport=253 ;
    bport=246 ;
    bport=235 ;
    bport=220 ;
    bport=201 ;
    bport=180 ;
    bport=158 ;
    bport=134 ;
    bport=109 ;
    bport=86 ;
    bport=64 ;
    bport=44 ;
    bport=27 ;
    bport=14 ;
    bport=5 ;
    bport=1 ;
    bport=5 ;
    bport=14 ;
    bport=27 ;
    bport=44 ;
    bport=64 ;
    bport=86 ;
    bport=109 ;
    bport=134 ;
    bport=158 ;
    bport=180 ;
    bport=201 ;
    bport=220 ;
    bport=235 ;
    bport=246 ;
    bport=253 ;
    bport=255 ;
    bport=253 ;
    bport=246 ;
    bport=235 ;
    bport=220 ;
    bport=201 ;
    bport=180 ;
    bport=158 ;
    bport=134 ;
    bport=109 ;
    bport=86 ;
    bport=64 ;
    bport=44 ;
    bport=27 ;
    bport=14 ;
    bport=5 ;
    bport=1 ;
    bport=5 ;
    bport=14 ;
    bport=27 ;
    bport=44 ;
    bport=64 ;
    bport=86 ;
    bport=109 ;
    bport=127 ;

    j=(~aport & 0x0f);
    m=(j+1)*2;
    while(m>1)
    {
      m--;
      delay_us(20);
    }
  }


  noisewave : ;
  while(1)
  {
    bport=3*bport+121;  // 擬似乱数1
    swap(bport);    // 上下ビット入れ替えで乱雑度アップ
    i=3*i+111;    // 擬似乱数2
    swap(i);
    bport=bport^i;    // 2つの擬似乱数のxorを行い乱雑度アップ
  }
}


【注意事項】
真似て作らないで下さい。当方は何の保証も致しません。

【予告】
次回は実際に作ったものを検証してみます。

以上です。













by ca3080 | 2013-01-24 18:02 | 電子工作(一般)
<< 信号発生器の作成② 古銭のサイトを作成しました >>