読者です 読者をやめる 読者になる 読者になる

やっつけファンクションジェネレータ作成

 以前直流電源が欲しくて電源装置を作りましたが、その時に正弦波が欲しい何て書いてたのをついに実行に移しました。

欲しかった仕様

波形:正弦波・のこぎり派・方形波(duty可変)
周波数:可聴域(~20kHz)
振幅:最大5Vpp

出来上がった仕様

波形:正弦波・のこぎり派・方形波(duty50%固定)
周波数:70~2kHz (周期およそ14msの1~32?等分)
振幅:最大およそ4.5Vpp(これ以上は波形がクリップ)
SN比:未測定(目測では結構酷い)




ハードウェア

 主要なICはATMega88, LM358 x2の3つだけ。あと昇圧回路。ATMega88でLCD表示と波形の作成。OpAmpでバイアス・ゲイン調整、LPFなどやってます。

 波形生成はR-2Rラダーを使えば割と簡単にできます。OpAmpは単電源で使うとバイアスの位置が地味にややこしくなって苦労しました。それと30mA?までしか出力が取れないので、テキトーに作ろうとするとすぐに波形がクリップして歪みました。と言うわけでアナログ系の回路に大変時間をかけることに。

 便利だろうと思ってACアダプタから電源を取れるようにソケットを付けましたが、ACアダプタのスイッチングノイズが酷く使い物になりません。

ソフトウェア*1

 main内のwhileで波形を出してます。波形を長さ1024の配列に入れて順番に、あるいは数個おきにPORTに吐き出すだけ。スイッチの読み込みはポーリングして読みに行くとこれも波形表示に支障が出てくるので割り込みにしてます。

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#define LEN 1024
#define MAX 32

volatile int step = 1;
volatile int state;
PROGMEM unsigned char sin[LEN] = { /* ... */ }; // 正弦波
PROGMEM unsigned char saw[LEN] = { /* ... */ }; // のこぎり派
PROGMEM unsigned char squ[LEN] = { /* ... */ }; // 方形波

ISR(PCINT0_vect){
  _delay_ms(10); // チャタリング対策  
  if((~PINB & (1<<PB0)) == (1<<PB0)) {
    if(++state == 3) state = 0; // state を 0, 1, 2, 0, ...にトグル
  } else if((~PINB & (1<<PB1)) == (1<<PB1)) {
    if(step != 1) step--;  
  } else if((~PINB & (1<<PB2)) == (1<<PB2)) {
    if(step != MAX) step++;
  }
}
int main(void){
  /* interrupt init */  DDRB = 0x00;
  PORTB = (1<<PB2)|(1<<PB1)|(1<<PB0);  PCICR = (1<<PCIE0);
  PCMSK0 = (1<<PCINT2)|(1<<PCINT1)|(1<<PCINT0);
  /* DAC init */  DDRD  = 0xFF;
  PORTD = 0x00;  unsigned int i = 0;
  state = 0;
  sei();

  while(1) {
    i = ((i+step) & (LEN-1));
    if(state == 0) PORTD = pgm_read_byte_near(sin+i);
    else if(state == 1) PORTD = pgm_read_byte_near(saw+i);
    else if(state == 2) PORTD = pgm_read_byte_near(squ+i);
  }
   return 0;
}


出力する波形をwhile内で分岐させてるためにちょっとオーバーヘッドが出てます。上手くポインタを駆使してwhile内で分岐しないようにやろうとするも失敗に終わり断念しました。

波形(正弦波のみ)


最小周波数 1V/div-5ms/div



最大周波数 1V/div-0.5ms/div



安定化電源使用時(最小周波数) 1V/div-2ms/div

ACアダプタ使用時(最小周波数) 1V/div-2ms/div

まとめ

  • OpAmp怖い
  • OpAmpかわいい
  • ACアダプタを使うときはシリーズレギュレータ通すこと
  • キレイなご飯をICにあげよう
  • ノイズ対策はしっかりすべき(テキトーにやりすぎ)
  • いい加減感光基板を使おう
  • ケースにおさめるまでが電子工作
  • 2次以上のフィルタも気軽に作れるように
  • C言語をもうちょっと使いこなせるようにしよう
  • アセンブラ使えるようにしよう
  • 素直にFPGA使おう
  • FPGA使えるようにしよう

*1:LCD関係の処理は省略