PICでパルス(矩形波)を発生させてみる

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


 今までにMyHPでもパルス(矩形波)を発生させた記事は書いていますが、PICでパルス(矩形波)を
発生させる手段は色々有りますのでここらでまとめた記事を書いて置こうと思います。

それとぉ、どの手段が精度の良いパルスが生成出来るのかも見て置きたいのですがぁ....
ならってんで水晶振動子を外付けしたい所ですが適当な手持ちがないのでこの話はまた後回しにします。
取り合えずは内蔵振動子で行います。
使うPICは16F18313ですこれは、Timer0が16bitと言う事とNCOモジュールが有り丁度良さげです。

※ 秋月通商のこちらの水晶発振器8MHz(±100x10-6)を使って少し追記して置きました。 *1)

《サンプルプログラムについて》

↓ここから実験で使用したサンプルプログラムファイルをダウンロード出来ます。
Pulse.zip
MPLAB X IDE v4.10
MPLAB(R) XC8 C Compiler Version 1.40

ダウンロードファイルを解凍すると下記の様なファイル構成です。
 CLKOUT32MHz.c・・・・・・・・・・・ CLKOUT(RA4)ピンからのFosc/4クロックを出力するサンプル
 Delay32MHz.c・・・・・・・・・・・・・・ プログラム(delay)でRA4ピンを10us毎にON/OFFさせるサンプル
 Timer1OUT.c・・・・・・・・・・・・・・・ Timer1を使いRA4ピンから矩形波を発生させるサンプル
 Timer1OUTRE.c・・・・・・・・・・・・ Timer1を使いRA4ピンから矩形波を発生させるサンプル2(改良版)
 PWMOUT.c・・・・・・・・・・・・・・・・・ PWM(CCP1)でRA4ピンから矩形波を発生させるサンプル
 Timer0OUT.c・・・・・・・・・・・・・・・ Timer0を使いRA4ピンから矩形波を発生させるサンプル
 CompareOUT.c・・・・・・・・・・・・・ コンペア機能(CCP1)を使いRA4ピンから矩形波を発生させるサンプル
 NCOOUT.c・・・・・・・・・・・・・・・・・・ NCO機能でRA4ピンから矩形波を発生させるサンプル

プログラムは全てRA4ピンからのパルス出力で設定していますが、測定しただけなので接続部品は無しです

《CLKOUT》

 周辺モジュールやタイマー等、システムクロックが基準なのでどの程度の精度か見てみます。
CLKOUTはどのPICにも有る機能で、ピンからシステムクロックのFosc/4が出力出来るものです。
通常はデジタルピンに割り当てられているので、コンフィギュレーションビットで有効にするだけで
該当ピンから出力されます、PIC16F18313はRA4ピンとなります。

Fosc=32MHzなのでCLKOUT出力は8MHz
CLKOUT32MHz図
6.25MHzが約8サイクルに1回程現れている、テスターでは7.998MHz程でした。
CLKOUT32MHz図(水晶発振器)
水晶発振器は8MHzなのでPIC内部で4xPLLを通して32MHzとなっていますがぁ...
なんだかぁ、変わりませんねテスターでは7.999MHzでした。 *1)

Fosc=8MHzなのでCLKOUT出力は2MHz
CLKOUT8MHz図
テスターでは2.002MHz程でした。
CLKOUT8MHz図(水晶発振器)
水晶発振器は8MHzそのままです、テスターでは1.999MHzでした。
PIC内部の4xPLLを通さない方が良いのかしらぁ? *1)

Fosc=4MHzなのでCLKOUT出力は1MHz
CLKOUT4MHz図
961.538KHzが約20サイクルに1回程現れている、テスターでは999.7KHz程でした。
パルス一つ一つなら意外とキッチリ出ている様な気もしますがぁ....

ここで使用したプログラムは"CLKOUT32MHz.c"を参考にして下さい。
#pragma config CLKOUTEN = ON       // CLKOUT(RA4)ピンからFoc/4クロックを出力する(ON)
とコンフィギュレーションを設定したら、RA4ピンは出力に設定するだけです。
(但し、この設定は16F18313でのやり方で、他のPICの場合は記述方法が異なります)

