PIC16F18313の基本動作から応用プログラムまでを学びます。

ホーム
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
    
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
Numerically Controlled Oscillator (NCO)
2021-12-18

16F18313 Numerically Controlled Oscillator (NCO1)があり、このモジュールを使うと周波数をきめ細かく調整できる発振器を構成することができます。
NCOは、20bit長の主レジスター(NCO1ACC)と20bitの加算器から成り立っており、NCO1_clk 入力のたびごとに、一定の値(NCO1INC)が主レジスターに加算されます。加算される値が小さければ、加算結果でOverFlow発生に時間がかかり、大きければすぐにOverFlowが発生します。OverFlow発生の繰り返し周波数は、以下の式で表されます。

Freq. Overflow = NCO1 Clock Freq. x Increment Value
2^20

NCOに関連するレジスター一覧を下表に示します。

*注意*
NCO出力は、PPS機能でピンを指定します。
NCO1INCL に書き込みを行うことで、NCO1INC のデータが INCBUF に転送されるため、NCO1INCU 及び NCO1INCH に値を書き込んだ後に NCO1INCL に値を書き込みます。

レジスタ 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)
000 = 1, 001 = 2, 010 = 4, 011 = 8,
100 = 16, 101 = 32, 110 = 64, 111 = 128,
6 N1PWS1
5 N1PWS0
1 N1CKS1 NCO1 Clock 選択
00 = HFINTOSC (16 MHz),01 = FOSC,10 = CLC1OUT
0 N1CKS0

NCOのプログラム例

NCOを利用した発振器プログラムを作成しました。SWを押す毎に、ドレミ・・・の方形波形をNCOから出力します。

<回路図>

<プログラム>

 /*************************************
  * File: NCO sample
  * System ClockはConfigで内部1MHzに設定
  * NCO を RA2 に出力
  * PIC16F18313
  * Created on 2021-12-18
  **************************************/

 #include <xc.h>
 #define _XTAL_FREQ 1000000      // delay_ms(x) のための定義
 #define SW  RA5                 // Push SW
 #define LED LAUA4               // LED

 // 音の高さを決める定数
  const int inc_tbl[] = {
 //    Do,    Re,   Mi,   Fa,   So,   Ra,  Si,   Do
     0x225,0x268,0x2B3,0x2DC,0x336,0x39B,0x40C,0x449
  };

 #pragma config FEXTOSC = OFF,RSTOSC = HFINT1  // HFINTOSC (1MHz)
 #pragma config CLKOUTEN = OFF,CSWEN = OFF,FCMEN = OFF
 #pragma config MCLRE = ON,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 = ON,CP = OFF,CPD = OFF

 void main(void) {
     char idx = 0;
     LATA   = 0;
     TRISA  = 0b101011;          // PortA5を入力に設定
     ANSELA = 0;                 // 全てのpinをデジタルに設定
     WPUA   = 0b111111;          // PortA入力に弱プルアップ

     // NCO 設定 ****************************************
     NCO1CLK = 0b00000001;       // Fosc (1 MHz)がクロック
     RA2PPS  = 29;               // RA2にNCO出力

     while(1){
         NCO1CON = 0b10000000;               // NCO ON FDCモード
         for(char i = 0;i < 8;i++){          // オクターブ(8回)繰り返し
             NCO1INCH = inc_tbl[i] >> 8;     //  音階データをセット
             NCO1INCL = inc_tbl[i] & 0xFF;   //  音階データをセット
             __delay_ms(500);                // 500ms演奏
         }
         NCO1CON = 0;                        // NCO OFF
         while(SW);                          // SWが押されるのを待つ
     }
 }