SMT機能を動作させて見ます
〔PICの動かせ方入門に戻る〕
SMT(Signal Measurement Timer module:信号計測タイマ)機能は、
入力された信号のパルスをカウントする機能です。
PICの12F1612/16F161xシリーズにはSMT機能を2モジュール内蔵しています、
これは、2つの信号のエッジ間隔やパルス幅・周波数・デューティサイクル等のカウントを行う機能で、
24ビットカウンタなので長いパルス幅も計測可能です、
又、24ビットカウンタのタイマーとしても動作可能です。
計測する入力信号は、Timer2/4/6とZCD出力やコンパレータ出力・外部ピンから選択します。
今回12F1612をマイクロチップからサンプル入手したのですが、メモリが2WordなでSMT機能の
実験には少しツライ物が有ります、出来るなら上位のPICで行った方が良い様に思います。
(2015/07現在、RSオンラインのここで10個単位ですが12F1612が手に入ります)
※ 2017/01/11現在、12F1612/16F1619が秋月電子通商でも手に入ります *1)
電子工作の実験室後閑先生のSMT(信号計測タイマ)の使い方を読みながら進めて下さい。
そこに書いて有る様にSMT機能には11個の計測モードが有りますが、このページでは以下の
4つの動作モードのみ記述して置きます。
・周期およびデューティ サイクル収集モード(Period and Duty Cycle Acquisition)
・HighおよびLow時間計測モード(High and Low Time Measurement)
・継続時間測定モード(Time of Flight)
・24ビットタイマーモード(Timer)
尚、こちらに12F1612の日本語データシートが有るので合わせて見ましょう。
又、恥ずかしい話ですがぁ、私はオシレータ発振器の部類は持っていません、ですので、
外部からパルスを入力出来ないので、ここの記事では12F1612自体のCCP1(PWM)機能でパルスを
発生(50KHz:20%デューティ比)させその出力をSMT機能に入力させています。
《周期およびデューティ サイクル収集モード》
連続計測では、SMTxGOビットを落とすまでパルスの周期毎に連続して計測を行いますが、
ここでは1周期で計測が終了する単発計測モードで説明します。
SMTxGOビットがONした後、入力信号の最初の1周期を計測します、計測後はPICがSMTxGOビットを
落とすので再計測する場合は再びSMTxGOビットをONさせます。
計測完了を知るには、
パルス幅計測完了での割込み(SMTxPWAIE)と周期幅計測完了での割込み(SMTxPWRAIE)を
利用しても良いのですが、サンプルプログラムではSMTxGOビットのOFFを見ています。
使用するレジスタ
周期およびデューティ サイクル収集モードに関連するレジスタのビットのみ記述します。
その他はデータシートを見ましょう、日本語だしぃ。
SMTxCON0のレジスタ
ビット |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
機能 |
EN |
- |
STP |
WPOL |
SPOL |
CPOL |
SMTxPS |
EN:SMTモジュールの
有効・無効使用ビット
1 = SMTを有効にする
0 = SMTを無効にする。内部状態はリセットされ、クロック要求は無効になる
SMTxPS:SMTプリ
スケール選択ビット(長いカウントを行うなら1:8にすれば良い)
11 = 1:8 10 = 1:4 01 = 1:2 00 = 1:1
SMTxCON1のレジスタ
ビット |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
機能 |
SMTxGO |
REPEAT |
- |
- |
MODE |
SMTxGO:SMTx
GOデータ収集の開始ビット
1 = データ収集を有効にする 0 = データ収集を無効にする
REPEAT:SMTx繰
り返し収集を行うかの指示ビット
1 = 繰り返し収集モードを有効にする 0 = 単発収集モードを有効にする
MODE:SMT機能の動
作モード選択ビット
1011 = 予約済み
1010 = ウィンドウ カウンタ
1001 = ゲート付きカウンタ
1000 = カウンタ
0111 = キャプチャ
0110 = TOF (Time of Flight)
0101 = ゲート付きウィンドウ計測
0100 = ウィンドウ計測
0011 = HighおよびLow時間計測
0010 = 周期およびデューティ サイクル収集
0001 = ゲート付きタイマ
0000 = タイマ
SMTxCLKのレジスタ
ビット |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
機能 |
- |
- |
- |
- |
- |
CSEL |
CSEL:SMTクロック選択ビット
100=MFINTOSC/16 011=LFINTOSC 010=HFINTOSC 16MHz 001=FOSC/4 000=FOSC
SMTxSIGのレジスタ
ビット |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
機能 |
- |
- |
- |
- |
- |
SSEL |
SSEL:SMT入力信号選択ビット
110 =TMR6_postscaled 101 =TMR4_postscaled 100 =TMR2_postscaled
011 =ZCD1_out 010 =C2_OUT_sync 001 =C1_OUT_sync 000 =SMTxSIGピン(外部入力)
SMTxCPWU(最上位byte)/SMTxCPWH(上位byte)/SMTxCPWL最(下位byte)のレジスタ
HIGHのパルス幅のカウント値(8bitx3の24ビット)を格納する、
SMTxGOがOFFされてもこのレジスタ値は保持されます。
SMTxCPRU/SMTxCPRH/SMTxCPRWLのレジスタ
パルスの1周期カウント値(8bitx3)を格納する、SMTxGOがOFFされてもこのレジスタ値は保持されます
配線図