他のPIC(12F/16F/18F)でも行ったが皆同じ様な波形でした。
因みに、内部クロックの精度は±2% となっているわりには良さげぇ―。
うぅん、外部水晶振動子を付けて見たくなって来たぞぉ!!

尚、データシートの”オシレータのパラメータ表”項に下記の様に記載が有ります。
これらのオシレータ周波数の許容誤差を確保するには、デバイスのなるべく近くでVDD とVSS に
 デカップリングコンデンサを接続する必要が有ります。0.1uF のコンデンサと0.01uF のコンデンサを
 並列に接続する事を推奨します。


CLKRモジュールについて *3)

PIC16F178x系のPICには、CLKOUTとは別に"CLKR(REFERENCE CLOCK MODULE)"が有ります。
これはCLKOUTの様にシステムクロックを分周して出力してくれる機能です。
CLKOUTは外部のHSオシレーターモードではOSC2ピンとして使用する為に出力出来ませんでしたが、
CLKRは"CLKR"ピン(RB2)が別に有るので、全てのオシレーターモードで出力可能です。

デューティ比は、0%/25%/50%/75% から選択出来ます。
分周比は、1:1/1:2/1:4/1:8/1:16/1:32/1:64/1:128 から選択出来ます。
又、スルーレート制限の有効/無効も選択出来ます。

《delayで出力》

 プログラムの"__delay_us( )"を使ってRA4ピンをON/OFFさせて見ます。
前に"__delay_us( )"の話は、こちらで記事にした様にコンパイル時に"__delay_us( )"はアセンブラの
命令サイクルに変換されますので、指定した時間が正確に作られます。
ですがぁ、その他の処理部分(緑色プログラム部分)が有るのでその分時間(us)が余計に掛かります、
その辺りを見てみたいと思います。
     while(1) {
          LATA4 = 1 ;
          __delay_us(10) ;
          LATA4 = 0 ;
          __delay_us(10) ; 
     }
これを実行させますが、1周期は20usなので50KHzと計算上はなりますがぁ....

32MHzで動作

時間表示の波形
Delay32MHz図(時間)
他の処理部分で"1us"程余計に掛かっていますね。

周波数表示の波形
Delay32MHz図(周波数)
これをテスターで測ると48.46KHzでした。

なのでぇ、調整してみる。
     while(1) {
          LATA4 = 1 ;
          __delay_us(9) ; // ここを1us減らして調整してみる
          LATA4 = 0 ;
          __delay_us(10) ;
     }
でぇ、テスターで測るとぉ50.82KHzでした。

8MHzで動作

時間表示の波形
Delay8MHz図(時間)
やはり他の処理部分で更に余計に掛かっていますね。

周波数表示の波形
Delay8MHz図(周波数)
これをテスターで測ると43.63KHzでした。

なのでぇ、調整してみる。
     while(1) {
          LATA4 = 1 ;
          __delay_us(9) ; // 1us減らす
          LATA4 = 0 ;
          __delay_us(8) ; // 2us減らす
     }
でぇ、テスターで測ると50.12KHzでした。

32MHzで__delay_us(10)の記述を__delay_ms(500)にして行って見た

Delay32MHz図(500ms)
んん、予想と違うなぁ"指定した時間が正確"と書いたがぁ、んん?、
テスター計測は1.005Hzでした、意外と良さげぇだがぁ....
とにかく"指定時間を調整しろ!"って事でぇ纏めて置きます。
それとぉ、"delay"でパルスを作る場合は、システムクロックを早くしろって事ですわ。

12F/16F系で32MHzなら、__delay_ms(6307)まで設定できるがそれ以上を望む人は、
void Wait(int num)
{
     // numで指定した回数だけ繰り返す
     do {
          __delay_ms(10) ;    // 10msプログラムの一時停止
     } while(--num > 0);
}
と言った関数を作りましょう、無論処理部分が有るので正確には刻めないですがぁ.....
まあ、最もぉ、Delayを使う場合はプログラムを一旦遅延させるのが目的なのでぇアバウトで良いのです

ここで使用したプログラムは"Delay32MHz.c"を参考にして下さい。
まあ、改めて記事にしなくても解り切った事やぁと言われそうな記事ですね。

