16F18325 Numerically Controlled Oscillator (NCO1)があり、このモジュールを使うと周波数をきめ細かく調整できる発振器を構成することができます。
NCOは、20bit長の主レジスター(NCO1ACC)と20bitの加算器から成り立っており、NCO1_clk 入力のたびごとに、一定の値(NCO1INC)が主レジスターに加算されます。加算される値が小さければ、加算結果でOverFlow発生に時間がかかり、大きければすぐにOverFlowが発生します。OverFlow発生の繰り返し周波数は、以下の式で表されます。
式23-1:NCO1の周波数
Freq. Overflow = | NCO1 Clock Freq. x Increment Value |
2^20 |
単純なカウンタ駆動タイマーに対する加算方法の利点は、出力周波数分解能が分周器の値によって変化しないことです。NCO1は、固定デューティサイクルで周波数精度と高分解能を必要とするアプリケーションに最も役立ちます。
NCO1の機能は次のとおりです。
*注意*
NCO出力は、PPS機能でピンを指定します。
NCO1INCL に書き込みを行うことで、NCO1INC のデータが INCBUF に転送されるため、NCO1INCU 及び NCO1INCH に値を書き込んだ後に NCO1INCL に値を書き込みます。
注1:インクリメントレジスタ(INCBUF)はダブルバッファリングされているため、NCO1モジュールを無効にせに値を変更することが可能です。また、INCBUFに直接アクセスすることはできません。
NCO1は、アキュムレータに固定値を繰り返し加算することで動作します。加算は入力クロックレートで発生します。アキュムレータは定期的にオーバーフローしキャリーが発生します。これが元となる NCO1出力(NCO_overflow)です。この原理で、加算値と最大アキュムレータ値に応じて入力クロックを効果的に式23-1に示す比率で分周することができます。
NCO1出力は、パルスを広げるか、フリップフロップをトリガし、内部の他のペリフェラルに分配され、さらに任意のピンに出力することができます。アキュムレータのオーバーフローの発生で割り込み((NCO_interrupt)を生成します。
NCO1で使用可能なクロックソースは次のとおりです。
NCO1クロックソースは、NCO1CLKレジスタのN1CKS <1:0>ビットによって選択されます。
アキュムレータは20ビットレジスタです。アキュムレータへの読み取りおよび書き込みアクセスは、次の3つのレジスタを介して利用できます。
NCO1加算器は全加算器であり、システムクロックとは独立して動作します。直前の結果とインクリメント値を加算すると、入力クロックの立ち上がりエッジでアキュムレータ値が置き換えられます。
20ビットのインクリメント値は、3つのレジスタに分けて格納されます。LSBからMSBの順に、次のとおりです。
NCO1モジュールを有効にする場合は、最初にNCO1INCUレジスタとNCO1INCHレジスタに値を書き込み、次にNCO1INCLレジスタに書き込む必要があります。NCO1INCLレジスタに書き込むと、インクリメントバッファレジスタにそれらデータが、NCO_clk信号の2番目の立ち上がりエッジで同時にロードされます。
レジスタは読み書きが可能です。インクリメントレジスタはダブルバッファリングされているため、NCO1モジュールを無効にすることなく値を変更できます。
NCO1モジュールが無効mp時は、インクリメントレジスタへの書き込み直後にデータはインクリメントバッファがロードされます。
注意:インクリメントバッファレジスタはユーザーはアクセスできません。
固定デューティサイクル(FDC)モードでは、アキュムレータがオーバーフローするたびに(NCO_overflow)、出力が反転します。これにより、加算値が一定なら、一定の周波数で50%のデューティサイクルが出力されます。
FDC周波数は、式23-2を使用して計算できます。1つのFDCクロック周期を生成するには2つのオーバーフローイベントが必要なため、FDC周波数はオーバーフロー周波数の半分です。
FDCモードは、NCO1CONレジスタのN1PFMビットをクリアすることで選択されます。
パルス周波数(PF)モードでは、アキュムレータがオーバーフローするたびに(NCO_overflow)、出力は1つ以上のクロック周期でアクティブになります。クロック周期が経過すると、出力は非アクティブ状態に戻ります。これにより、パルス出力が提供されます。出力は、オーバーフローイベントの直後のクロックの立ち上がりエッジでアクティブになります。詳細については、図23-2を参照してください。
アクティブ状態と非アクティブ状態の値は、NCO1CONレジスタの極性ビットN1POLによって決まります。
PFモードは、NCO1CONレジスタのN1PFMビットをセットすることによって選択されます。
PFモードで動作している場合、出力のアクティブ状態の幅は複数のクロック周期で可変することができます。NCO1CLKレジスタのN1PWS <2:0>ビットでパルス幅が選択されます。
選択したパルス幅がアキュムレータのオーバーフロー時間枠よりも大きい場合、NCO1の出力は切り替わりません。
NCO1モジュールの最後は出力極性です。NCO1CONレジスタのN1POLビットは出力極性を選択します。割り込みが有効なときに極性を変更すると、結果の出力遷移に割り込みが発生します。
NCO1出力は、ソースコードまたはその他の周辺機器によって内部的に使用できます。これを実現するには、NCO1CONレジスタのN1OUT(読み取り専用)ビットを読み取ります。
NCO1出力信号は、次の周辺機器で使用できます。
アキュムレータがオーバーフローすると(NCO_overflow)、PIR2レジスタのNCO1割り込みフラグビットNCO1IFがセットされます。割り込みイベント(NCO_interrupt)を有効にするには、次のビットを設定する必要があります。
割り込みは、割り込みサービスルーチンのNCO1IFビットをクリアすることで、ソフトウェアによってクリアする必要があります。
リセットの結果、すべてのNCO1レジスタがゼロにクリアされます。
NCO1モジュールは、システムクロックとは独立して動作し、選択したクロックソースがアクティブのままである限り、スリープ中も実行を継続します。
NCO1モジュールが有効で、選択されたシステムクロックソースに関係なく、HFINTOSCがクロックソースとして選択されている場合、スリープ中はHFINTOSCがアクティブのままになります。
つまり、HFINTOSCがシステムクロックとNCO1クロックソースとして同時に選択されている場合、NCO1が有効になっていると、CPUはスリープ中にアイドル状態になりますが、NCO1は動作を継続し、HFINTOSCはアクティブのままになります。
これは、スリープモード電流に直接影響します。
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
---|---|---|---|---|---|---|---|---|
INTCON | GIE | PEIE | - | - | - | - | - | INTEDG |
PIE2 | TMR6IE | C2IE | C1IE | NVMIE | SSP2IE | BLC2IE | TMR4IE | NCO1IE |
PIR2 | TMR6IF | C2IF | C1IF | NVMIF | SSP2IF | BLC2IF | TMR4IF | NCO1IF |
NCO1CON | N1EN | - | N1OUT | N1POL | - | - | - | N1PFM |
NCO1CLK | N1PWS <2:0> | - | - | - | N1CKS <1:0> | |||
NCO1ACCL | NCO1ACC <7:0> | |||||||
NCO1ACCH | NCO1ACC <15:8> | |||||||
NCO1ACCU | - | - | - | - | NCO1ACC <19:16> | |||
NCO1INCL | NCO1INC <7:0> | |||||||
NCO1INCH | NCO1INC <15:8> | |||||||
NCO1INCU | - | - | - | - | NCO1INC <19:16> | |||
RxyPPS | - | - | - | RxyTPPS <4:0> NCO1 は 29 : <11101> |
レジスタ | BIT | 名 | 説明 | 1 | 0 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
INTCON | 7 | GIE | 全インタラプトの使用許可 | 許可 | 否 | ||||||||||||||||
6 | PEIE | 周辺機能インタラプトの使用許可 | 許可 | 否 | |||||||||||||||||
PIE2 | 0 | NCO1IE | NCO1 インタラプトを使用許可 | 許可 | 否 | ||||||||||||||||
PIR2 | 0 | NCO1IF | NCO1 フラグ | 発生 | 未発生 | ||||||||||||||||
NCO1CON | 7 | N1EN | NCOモジュールのOn/Off | ON | OFF | ||||||||||||||||
5 | N1OUT | (Read Only)NCO1 出力 | 1 | 0 | |||||||||||||||||
4 | N1POL | NCO1 出力極性 | 不論理 | 正論理 | |||||||||||||||||
0 | N1PFM | NCO1 出力モード | Pulse | FDC | |||||||||||||||||
NCO1CLK | 7 | N1PWS2 | NCO1 Pulse Mode時の出力Pulse幅選択(x入力Clk)
|
||||||||||||||||||
6 | N1PWS1 | ||||||||||||||||||||
5 | N1PWS0 | ||||||||||||||||||||
1 | N1CKS1 | NCO1 Clock 選択
|
|||||||||||||||||||
0 | N1CKS0 |
NCOを利用した発振器プログラムを作成しました。VRで 0−488Hzの方形波形をNCOから出力します。
<回路図>
*注意*
XC-8のマクロを使用して、 NOC1INC = 0xAABBCC; とすると、
コンパイラーは、NOC1INCLに0xCC --> NOC1INCHに0xBB --> NOC1INCUに0xAA の順でレジスターに書き込みます。この順では、正しくINCBUFFにデーターを転送することができません。XC-8のマクロを使用せず、プログラム例のようにデータをNCO1INCに書き込む必要があります。
<回路図>
<プログラム>
/************************************* * File: NCO sample * System ClockはConfigで内部1MHzに設定 * RA2 (ANA2) の電圧をAD変換、 * 変換された10ビットをNOCINCにセット * VR値で、0−488HzのNCO出力反転を繰り返す * PIC16F18325 * Created on Sep 22, 2017, 2:37 PM **************************************/ #include <xc.h> #define _XTAL_FREQ 1000000 // delay_ms(x) のための定義 #pragma config FEXTOSC = OFF,RSTOSC = HFINT1 // HFINTOSC (1MHz) #pragma config CLKOUTEN = OFF,CSWEN = OFF,FCMEN = OFF #pragma config MCLRE = OFF,PWRTE = OFF,WDTE = OFF,LPBOREN = OFF #pragma config BOREN = OFF,BORV = LOW,PPS1WAY = OFF,STVREN = ON #pragma config DEBUG = OFF #pragma config WRT = OFF,LVP = OFF,CP = OFF,CPD = OFF void main(void) { LATC = 0; TRISC = 0b111110; // RC0を出力に設定 TRISA = 0b111111; // PortAを入力に設定 ANSELA = 0; // 全てのpinをデジタルに設定 ANSELC = 0; // ADC 設定 ************************************************ ANSA2 = 1; // ANA2(RA2)はアナログ入力に設定 ADACT = 0b00000000; // AD変換はプログラムの命令で開始 ADCON1 = 0b10000000; // 右詰め出力, AD変換クロックFosc/2 // 正基準電圧 VDD ADCON0 = 0b00001001; // アナログ入力 AN2(RA2),ADC ON // NCO 設定 ************************************************ NCO1CLK = 0b00000001; // Fosc (1 MHz)がクロック NCO1CON = 0b10000000; // 正論理、反転モード RC0PPS = 29; // RC0にNCO出力 while(1){ __delay_ms(5); // ADチャージ時間 GO = 1; // AD変換開始 while(GO); // AD変換終了待ち NCO1INCU = 0; // NCO1INCに結果セット NCO1INCH = 0; // NCO1INCL = ADRES; // } }