簡易波形発生器の作製


注意!このページを読んだことによる如何なる損害に対しても筆者は責任を取りません。
参考にされる場合は全て自己責任で行ってください。


ロジック回路の実験をする時。アンプのテストをする時。

簡単な波形発生器が欲しい時は良くある。
手元にはデジットで買った大量の1%910Ωが。
そこで、tiny2313とR-2Rラダーで簡単な波形発生器を作ってみた。


◆設計仕様

3V〜5V程度での出力振幅の可変

正弦波・矩形波・その他の波形の選択

0.25〜1kHz程度での周波数可変


◆回路図
クリックで拡大


マイコンからパラレル8ビットで出力した数値をR-2RラダーでD/A変換したものをアンプで増幅する。
VR1で出力電圧を変化させる。
マイコンのISPソケットと5V電源用の7805は省略している。


◆配線




◆結果

オペアンプに単電源用のものを使用したが、グランド付近で少しクリップした。
オペアンプの電源に少しマイナスのバイアスをかければ解消すると思うが、私の実用には問題ないので改善はしていない。
※データの取り方がだめだめなのは仕様です。


正弦波 Vpp=5V 200Hz


正弦波 Vpp=5V 0.25Hz
いかにもデジタルな波形
オペアンプの負帰還に付いているCxである程度はなだらかになる。…かも。


ノコギリ波 Vpp=5V 200Hz


逆ノコギリ波 Vpp=5V 200Hz


矩形波 Vpp=5V 1.6kHz程度
これが限界のよう


今回は一波長を64分割したものを出力したことで2kHz弱の波形までしか出力できなかった。
分割量を更に大きくすれば出力波形は更に滑らかになるが、出力可能周波数は低くなる。
分割量を小さくするとその逆になる。
その兼ね合いを見て64分割にしたが、矩形波についてはHかLかのみなので10kHz程度までの波形なら簡単に出力できる。
また、他の波形についても最大16種類まで登録出来る。


◆波形選択

出力波形はマイコン横のDIP-SWによって設定する。
8ビットの入力があり、前半4ビットが波形選択・後半4ビットが周波数選択である。
DIP-SWはマイコンが上になるように見て、右端0bit目・左端が7bit目であり、上に押し上げるとH・下に押し下げるとLである。




bit7-4 波形
0000 正弦波
0001 矩形波
0010 ノコギリ波
0011 逆ノコギリ波
  
bit3-0 周波数[Hz]
0000 0.25
0001 0.5
0010 1
0011 10
0100 20
0101 50
0110 70
0111 100
1000 200
1001 500
1010 700
1011 1k


◆プログラム

一応プログラムファイルも置いておく:ladder2313.c
(右クリックで「名前を付けてリンク先を保存」)

/************************************************************
 
device:        tiny2313
clk:        8MHz
    
written by yosio @ chocolatespeaker
2010/1/9
 
*************************************************************/
 
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
 
#define WAVEFORM_SIN    0    //正弦波
#define WAVEFORM_PULSE    1    //矩形波
#define WAVEFORM_SAW    2    //ノコギリ波
#define WAVEFORM_SAW_R    3    //逆ノコギリ波
 
#define LED_FLIP    PIND|=0b01000000;
 
/*グローバル変数宣言*/
uint8_t cnt_wave=1;    //波形生成カウンタ
uint8_t wave[64]={0};    //波形データ
 
const uint8_t data_sin[] PROGMEM ={128,140,153,165,177,188,
                            199,209,218,226,234,240,
                            245,250,253,254,255};
                            
const uint16_t data_freq[] PROGMEM={62500,31250,15625,12500,
                                    6250,2500,1786,1250,625,
                                    250,179,125,50,25,18,13};
 
/*プロトタイプ宣言*/
uint8_t getSW(uint8_t *);
void changeWave(uint8_t);
uint8_t reversalBits(uint8_t);
 