《タイマー1で出力》

 通常PICはTimer0(8bit)/Timer1(16bit)/Timer2(8bit)の3種類が有ります、PICによっては更に
Timer1/3/5(16bit)にTimer2/4/6(8bit)とたくさん有ります。
でぇ、タイマーは指定した値までカウントを行い割り込みを発生させます、
でぇ、1カウント当たりの時間を設定出来ますが、 ここでは1us(Fosc=32MHz)で行います
例えば1usで1000回カウントさせれば1ms毎に割り込み発生って感じですね。
ですがぁ、割り込み発生時に、1000回又カウントする様に再設定をしないとダメなのでぇ
ここら辺がプログラム記述による遅延が発生します
     // タイマー1用の割込み処理
     if (TMR1IF == 1) {            // タイマー1の割込み発生か?
          TMR1H = (T1count >> 8) ; // タイマー1の再設定
          TMR1L = (T1count & 0x00ff) ;
          LATA4=~PORTAbits.RA4 ;   // RA4ピンをON/OFF出力する(これでパルスを作る)
          TMR1IF = 0 ;             // タイマー1割込フラグをリセット
     }
こんな感じです。

1000Hzを発生

時間表示の波形
Timer1図(時間)
500usの山や谷なら良いのですがぁ、"510us"と10us程余分に掛かっていますね。

周波数表示の波形
Timer1図(周波数)

なら10us程調整してみる、上は500us毎に割り込み発生でした。
491us(1020Hz)として表示させた波形です。
Timer1図(調整波形)
お、なかなか良い感じみたいなぁ。

Fosc=32MHz タイマークロック=Fosc/4(8MHz)
プリスケーラ
1:1
1:2
1:4
1:8
1カウント
125ns
250ns
500ns
1us
65536カウント
8.192ms
16.384ms
32.768ms
65.536ms
タイマークロックをFosc(32MHz)に設定すると最低カウントは"31ns"となる。
Fosc=4MHzでFosc/4のタイマークロックで1:8にすれば最高カウントは"524.288ms"

今回の設定(32MHz/4の1:8)で1us(500KHz)〜65.536ms(8Hz程)となるが、チョットやって見る。

8Hzの周波数表示波形
Timer1図(8Hz周波数)
まぁ、いい感じ

8Hzの時間表示波形
Timer1図(8Hz時間)
1000000us(1秒)/8Hz=125000us(125ms)だよねー

500KHzの時間表示波形(周波数表示では44.444KHzと表示されている) Timer1図(500KHz時間)
1000000/500000Hz=2usなので1サイクル2usだがぁ、
でもぉ22us、上で10us程余分に掛かっていると書いたよねー
って事は割り込み発生時の処理が10us余計に掛かるのでぇこれ以上の周波数発生は無理って事やね。
8Hz〜40KHz辺りでぇ、10us(Fosc=32MHz時)を考慮しましょうって事でぇ。

上で記載の"タイマー1用の割込み処理"が、本当に"10us"処理が掛かっているのか?
チョットぉMPLAB X IDEシミュレーターのストップウォッチ機能で測定して見たら[9.875us]でした。
なるほどーぉ (゚∀゚;)

ここで使用したプログラムは"Timer1OUT.c"を参考にして下さい。
Timer1の詳しい設定方法等は、”PICの動かせ方入門”ページ内の各PIC覚書を参照下さい。

《PWMで出力》

 多くのPICにはPWMを出力するモジュールが有ります、16F18313にもCCP1/CCP2とPWM5/PWM6の
4個が有ります。ここでは、CCP1のPWM機能から矩形波を発生させて見ます。
PWMを出力するモジュールのタイマーはTimer2(8bit)が使われますが、"T2CONレジスタ"の
ポストスケーラは使用出来ません。(尚、PICによってはTimer2/4/6から選択出来ます。)

PWMは設定を行えば、後はPIC内部のハードウェアがやってくれるのでそこそこ精度は出ると思います。
今回はFosc32MHz設定で、500Hz〜2MHz程まで出力可能です、16F18313の"T2CONレジスタ"は
プリスケーラ値が1:1/1:4/1:16/1:64と有るので500Hzまで行けますが、他のPICでは1:64が無い物が
存在します、この場合は2000Hzまでとなります。


