NCO機能を動作させて見ます

〔PICの動かせ方入門に戻る〕


12F1501のNCO(Numerically Controlled Oscillator module:数値制御オシレータ)機能は、
周波数発生器と思えば解りやすいでしょう。

動作概要

20ビットの加算器を持っていて、指定クロックの1サイクル毎にある数値で加算していきます。
ある数値とは16ビットのインクリメントレジスタで1〜65535で設定します。
例えば65535と指定していたら加算器は1サイクル毎に65535づつ足していきます、
で、20ビットなので、足し算をして行って1048575を超えたらオーバフローです。
(1048575/65535=16 16回足して17回目でオーバーフローします)
オーバーフローで0に戻り(ここでイベント発生)、また加算をして行くと言った感じで繰り返します。
以下が動作の概念図です。

動作概要1
クロックは、システムクロック(Fosc/HFINTOSC)にCLCの出力、外部ピン入力が利用出来る。
もちろん割込みイベントを有効にしておけばオーバーフロー時に割り込みが発生します。


NCOの出力は下記図の様に2つのモードが有ります、
ひとつはFDC MODE(固定デューティサイクル モード)でこれはデューティ比 50%です。
もう一つが PF MODE(パルス周波数モード)でこれはデューティ比が可変出来ます。

動作概要2

Fosc=8MHz インクリメントレジスタ=65535 FDC MODE での周波数は?

8MHzの1サイクルは?       1000000us / 8000000Hz = 0.125us(125ns)
オーバーフローは何回で発生?  1048575 / 65535 = 16回
オーバーフローの発生時間は?  125ns x 16 = 2000ns(2us)
FDC MODEなので1サイクルは?  2us * 2 = 4us ;
周波数は?               1000000us/4us=250000Hz(250KHz)
8MHzでの最高発生周波数は250KHz、PF MODE なら500KHzですね。(下の方波形図参照)
実際にテスターで周波数を計測したら 249.0KHz でした、精度の良い外部システムクロックに
すれば良いかもね
ちなみに、インクリメントレジスタ=1とすると最低発生周波数となるので、自分で計算してみて。

周波数 10KHzを発生させるならインクリメントレジスタの値は?

10KHzの1サイクルは?       1000000us / 10000Hz = 100us
FDC MODEなので 100us / 2 = 50us(50000ns) 毎にオーバーフローさせる。
オーバーフローの発生回数は?   50000ns / 125ns = 400回 (Fosc=8MHz)
インクリメントレジスタの値は?    1048575 / (400-1) = 2628.0075 なので 2628を設定する

《PIC12F1501ピン構成》

ピン構成図

NCOの出力するピンは、NCO1が2番と6番ピンの何方からか出力出来ますが、
今回は6番(RA1)ピンからの出力で設定しています。
また、2番(RA5)ピンのNCO1CLKは外部クロックを入力できます。
尚、PICの1番ピンに電源+5V、8番ピンに電源GND(-)を接続しています。

《サンプルプログラム》

NCOのクロックはFoscから入力してFDC MODEで10KHzを出力する様に設定しています。
尚、PICのシステムクロック(Fosc)は内蔵8MHzで行っています。

下記がプログラムソースです、
MPLAB X(v2.15)MPLAB(R) XC8 C Compiler Version 1.32コンパイラを使用しています。
 プロジェクトを作成して新規ファイルにコピーペーストして貼り付けて下さい。 *2)
---------------------------------------------------------------------
#include <xc.h>

// コンフィギュレーション1の設定
#pragma config FOSC     = INTOSC   // 内部クロック使用する(INTOSC)
#pragma config WDTE     = OFF      // ウオッチドッグタイマー無し(OFF)
#pragma config PWRTE    = ON       // 電源ONから64ms後にプログラムを開始する(ON)
#pragma config MCLRE    = OFF      // 外部リセット信号は使用せずにデジタル入力(RA3)ピンとする(OFF)
#pragma config CP       = OFF      // プログラムメモリーを保護しない(OFF)
#pragma config BOREN    = ON       // 電源電圧降下常時監視機能ON(ON)
#pragma config CLKOUTEN = OFF      // CLKOUTピンをRA4ピンで使用する(OFF)

