2015年10月22日

PIC12F1501でソフトウエアDDS

PIC12F1501でソフトウエアDDS

最近秋月電子で取り扱いを始めた8ピンのPICマイコン・PIC12F1501(70円)ですが、5bitのDAC機能を利用して ソフトウエアDDS(ダイレクト・デジタル・シンセシス) を作ってみました。
(同じ5bitのDAC機能があるPIC12F1822(100円)でも同様の動作が実装できます。)
なお、同様の機能はアナログ回路の方がより良い波形が得られますが、あくまでマイコン機能確認ということで。

【動作波形】
5bit(32段階)なので歪の多い正弦波です。
PIC12F1501でソフトウエアDDS

PIC12F1501でソフトウエアDDS

【回路】
 ボリュームで出力周波数を可変する仕様です。(~約1kHz)
PIC12F1501でソフトウエアDDS

【動画】
 ボリュームで周波数を可変させてオシロスコープで波形を見ている様子です。



【ソースコード】
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)

//───────────────────────────────────
// 定数定義
//───────────────────────────────────
// 基本になる出力波形の周波数(Hz)
#define BASE_FREQ   500

//───────────────────────────────────
// ユーザメモリ
//───────────────────────────────────
unsigned int Freq = 500;   // 出力周波数

//───────────────────────────────────
// 正弦波テーブル
//───────────────────────────────────
const unsigned char WaveTable[64] = {
    16,17,19,20,22,23,24,26,
    27,28,28,29,30,30,31,31,
    31,31,31,30,30,29,28,28,
    27,26,24,23,22,20,19,17,
    16,15,13,12,10,9,8,6,
    5,4,4,3,2,2,1,1,
    1,1,1,2,2,3,4,4,
    5,6,8,9,10,12,13,15
};

//───────────────────────────────────
// 初期化
//───────────────────────────────────
static void init(void)
{
    // Clock
    OSCCON = 0b01111010;     // Internal Osc 16MHz
    OPTION_REG = 0b00000000; // PSA=0  1/2分周 WPU許可

    // Port
    TRISA  = 0b00011000;
    PORTA  = 0b00000000;
    ANSELA = 0b00010000;     // AN3(RA4)使用
    WPUA   = 0b00001000;     // RA3(INPUT専用)のみWPU

    // DAC
    DACCON0 = 0b10010000;    // DAC許可 DACOE2出力

    // ADC
    ADCON1 = 0b10000000;     // ADC 結果右詰, FOSC/2, VREF+ to VDD
    ADCON0 = 0b00001101;     // AN3 選択

    // Timer2(32kHz)
    T2CON = 0b00000100;
    PR2 = 125;

    // Interrupt
    PEIE = 1;               // Peripheral Interrupt Enable
    TMR2IE = 1;             // Timer2 Interrupt Enable
    GIE = 1;
}

//───────────────────────────────────
// タイマ割込み処理
//───────────────────────────────────
static void interrupt isr( void )
{
    static unsigned int IdxOffset = 0;  // テーブルのオフセット
    static unsigned int PhCnt = 0;      // ブレゼンハム用作業変数

    if( TMR2IF )                        // TMR2オーバーフロー 31.25usec
    {
    TMR2IF = 0;                     // オーバーフローフラグクリア
       
        PhCnt += Freq;
        while( PhCnt >= BASE_FREQ)
        {
            PhCnt -= BASE_FREQ;
            IdxOffset ++;
            IdxOffset &= (sizeof(WaveTable)-1);
        }
        DACCON1 = WaveTable[IdxOffset];
    }
}

//───────────────────────────────────
// ADC処理(周波数可変)
//───────────────────────────────────
static void getAnData( void )
{
    unsigned int tmpAd;

    GO_nDONE = 1;           // スタート
    while( GO_nDONE );      // 終了待ち

    tmpAd = ADRESH;
    tmpAd <<= 8;
    tmpAd |= ADRESL;
    Freq = tmpAd;           // ~1024Hzとする
}

//───────────────────────────────────
// メイン処理
//───────────────────────────────────
int main(int argc, char** argv)
{
    static unsigned char cnt = 0;

    init();
    while(1)
    {
        if( ++cnt >= 100 )
        {
            cnt = 0;
            getAnData();
        }
    }
    return (EXIT_SUCCESS);
}


【その他】
 DACポートは出力ですが
 内部プルアップ抵抗(WPU)がOn
 の場合は電圧が正常に出ないようです。
 したがって該当ポートをWPUAレジスタで "0" にします。
 これはPIC12F1822でも同様です。

例としてノコギリ波を出力、WPUがOffの場合は正常な波形です。
PIC12F1501でソフトウエアDDS

同じ仕様でWPUがOnの場合は歪んだ波形となります。
PIC12F1501でソフトウエアDDS





同じカテゴリー(マイコン開発)の記事
Fusion PCBでエレキー
Fusion PCBでエレキー(2020-04-01 19:00)


上の画像に書かれている文字を入力して下さい
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。

削除
PIC12F1501でソフトウエアDDS
    コメント(0)