PIC12(16)F161x系のプリスケーラ値は"1:128"まで有ります、なのでぇ、250Hzまで行けます。*2)

500Hzを発生

周波数表示の波形
PWM500Hz図(周波数)
"555.556Hz"のボケは25サイクルに1回程の頻度で現れます。
テスターで測ると、"502.5Hz"でした。
外付け水晶振動子ならボケも消えるかしらぁ?
PWM500Hz図(周波数/水晶発振器)
水晶発振器8MHzそのままで(4xPLL通さない)でおこなったら、ボケ消えましたね。
テスターで測ったら、"499.9Hz"でした。精度出ますね!! *1)

時間表示の波形
PWM500Hz図(時間)
んん、なかなかやね

2MHzを発生

周波数表示の波形
PWM2MHz図(周波数)
おほ、すてきだぁ
テスターで測ると、"2.010MHz"でした。
水晶発振器8MHzでの出力波形をテスターで測ると、"1.999MHz"でした。 *1)

時間表示の波形
PWM2MHz図(時間)
わんだほー

2MHzを超えるとぉ

2.5MHzの波形
PWM2.5MHz図(周波数)
ぐぅ、(/ω\)イヤン

3MHzの波形
PWM3MHz図(周波数)
ヽ( ̄ー ̄ )ノ

って事でぇ、Fosc32MHzなら500Hz(2000Hz)〜2MHz位までなら良い精度で矩形波が出せそうですね
因みにFosc4MHzなら65Hz、Fosc2MHzなら31Hz、Fosc1MHzなら16Hzとなる。(プリスケーラ1:64)
私の希望は8MHz以上で、30Hz位までは出力して欲しいぞぉ―。

ここで使用したプログラムは"PWMOUT.c"を参考にして下さい。
CCP(PWM)の詳しい設定方法等は、”PICの動かせ方入門”ページ内の各PIC覚書を参照下さい。

PSMCモジュールについて *4)

PIC16F178x系のPICにはPSMC(プログラマブル スイッチング モード コントローラ)モジュールが
有ります、これは高性能の16ビットPWM生成器で、モジュールのクロックソースは外部ピン、Fosc、
PSMC専用64MHz(システムクロックとは別に駆動される)から選べます。
まあ、従来の8ビットPWMのECCPやCWG/COG機能と同等以上な物と思って下さい。

PSMCクロック=16MHz(Fosc)/8 で最低35Hz辺りから、PSMCクロック=64MHz(専用)/1 なら
最高8MHz位まで生成出来そうです。

クロックは64MHzでプリスケーラ1:1なので、1カウントは15.625nsです。
8MHzの1周期は125ns、125/15.625ns=8、8-1=7カウントさせた波形です。
PSMCでの8MHz波形図
高い周波数になるとカウント値が少なくなるので調整は無理ですね。
因みにテスター測定値は7.989MHzと表示されました。

この機能に付いての記事はこちらを参照下さい。

《タイマー0で出力》

 PWMでもシステムクロックを2MHzまで落とせば50Hzとか出力しそうですがぁ....
色々他の仕事をPICにさせる場合は、2MHzまで落としたくないぞぉと....
でぇ、16F18313のTimer0なんですがぁ、16bitになっていてプリスケーラ値が1:32767まで設定出来、
なんとぉ、ポストスケーラ値も設定可能と素晴らしい高性能なのですよ。
これはもぉおそらく相当長い時間が設定出来そうなのでチョットやって見ます。
(尚、タイマーは16ビットでのカウントで行います)

Fosc=32MHz タイマークロック=Fosc/4(8MHz) ポストスケーラ=1:1
プリスケーラ
1:1
1:8
1:32768
1カウント
125ns
1us
4.096ms
655635カウント
8.191875ms
65.535ms
268.43136s
ポストスケーラ1:16で設定したら
131.07ms
1.04856s
4294.90176s(71 分)
プリスケーラが1:8までならTimer1と同じ最長"65.535ms"で、
プリスケーラを1:32768に設定したら最長"268.43136s"となります、
でぇ、ポストスケーラ1:16としたら、なんとぉ驚きの"4294.90176s(約71分)"ですよぉ。 w(*゚o゚*)w