回路電源は5Vです。
RA5端子から別途作成のLCDモニターに接続し、計測値を
表示させています。
SMTの入力信号として、CCP1(PWM)機能で
パルスを生成(50KHz)し、RA2(CCP1)端子から出力した物を、
RA4(SMTSIG1)端子に入力しています。(左桃色線)
尚、LEDは無くても良いです、CCP出力の確認用です。
実験風景です、写真があまり良くないですね。
LCD画面部分を画像補正しています、ってぇ
補正する位なら、撮り直せよ!、自分!
[50000Hz(640P)] ← 周波数
[20%(128P)] ← デューティ比
ってぇ、表示されています。
カッコ内数値はパルスのカウント値です。
SMTクロックはFosc(32MHz)、プリスケール1:1
なら、1カウント時間は
(1000000/32000000) * 1 =0.03125us
640カウント(1サイクル)だから
1000000/(0.03125*640) = 50000Hz
因みに、テスターでCCP1(RA2)出力を測って
見た所、49.89KHzで20.2%でした。
尚、LEDは薄っすらと点灯しています。
このサンプルプログラムは単発なので1回の計測で終了します、入力信号がふらつく場合等により連続で
計測し平均を求めたい人は頑張ってご自分でプログラミングして下さい。
サンプルプログラムについて
↓ここからサンプルプログラムソースファイルをダウンロードして下さい。
SMT.zip
Ver 1.10 18/04/17 "SMT_Timer.c"の割り込み処理を変更 *2)
プログラムソースをダウンロードしたら、MPLAB Xにてプロジェクトを作成します。
以下のファイルをプロジェクトディレクトリにコピーしてプロジェクトに取込んで下さい。
次にコンパイルとPIC書き込みを実行して下さい。
MPLAB(R) XC8 C Compiler Version 1.32コンパイラを使用しています。
ダウンロードファイルを解凍すると下記の様なファイル構成です。
SMT_PeriodDuty.c ・・・・・ "周期およびデューティ サイクル収集モード"のプログラムソースファイル
SMT_HighLow.c ・・・・・・・ "HighおよびLow時間計測モード"のプログラムソースファイル
SMT_Timer.c ・・・・・・・・・・ "タイマモード"のプログラムソースファイル *2)
SMT_TOF.c ・・・・・・・・・・・ "TOF(Time of Flight)モード"のプログラムソースファイル
上記ファイルの何れか一つでコンパイルをします。
"SMT_Timer.c"ファイル以外は、LCDに表示する為のデバッグモニタープログラム「skMonitorLCD.c」
「skMonitorLCD.h」が必要です、デバッグLCDモニターについてはこちらを参照して下さい。
また、LCDモニターの出力はRA5から行っているので「skMonitorLCD.h」を下記の様に変更します。
#define _XTAL_FREQ 32000000 // 使用するPIC等により動作周波数値を設定する
#define MONITOR_PIN RA5 // モニタ出力するピンの番号を設定する
(但し、"SMT_TOF.c"ではRA2から、LCDモニターに出力しています。)
尚、CPUのクロックは32MHzを想定しています。
SMT_PeriodDuty.c について
実行させると上記実験写真の様に表示すると思います。
CCP1(PWM)で使用するタイマは、プログラムではTimer4を使っていますがTimer2/6も使用可能です。
ですが、Timer2はデバッグモニタープログラムで使用しています。
計測完了時に割り込みを行いたい人は、プログラムのコメントを外せば割り込みが掛かります、
但し、割り込みで何を処理するかはご自分で作成しますよ。
※ PWM機能は250Hz〜2MHzまで生成出来ますので、SMT機能でこの範囲の周波数は計測していますが、
それ以外の周波数は不明です。
《HighおよびLow時間計測モード》
このモードも1周期で計測が終了する単発計測モードで説明します。
基本は"周期およびデューティ サイクル収集モード"と同じです、
上記モードでは1周期のカウント値でしたが、このモードはHIGHとLOW部分を別々にカウントします。
使用するレジスタ
使用するレジスタも"周期およびデューティ サイクル収集モード"と同じです、
SMTxCON1のレジスタのモードを"HighおよびLow時間計測モード"に変更するだけです。
配線図
配線図も、上記"周期およびデューティ サイクル収集モード"と同じです。
SMT_HighLow.c について
このプログラムを実行すると、"HighおよびLow時間計測モード"で計測されLCDにカウント値が
表示されます。
LCDの表示は、
[HIGH LOW ] ← パルスの状態
[128P 512P ] ← パルス幅のカウント値
ってぇ、表示されています。
カウント値を時間に変換し表示させたかったのですがぁ、プログラム容量が足りませんでした。
通常のタイマ、Timer0(8bit)/Timer1(16bit)/Timer2/4/6(8bit)となっていますが、
このSMTは24ビットのタイマとして動作させられますので、長いインターバルタイマが可能でしょう。
使用するレジスタ
SMTxCON0のレジスタ
ビット |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
機能 |
EN |
- |
STP |
WPOL |
SPOL |
CPOL |
SMTxPS |
EN:SMTモジュールの
有効・無効使用ビット
1 =
SMTを有効にする
0 = SMTを無効にする。内部状態はリセットされ、クロック要求は無効になる
SMTxPS:SMTプリ
スケール選択ビット
11
= 1:8 10 = 1:4 01 = 1:2 00
= 1:1
SMTxCON1のレジスタ
ビット |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
機能 |
SMTxGO |
REPEAT |
- |
- |
MODE |
SMTxGO:SMTx
GOデータ収集の開始ビット
1 =
データ収集を有効にする 0 = データ収集を無効にする
MODE:SMT機能の動
作モード選択ビット
1011 = 予約済み
1010 = ウィンドウ カウンタ
1001 = ゲート付きカウンタ
1000 = カウンタ
0111 = キャプチャ
0110 = TOF (Time of Flight)
0101 = ゲート付きウィンドウ計測
0100 = ウィンドウ計測
0011 = HighおよびLow時間計測
0010 = 周期およびデュー
ティ サイクル収集
0001 = ゲート付きタイマ
0000 = タイマ
SMTxCLKのレジスタ
ビット |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
機能 |
- |
- |
- |
- |
- |
CSEL |
CSEL:SMTクロック選択ビット
100=MFINTOSC/16 011=LFINTOSC 010=HFINTOSC 16MHz 001=FOSC/4 000=FOSC
SMTxPRU(最上位byte)/SMTxPRH(上位byte)/SMTxPRL最(下位byte)の周期レジスタ
何カウントさせるのかを24ビット値で設定します。
例えば、1000000回(0xF4240)カウントさせるには
SMT1PRU = 0x0F ; // 周期レジスタで最上位バイト
SMT1PRH = 0x42 ; // 周期レジスタで上位バイト
SMT1PRL = 0x40 ; // 周期レジスタで下位バイト
割り込みのレジスタ
SMT1IE = 1 ; // SMT1オーバーフロー割込みを許可する
SMT1IF = 0 ; // SMT1オーバーフロー割込みフラグを0にする
PEIE = 1 ; // 周辺装置割込みを許可する
GIE = 1 ; // 全割込み処理を許可する
配線図
配線図は、上記"周期およびデューティ サイクル収集モード"と同じ物を使います。
約1秒毎にLEDを点滅させますのでLEDは配線をして置きましょう。
SMT_Timer.c について
このプログラムを実行するとRA2に接続したLEDが1秒毎にON/OFFします。
SMTの入力端子、SMTWIN/SMTSIGは使わないのでデジタル端子で使用可能です。
SMTxGOビットがONすればタイマのカウントが開始され、SMTxPR周期レジスタの設定値まで
カウントしたら割り込みが発生(SMTxIF)します、で、また再カウントを行います。
尚、このモードは、SMTクロックをFOSC/4、プリスケーラを1:8に設定を変えています。
ワンカウントの時間は?
PICのクロック周波数とプリスケーラ設定値できまります。
・ 例えばシステムクロック周波数32MHz(SMTクロックはFosc/4)でプリスケーラ設定値が 1:8 なら
((1/システムクロック周波数) x 4) x プリスケーラ設定値
((1 / 32MHz) x 4) x 8 = 1μs → これがワンカウントの時間です。
これを1000000回カウントアップさせると1秒と言う事なのでSMTxPR周期レジスタに設定します。
SMTxPR周期レジスタは24ビットで16777215までカウント可能だから16777215usまでイケそう。
因みにシステムクロック4MHzなら (((1/4MHz)x4)x8)x16777215 = 134217720us(約134秒)
《TOF(Time of Flight)モード》
このモードも1周期で計測が終了する単発計測モードで説明します。
このモードは、2つの入力信号1/2のパルス間をカウントする機能です。
(って言うかぁ、ストップウオッチきのおぉ、みたいなぁ、かんじぃ)
SMTxGOビットがONした後、入力信号1の立ち上がりでカウントを開始します、
次に入力信号2の立ち上がりでカウントを終了し、周期キャプチャレジスタ(SMTxCPR)にカウント値を
セットしてぇ、SMTxGOビットを落とします。
入力信号1:SMT1ウインドウ信号の入力源は、SMTWIN1ピン(RA5:2番端子)にスイッチ1を配線。
入力信号2;SMT1信号の入力源は、SMTSIG1ピン(RA4:3番端子)にスイッチ2を配線。
スイッチ1でカウント開始し、スイッチ2でカウント終了です。
スイッチ1でカウント開始し、スイッチ2のパルスが来なくてスイッチ1のパルスが先に来た場合は、
その時点までのカウント値はパルス幅キャプチャレジスタ(SMTxCPW)にセットされます。
キャプチャレジスタ(SMTxCPR/SMTxCPW)やタイマーレジスタ(SMTxTMR)は24ビット(3バイト)です、
”16777215”でオーバーフローします、オーバーフローしたらまた0から再カウントするだけです、
オーバーフローすると割り込み(SMTxIF)が発生します、ですのでこの発生回数を数えれば長い時間の
測定も出来ます。
使用するレジスタ
上記モードと同じです、
SMTクロック(SMTxClock)は"タイマモード"と同じに設定しているので1カウント1usとなります。
SMTxWINのレジスタ
ビット |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
機能 |
- |
- |
- |
- |
- |
WSEL |
WSEL:SMTウインドウ入力信号選択ビット
110 =TMR6_postscaled 101 =TMR4_postscaled 100 =TMR2_postscaled
011 =ZCD1_out 010 =C2_OUT_sync 001 =C1_OUT_sync 000 =SMTxWINピン(外部入力)
配線図
RA2端子から別途作成のLCDモニターに接続し、計測値を表示させています。
SMTの入力信号として、RA4(SMTSIG1)端子にスイッチ2を接続、RA5(SMTWIN1)端子にスイッチ1を
接続しています。
但し、スイッチはチャタリングが有りパルスが何回も入力されるので、チャタリング防止回路を
通しています、チャタリング防止回路の話はこちらを参照下さい。
SMT_TOF.c について
起動すると、LCDの1行目に"SMT TOF TEST"が表示されます。
SW1を押しましょう、適当な時間でSW2を押せばLCDにSW1とSW2間の時間が表示されます。
1行目がSW1とSW2間の時間を"us"で表示。
2行目が"SMTxCPR"のカウント値、
[ ]内が"SMTxTMR"のオーバーフロー回数です。
尚、何度か試して計測させたい場合は、PICにリセットを掛ければ最初からプログラムが動きます。
(因みに、PICの4番ピンをGNDに落とせばリセットが掛かります)
又は、ご自分でプログラムを改造しましょう。
《16F1619》
*3)
PIC16F1619でもSMT機能を動作させたので、サラッとぉ追記して置く。
”周期およびデューティ サイクル収集”と”タイマー”モードのみです。
配線図