// コンフィギュレーション2の設定
#pragma config LPBOR  = OFF        // 低消費電力ブラウンアウトリセット(OFF)
#pragma config WRT    = OFF        // Flashメモリーを保護しない(OFF)
#pragma config STVREN = ON         // スタックがオーバフローやアンダーフローしたらリセットをする(ON)
#pragma config BORV   = HI         // 電源電圧降下常時監視電圧(2.5V)設定(HI)
#pragma config LVP    = OFF        // 低電圧プログラミング機能使用しない(OFF)

// メインの処理
void main()
{
     OSCCON = 0b01110000 ;    // 内部クロックは8MHzとする
     ANSELA = 0b00000000 ;    // アナログは使用しない(すべてデジタルI/Oに割当てる)
     TRISA  = 0b00000000 ;    // ピンは全て出力に割当てる(RA3は入力専用)
     PORTA  = 0b00000000 ;    // 出力ピンの初期化(全てLOWにする)

     // NCOの設定
     NCO1SEL  = 0 ;           // 0:RA1から出力 1:RA5から出力
     NCO1ACCL = 0 ;           // アキュムレータレジスタ(下位バイト)初期化
     NCO1ACCH = 0 ;           // アキュムレータレジスタ(上位バイト)初期化
     NCO1ACCU = 0 ;           // アキュムレータレジスタ(最上位バイト:bit3-0)初期化
     NCO1INCH = 2628 >> 8 ;   // インクリメントレジスタ(上位バイト)初期化(10KHz出力)
     NCO1INCL = 2628 & 0x00ff;// インクリメントレジスタ(下位バイト)初期化
     NCO1CLK  = 0b00000001 ;  // CLCのクロックはFoscとする
     NCO1CON  = 0b11000000 ;  // CLCは有効でピンに出力する、固定デューティサイクルモード(FDC)

     while(1) {
     }
}
---------------------------------------------------------------------

実行結果

このプログラム自体は設定のみなので、LED表示などの外部出力はないので何も変化は
無いですが、NCO1(RA1)からは10KHzの信号が出力されています。
LEDを取り付ければ点灯するので解りやすいでしょう、
尚、テスターで周波数を計測したら9.993KHzと表示されました。

インクリメントレジスタに値を設定する場合はNCO1INCHから先にセットします、
NCO1INCLをセットしたらバッファに取り込まれるらしいのでぇ。

《PF MODE》  *1)

ロジックアナライザで内蔵システムクロックとNCO出力を表示させて見ます、
内蔵システムクロックを外部ピンに出すにはCLKOUT(RA4)に出力出来ますが、
システムクロックの4分の1(8MHz/4=2MHz)でしか出力出来ない所に注意して下さい。
(だからぁ、赤色波形の1サイクルは、8MHzの4サイクル分と数えて下さいね)

この図はFDC MODEでインクリメントレジスタ=65535での波形です
FDC_MODE波形

 上記図の設定は
     NCO1INCH = 65535 >> 8 ;   // インクリメントレジスタ(上位バイト)初期化
     NCO1INCL = 65535 & 0x00ff;// インクリメントレジスタ(下位バイト)初期化
     NCO1CLK  = 0b00000001 ;   // CLCのクロックはFoscとする
     NCO1CON  = 0b11000000 ;   // CLCは有効でピンに出力する、固定デューティサイクルモード
 としています。