では、どの設定にしたらピッタリ時間が出来るのか見てみる

1ms
10ms
100ms
500ms
1s
60.000256s
180s(179.99872s)
600s(604s)
3600s(3758s)
プレスケーラ
1:64
1:8
1:32
1:128
1:512
1:8192
1:32768
1:8192
1:32767
ポストスケーラ 1:1
1:1
1:1
1:1
1:1
1:1
1:1
1:10
1:15
TMR0H
0xFF
0xD8
0x9E
0x85
0xC2
0x1B
0x54


TMR0L
0x83
0xF0
0x58
0xEE
0xF7
0x1E
0x57


ポストスケーラが1:1であれば"268s"位までなら作れそうだが、1:1以外に設定を行うともう何だかぁ
上手く作れない!、これってぇ〜、ポストスケーラってぇ〜、"おまけ"なのかしらぁ♪
"おまけ"じゃないのなら―、強引に調整するわぁ〜、ゴ―イン、ゴ―イン♪♪ やでぇ〜〜

上の表から10ms(50Hz)を作ってみた

Timer0図(時間表示:10ms)
結構いいぞぉ、あれ!、んん、10us程加わるのでは?

     // タイマー0用の割込み処理
     if (TMR0IF == 1) {            // タイマー0の割込み発生か?
          TMR0H = TIMER0H ;        // タイマー0の再初期化
          TMR0L = TIMER0L ;
          LATA4=~PORTAbits.RA4 ;   // RA4ピンをON/OFF出力する
          TMR0IF = 0 ;             // タイマー0割込フラグをリセット
     }
あ、そうかぁ、Timer1時の割り込み処理よりもこちらの方が簡略化されています
なら、シミュレータで見てみる、[1.75us]おお、いいじゃないかぁ。
上記で記載の"Timer1"の割り込み処理をこの様に書き換えればいいんじゃな〜い。
(下の方に"Timer1"の割り込み処理を改良した記事を追記して置きました。)

※ Timer2(8bit)の場合は、タイマ−カウンターの再設定は必要無いので[1.25us]となりました。
  PWM等はTimer2で割り込みも必要無いからどおりで精度が出るはずですわ。

1秒毎も作ってみた

Timer0図(時間表示:1秒)
上の表からタイマ−カウンター値は"0xC2F7"だがぁ

調整してみた、タイマ−カウンター値は"0xC28C"
Timer0図(時間表示:1秒調整)
良くなったがぁ...、やっぱり調整必要
数分オーダーも出来そうだが、調整必要ですね。
ってかぁ、秒越えは、アバウトでいいんじゃな〜い、アバウトタイム。

ここで使用したプログラムは"Timer0OUT.c"を参考にして下さい。
Timer0の詳しい設定方法等は、”PICの動かせ方入門”ページ内の各PIC覚書を参照下さい。

SMTタイマー *2)

PIC12(16)F161x系のPICにはSMT(信号計測タイマー)モジュールが有ります、これはパルスを計測する
モジュールですが、この機能は24ビットカウンタでタイマーモードでも動作します。
このモジュールは割り込み処理の中でカウンター値の再設定は必要無く、出力ピンをプログラムで
トグル動作させるだけですが処理時間は[1.25us]かかります。
コンペア機能の様にハードでトグル動作をしてくれれば最高なのだがぁ...
24ビットだから16777215までカウント可能で、1カウント1usなら約16s(32MHz/4)のパルスを作れそう

1秒毎の出力を行って見た
SMTタイマー図(時間表示:1秒)
1us設定だから1000000回(0xF4240)カウントさせただけ調整なし、
Timer0は[1.75us]でSMTは[1.25us]遅延するがTimer0よりよかね―。

この機能に付いての記事はこちらを参照下さい。

《コンペア機能》

 PICにはCCP(Capture/Compare/PWM Modules)モジュールが有ります、
"Compare"機能は指定した時刻になるとピン出力(LOW/HIGH/トグル)をさせる事が出来るので
トグル動作で矩形波を発生させて見ます。
コンペア機能構成図 左図は16F18313のデータシートからの拝借図です。

