NCO機能を動作させて見ます
〔PICの動かせ方入門に戻る〕
12F1501のNCO(Numerically Controlled Oscillator module:数値制御オシレータ)機能は、
周波数発生器と思えば解りやすいでしょう。
動作概要
20ビットの加算器を持っていて、指定クロックの1サイクル毎にある数値で加算していきます。
ある数値とは16ビットのインクリメントレジスタで1〜65535で設定します。
例えば65535と指定していたら加算器は1サイクル毎に65535づつ足していきます、
で、20ビットなので、足し算をして行って1048575を超えたらオーバフローです。
(1048575/65535=16 16回足して17回目でオーバーフローします)
オーバーフローで0に戻り(ここでイベント発生)、また加算をして行くと言った感じで繰り返します。
以下が動作の概念図です。

クロックは、システムクロック(Fosc/HFINTOSC)にCLCの出力、外部ピン入力が利用出来る。
もちろん割込みイベントを有効にしておけばオーバーフロー時に割り込みが発生します。
NCOの出力は下記図の様に2つのモードが有ります、
ひとつはFDC MODE(固定デューティサイクル モード)でこれはデューティ比 50%です。
もう一つが PF MODE(パルス周波数モード)でこれはデューティ比が可変出来ます。
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での波形です
上記図の設定は
NCO1INCH = 65535 >> 8 ; // インクリメントレジスタ(上位バイト)初期化
NCO1INCL = 65535 & 0x00ff;// インクリメントレジスタ(下位バイト)初期化
NCO1CLK = 0b00000001 ; // CLCのクロックはFoscとする
NCO1CON = 0b11000000 ; // CLCは有効でピンに出力する、固定デューティサイクルモード
としています。
こんどの図はPF MODEでインクリメントレジスタ=65535での波形です
上記図の設定は
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の構成
ビット |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
機能 |
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の構成
ビット |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
機能 |
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.