/*カウンタ1の割り込み*/
ISR(TIMER1_COMPA_vect){
    PORTB = wave[cnt_wave];
    cnt_wave = (cnt_wave+1) & 0b00111111;        //カウント(64バイトで1周期)
}
 
//*************************
//メイン関数
//*************************
int main(void){
 
/*ローカル変数宣言*/
uint8_t sw_state_old=0;    //前回のスイッチの状態
 
/*入出力ポート設定*/
    PORTA = 0b00000011;//プルアップ
    PORTD = 0b01111111;
    PORTB = 0;
    
    DDRA = 0x00;    //入力
    DDRD = 0x00;    //入力
    DDRB = 0xff;    //出力
 
    DDRD |=(1<<PD6);
 
/*カウンタ1の設定*/
    TCCR1A=0;
    TCCR1B |= (1<<WGM12)|(1<<CS10);//CTC動作,分周なし
    TCCR1C=0;
    
    OCR1A=0x0fff;            //比較一致TOP値(後で再設定)
    
    TIMSK |= (1<<OCIE1A);    //割り込み許可
    
    getSW(&sw_state_old);
    changeWave(sw_state_old);
    
    sei();        //全割り込み許可
    
    for(;;){
        if(!cnt_wave){    //波形生成カウンタが0なら(1周期ごとに)
            if( getSW(&sw_state_old) ){    //SW入力変化があれば
                changeWave(sw_state_old);    //波形変更
            }
        }
    }
    
 
    return 0;
}
 
//*************************
//スイッチの読み込み
//引数        前回のスイッチの状態(ポインタ)
//戻り値    0:スイッチ変更なし
//            1:スイッチ変更あり
//*************************
uint8_t getSW(uint8_t *old_sw){
    uint8_t new_sw=(PIND<<2) | (PINA&0b00000011);
    if(*old_sw!=new_sw){
        *old_sw=new_sw;
        return 1;
    }
    return 0;
}
 
//*************************
//波形変更
//引数        スイッチの状態
//*************************
void changeWave(uint8_t sw_state){
    uint8_t frequency =0;
    uint8_t waveform  =0;
    uint8_t i=0;
    
    sw_state = ~sw_state;
    
    frequency = reversalBits(sw_state)&0x0f;
    waveform  = sw_state & 0x0f;
    
    
    if(frequency<=2){                                //1Hz以下なら
        TCCR1B = (TCCR1B & 0b11111000) | (1<<CS11);    //8分周
    }else{
        TCCR1B = (TCCR1B & 0b11111000) | (1<<CS10);    //分周無し
    }
    
    OCR1A=pgm_read_word(&data_freq[frequency]);        //TOP値設定
 
    switch(waveform){
        case WAVEFORM_SIN:
            for(i=0;i<17;i++)wave[i]=pgm_read_byte(&data_sin[i]);
            for(i=1;i<17;i++)wave[16+i]=wave[16-i];
            for(i=1;i<17;i++)wave[32+i]=256-wave[i];
            for(i=0;i<15;i++)wave[49+i]=wave[47-i];
            break;
        
        case WAVEFORM_PULSE:
            for(i=0;i<32;i++){
                wave[i]=0xff;
                wave[63-i]=0;
            }
            break;
            
        case WAVEFORM_SAW:
            for(i=0;i<64;i++)wave[i]=i*4;
            break;
            
        case WAVEFORM_SAW_R:
            for(i=0;i<64;i++)wave[63-i]=i*4;
            break;
            
    }
    
}
 
//*************************
//ビット逆順
//*************************
uint8_t reversalBits(uint8_t bits){
    bits=( bits         << 4) | ( bits         >> 4);
    bits=((bits & 0x33) << 2) | ((bits & 0xcc) >> 2);
    bits=((bits & 0x55) << 1) | ((bits & 0xaa) >> 1);
    return bits;
}





2010/1/8  作成

HOME /電子工作_TOP inserted by FC2 system