Timer1は16bitなので0〜65535までカウントアップ
して行きます。
でぇCCPRxL/CCPRxHレジスタに設定された値と
同じになった時にCCPピンに出力を行う機能です。

同じになった時にTimer1カウンターはクリアされないので割り込み発生時に自分でクリアさせます。
ですがぁ、最新のPIC(16F18313等)はクリアする
コンペアモードが付いているのでこれを利用します。
って事は、PICが行うなら余計な処理を記述しなくて良いので遅延は最小限に抑えられそうですね。
尚、Timer1/3/5付きのPICならこれらから選択出来ます。

設定するFoscによる出力可能時間(ここでは32MHzで設定)
Fosc
32MHz
16MHz
8MHz
4MHz
2MHz
1MHz
1カウント時間
125ns
250ns
500ns
1us
2us
4us
出力可能時間
8.192ms
16.384ms
32.768ms
65.536ms
131.072ms
262.144ms
とぉ、Foscを落とせば出力可能時間は伸びるのですがぁ...

コンペア機能時のTimer1プリスケーラは"1:1"のみ設定出来ます、"1:8"が使えない!
My掲示板に書き込まれた"猛牛ロック"さんの情報によると、"16F18325/18345のエラッタ"に記載が
有るらしい、だから32MHz動作なので1カウント125nsで最大8.192msまでのトグル動作をさせます。

1us(500KHz)で出力してみた。
Timer0図(時間)
ふむ、PICがタイマ−カウンターをクリアしてくれる割には1us以下になるとぉチョットぉビミョー

1ms(500Hz)で出力してみた。
Timer0図(時間)

8ms(62.5Hz)で出力してみた。
Timer0図(時間)
まあ、良いんじゃないでしょうか
がぁ、”1:8”が使える様になってから出直して来いって感じでしょうか?
Timer0図(時間/水晶発振器)
水晶発振器8MHzでも出力させてみた。 *1)


ここで使用したプログラムは"CompareOUT.c"を参考にして下さい。

T1CONの設定
 T1CON = 0b00000001 ;
 青数字部分でTimer1のクロックソースを選択します。(Fosc/4のみ使用する)
  00 = Fosc/4  01 = Fosc  10 = 外部入力  11 = 内蔵の容量検知オシレータ (CAPOSC)
 緑数字部分でプリスケーラの設定を行います。(1:1のみ使用する)
  00 = 1:1  01 = 1:2  10 = 1:4  11 = 1:8
 橙色数字部分で外部クロック入力を同期させるか設定します。(同期させる)
  1=同期させない 0=システムクロックと同期させる
 紫色数字部分 1=TIMER1を動作させる 0=TIMER1を動作させない

CCPxCONの設定
 CCPxCON = 0b00000001
 青数字部分でイベントを発生させるエッジの指定をします。
  0000 = CCPモジュールOFF
  0001 = 比較一致時に出力をトグルし、タイマ−カウンターもクリアする
  0010 = 比較一致時に出力をトグルする
  1000 = ECCP1ピンをLowに初期化し、比較一致時に出力をセットする(同時にCCP1IFをセット)
  1001 = ECCP1ピンをHighに初期化し、比較一致時に出力をクリアする(同時にCCP1IFをセット)
  1010 = ソフトウェア割り込みのみを生成し、ECCP1ピンはI/Oステートに戻る
  1011 = 特殊イベントトリガ(CCP1がTimerをリセットし、CCP1IFをセットする、
      ADC モジュールが有効な場合はA/D 変換を始める)

《NCOで出力》

NCO(Numerically Controlled Oscillator module:数値制御オシレータ)は周波数発生器の様な機能で、
全てのPICに有るわけではなく、10F322/16F18313/12F15xx/16F15xx等が内蔵しています。
このモジュールも設定を行えば後はハードがやってくれます。
PWMにくらべると、細かい周波数設定がお得意の様で、低い周波数から出力が出来そうです。
NCOの詳しい話は、PIC12F1501での記事ですがこちらを参考にして下さい。

インクリメントレジスタ値=1での波形
NCOインクリメントレジスタ値=1
この周波数がNCOで出力可能な最低周波数の設定です。