こんどの図はPF MODEでインクリメントレジスタ=65535での波形です
PF_MODE波形

 上記図の設定は
     NCO1INCH = 65535 >> 8 ;   // インクリメントレジスタ(上位バイト)初期化(10KHz出力)
     NCO1INCL = 65535 & 0x00ff;// インクリメントレジスタ(下位バイト)初期化(2628)
     NCO1CLK  = 0b01100001 ;   // CLCのクロックはFoscとし、出力パルスの幅は8周期分
     NCO1CON  = 0b11000001 ;   // CLCは有効でピンに出力する、パルス周波数モード
 としています。
 ですので、FDC MODEの半分(倍の周波数)でON/OFFしているのが判ると思います。
 もちろん出力パルスの幅(N1PWSビット)を4周期分と設定すると、ONが4サイクル分(500ns)で
 OFFが12サイクル分(1500ns)となりますよね。
 ちなみに、この設定内容では出力パルスの幅は16周期までの設定しか出来ないと言う事になります。

《レジスタの設定》

NCOにて出力するピンを決めるには
 NCO1SEL = 1 ;  // 0:6番(RA1)ピンを使用する 1:2番(RA5)ピンを使用する
 もちろんANSEL/TRISにて使用するピンはデジタル出力に設定します。

NCO1CONの構成
ビット
機能 N1EN N1OE N1OUT N1POL N1PFM

Bit 7:N1EN   NCOモジュールの有効無効指定ビット
           1:モジュールを使用する
           0:モジュールを使用しない

Bit 6:N1OE   NCOピンの出力有無を指定するビット
           1:出力指定ピンはNCOで使用する
           0:出力指定ピンはNCOで使用しない

Bit 5:N1OUT  N1OUTの極性を指定するビット
           1:HIGHで出力する
           0:LOWで出力する

Bit 4:N1POL  NCO出力極性ビット
           1:出力は極性を反転する(アクティブ HIGH)
           0:出力は通常の極性である(アクティブ LOW)

Bit 0:N1PFM  出力モードの選択ビット
           1:パルス周波数モードで動作させる(PF MODE)
           0:固定デューティサイクル モードで動作させる(FDC MODE)

NCO1CLKの構成
ビット
機能 N1PWS N1CKS

Bit 7-5:N1PWS   PF MODE 時の出力パルス幅選択ビットト
              111:クロック128周期
              110:クロック64周期
              101:クロック32周期
              100:クロック16周期
              011:クロック8周期
              010:クロック4周期
              001:クロック2周期
              000:クロック1周期
              パルス幅がオーバーフロー周期よりも長い場合、動作は未定義の状態です。

Bit 1-0:N1CKS   クロック源選択ビット
              11:NCO1CLK(外部ピン)
              10:LC1OUT(CLCからの出力)
              01:FOSC
              00:HFINTOSC (16 MHz)

アキュムレータ レジスタの構成
 アキュムレータレジスタは20ビットで加算用です、通常は何もしないレジスタです。
 NCO1ACCL:NCO1 アキュムレータ レジスタ - 下位バイト(0-7bit :NCO1ACC[ 7: 0])
 NCO1ACCH:NCO1 アキュムレータ レジスタ - 上位バイト(0-7bit :NCO1ACC[15: 8])
 NCO1ACCU:NCO1 アキュムレータ レジスタ - 最上位バイト(0-3bit:NCO1ACC[19:16])

インクリメント レジスタの構成
インクリメントレジスタは16ビットです。
NCO1INCL: NCO1 インクリメント レジスタ - 下位バイト(NCO1INC[ 7: 0])
NCO1INCH: NCO1 インクリメント レジスタ - 上位バイト(NCO1INC[15: 8])
このレジスタの初期値は0x01です、1〜65535の範囲でセットします。

《その他》

LEDではなく圧電スピーカを取り付ければメロディを鳴らす事が出来るでしょう。
前にこちらの記事ではデジタル出力ピンをON/OFFさせて鳴らせましたがNCO機能を利用すれば
もっとスマートなプログラムが書けるでしょう。
尚、音階の周波数はTOM's Web Siteさんこちらを参考にして見て下さい。 *3)



リンク切れ見直し(*3) 2020/03/22
MPLAB X用に記事変更(*2) 2015/10/02
追記(*1) 2014/05/16


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2020 Shigehiro Kimura All Rights Reserved.