電源は5.0Vです。表示はI2C接続LCDで行っています。
この配線図は、”周期およびデューティ サイクル収集”モード用です、”タイマー”モードはRC0ピンに
LEDを接続して下さい。
SMTSIG1ピン:パルスの計測用入力で使用
SMT1モジュールを使用、ピンの割付けデフォルトはRA4(3番)ピンですがPPS機能で他ピンに変更可能
デフォルトRA4で動作しなかったので再度PPS機能で割付け直したら動作した?
CCP1ピン:PWMでパルスを出力する為に使用
PPS機能でRB7ピンに割付けています。
250-2000000Hz程出力可能です。
I2Cピン:I2C接続LCDの表示用で使用
PPS機能でRB4ピンに"SDA"としてRB6ピンに"SCL"と割付けています。
I2C用プルアップ抵抗は外付けですがPIC内蔵プルアップでも良いでしょう。
サンプルプログラムについて
↓ここからサンプルプログラムソースファイルをダウンロードして下さい。
SMT2.zip
ダウンロードファイルを解凍すると下記の様なファイル構成です。
SMT_PeriodDuty.c ・・・・・ "周期およびデューティ サイクル収集モード"のプログラムソースファイル
SMT_Timer.c ・・・・・・・・・・ "タイマモード"のプログラムソースファイル
skI2Clib.c・・・・・・・・・・・・・・ I2C通信を行う関数ソースファイル
skI2Clib.h・・・・・・・・・・・・・・ I2C通信を行う関数のヘッダファイル
skI2CLCDlib.c・・・・・・・・・・ I2C接続LCD関数ライブラリソースファイル
skI2CLCDlib.h・・・・・・・・・・ I2C接続LCD関数ライブラリのヘッダファイル
skI2CLCDlib.c
skI2CLCDlib.h
skI2Clib.c
skI2Clib.h
この内容とI2C接続LCDについては、”秋月電子I2C接続小型LCDモジュールに表示を行う”を参照下さい。
SMT_PeriodDuty.c について
実行させると、[ SMT Test ]が表示され3秒後に計測を開始し下の様に表示すると思います。
[1000 Hz 50% ]
[32000 16000 ]
1000Hzで設定しているので他の周波数で行う場合は、
"PWM_Frequency(1000)"を書き換えましょう、250Hz〜2MHzまでは出来るでしょう。
※ PWM機能は250Hz〜2MHzまで生成出来ますので、SMT機能でこの範囲の周波数は計測していますが、
それ以外の周波数計測は不明です。
SMT_Timer.c について
RC0ピンにLEDを接続し、起動させると1秒毎に点滅を行うと思います。
タイマーの設定は1カウント1usで行っています、24ビットタイマーなので16777215usまでOKでしょう。
《その他》
モードによっては、SMTWIN1ピン(RA5:2番端子)とSMTSIG1ピン(RA4:3番端子)はデジタルで使用
出来たりする、だが、SMT機能で利用しない場合は自由にピンを設定(SMTxSIG/SMTxWIN辺りで)で
開放出来る様にしてくれれば便利なんだけどなぁ...Microchipさん。
16F1619の話を追記(*3) 2018/04/19
"SMT_Timer.c"のプログラムを変更(*2) 2018/04/17
一部追記(*1) 2017/01/11
【きむ茶工房ガレージハウス】
Copyright (C) 2006-2018 Shigehiro Kimura All Rights Reserved.