250KHzでの波形
250KHzでの波形
この周波数までは、計算通りのインクリメントレジスタ値で動作するようだがぁ...
この周波数を超えてくるとぉ、インクリメントレジスタ値を調整する必要が有りそうです。

2MHzでの波形(計算上のインクリメントレジスタ値=149796)
2MHzでの波形1

2MHzになる様に調整してみたインクリメントレジスタ値=135000
2MHzでの波形2
ね、調整必要じゃろーぉ。
インクリメントレジスタ値の設定からするとぉ、周波数は8MHzまで行けそうだが....
周波数設定がビミョーなせいか?、なんだかぁ、PWMの方が精度良さそうな気がするが....

3MHzの波形
2MHzでの波形2
あれ、これはぁPWM時と同じ出力の仕方やね、調整の使用が無い様な気がするぅ。
もぉ、ハード的に限界なのかしらぁ?
NCOは16Hz〜250KHzなら希望通り行けそうだが、それ以上は調整必要ってとこかしら

ここで使用したプログラムは"NCOOUT.c"を参考にして下さい。
サンプルで周波数を計算しているロジックが有りますがぁ、この計算は1KHz〜250KHzまでなら
まあまあ上手く動作します、マイコンには誤差等が有り、floatで行えば最も正確な数値が出せるかも
ですがぁ...
電卓で計算してそれを設定した方が良いかも、でも高い周波数になるとぉ調整が必要だけどねー。
それとぉ、このNCO記事は、"FDC MODE"です、"PF MODE"にするとデューティ比調整が出来ます。
NCO付きのPICであれば150Hz辺りからデューティ比設定が出来そうな気配やね。(未実験)
NCOの使い処は"262Hz"とかの出力調整して値を配列等で固定値として持って使う様な方法がよかね。

”262Hz”チョットぉやってみた
NCO262Hz図(周波数)
テスターで測るとぉ、260.5Hz...おしぃ!!
絶対音感のPICは無理かぁ、私よりはかなりましですがぁ。
NCO262Hz図(周波数/水晶発振器)
水晶発振器8MHzでも出力させてみた、テスターで測るとぉ、263.1Hz
NCO機能は、水晶発振器でもあまり変わらない様な気がします。 *1)

《タイマー1で出力改良》

 上記で割り込み処理時に10us掛かっていましたね、これをTimer0の割り込みの如く改良しました、
これで[1.75us]の割り込み処理時間となったのでぇチョットぉやって見ます。

改良前の10us遅延

Before1000Hz波形
Timer1図(周波数)

Timer1図(時間)

改良後の1.75us遅延

After1000Hz波形
Timer1図(周波数)改良

Timer1図(時間)改良
完璧過ぎてぇ、。゚(゚´Д`゚)゚。
でもぉ、1.75usが影響しそうな高い周波数は調整が必要だけどね\_(・ω・`)ココ重要!

改良したプログラムは"Timer1OUTRE.c"を参考にして下さい。


《まとめ》

1サイクルのデュティ比を可変できる機能は、PWMとNCOです。
500Hz(2000Hz)〜2MHzの範囲内で精度を求めるならPWMをお勧めして置きます。
1KHz〜250KHz以上(調整必要かも)の範囲内でデュティ比の可変を行いたいならNCOでも良いでしょう。

16F18313のTimer0なら、268秒〜数us(調整必要)で出力出来ます。
(通常のTimerは割込み処理(数us)が有るのでそれ以上のパルス発生は無理って事ですよね、
 100KHz以内の長いパルスを生成する場合等に使いましょう。)
システムクロックを下げても良いなら2秒〜1us(500KHz)範囲内でコンペア機能も精度が出せます。
(但し、タイマークリアモード有りのPICに限りますがぁ)
プログラムの一時停止をアバウトタイムで良いなら__delayが使いやすくて一番やぁ―

内部クロックでも調整を行えばそこそこ精度が出る事が解りましたが、
更に精度を求めるなら外部水晶振動子を取り付けましょう。




PSMCの話を追記(*4) 2018/05/03
CLKRの話を追記(*3) 2018/04/21
SMTタイマーの話を追記(*2) 2018/04/17
水晶発振器を取付けてチョットぉやってみた(*1) 2018/04/15


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