実例09 TIM1はONE SHOTとして動作する
----単発パルスの発生----
これが必要とされる場面はあまり多くないとは思いますが、これも主要なタイマ機能の一つですから、解説しておきます.
ワンショットとかモノマルチと呼ばれる機能で、汎用ロジックICでは74HC123で実現されることの多い機能です.
トリガにpositiveエッジが生じると、出力がただちにHIGHになります.
そのpositiveエッジから起算して、一定の時間長後に出力がLOWになります.
これがワンショットの動作です.
普通の発振回路と違うのは、1トリガあたり1パルスしか出ないことです.
以下で試作するワンショットは、STM8S-DISCOVERYでこのブロック図のように構成します.
TIM1がワンショットの本体です.
TIM2はワンショットを駆動するトリガ信号を1Sec毎に発生させる役目です.
CPUはTIM1とTIM2の初期設定機能だけで、初期設定が終わった後は休んでいます.
割り込みは使いません.
ハードウエアの準備
STM8S-DISCOVERYにハンダごてで線をつなぎます.
1) 1Sec毎のパルスがTIM2_CH1に出てきますので、それをTIM1_CH2に接続します.
基本これだけですが、
2) ワンショット出力をオシロでモニタするために線をつなぎたい人は TIM1_CH1 に短い線でもなんでもつければ良いでしょう
サンプルプログラムの解説
サンプルプログラムはこちらを参照してください.
以下は、project test09のmain.cです.
●#include "stm8s.h"
ライブラリを使うためにインクルードします.
●@CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI, DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE);
ACLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1 );
BCLK_SYSCLKConfig( CLK_PRESCALER_CPUDIV1 );
@は内部クロックの16MHzをつかうように設定します.
Aは16MHzを1分周して(=分周せずに)fMASTER=16MHzに設定します.fMASTERはタイマに供給されます.
BはfMASTERを1分周して(=分周せずに)fCPU=16MHzに設定します.fCPUはCPUに供給されます.
●TIM1_TimeBaseInit( C1599, DTIM1_COUNTERMODE_UP, E2999, F0 );
TIM1のカウンタの設定です.
CfMASTERを1600分周して16MHz/1600=10kHzがカウンタに供給されるように設定します.
Dカウンタがカウントアップするように設定します.
Eカウンタが0〜2999までカウントするように設定します.
F割り込みをかけるときに間引き数を設定するのに使いますが、ここでは割り込みしないので0でいいです.
●GTIM1_SelectInputTrigger( TIM1_TS_TI2FP2 ); // TS=110
HTIM1_SelectSlaveMode( TIM1_SLAVEMODE_TRIGGER ); // SMS=110
Gカウンタへのトリガ信号を、TIM1_CH2由来の信号に設定します.
Hカウンタがトリガのスレーブとして動くように設定しています.
●ITIM1_SelectOnePulseMode( TIM1_OPMODE_SINGLE ); // OPM=1
TIM1_OC1Init( JTIM1_OCMODE_PWM2,
KTIM1_OUTPUTSTATE_ENABLE, LTIM1_OUTPUTNSTATE_DISABLE, M1000,
NTIM1_OCPOLARITY_HIGH, OTIM1_OCNPOLARITY_HIGH, PTIM1_OCIDLESTATE_RESET,
QTIM1_OCNIDLESTATE_SET );
Iワンショットに設定しています.カウンタがグルグル回らずに1回で止まるように設定しています.
J正極性パルスを出します.負極性パルスを出したければ、TIM1_OCMODE_PWM1 にすればOKです.
KTIM1_CH1を出力に設定しています.TIM1_OUTPUTSTATE_DISABLE にするとTIM1_CH1はOFFになります.
LTIM1_CH2を出力に設定しないので、......DISABLEにしておかなくちゃいけません.
Mカウンタが0〜3000の範囲で動くようにEで設定しました.ここでは1000でコンパレートするように設定しています.
N正極性のパルスが出ます.TIM1_OCPOLARITY_LOWにすると負極性パルスになります.
OTIM1_CH2は出力としては使わない(トリガ入力としてつかう)ので、この引数はドントケアです.
PBREAKをかけたりしたいときに関係する引数なので、この引数はドントケアです.
QBREAKをかけたりしたいときに関係する引数なので、この引数はドントケアです.
●TIM1_Cmd(ENABLE);
TIM1_CtrlPWMOutputs(ENABLE);
TIM1を動作させ、出力をオンにしています.
●TIM2_DeInit();
TIM2_TimeBaseInit(TIM2_PRESCALER_1024, 15624); // 16MHz/1024/15625=1Hz
TIM2_OC1Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE, 500, TIM2_OCPOLARITY_HIGH); // output TIM2_CH1 D4
TIM2_Cmd(ENABLE);
TIM2で1秒毎のパルスを発生させるための設定です.
カウンタは0〜15625の範囲で動きます.
1秒毎のパルスが出る理由は、16MHz/1024/15625=1Hz だからです.
パルス幅は、500という引数が利いています.カウンタが0〜500の間だけHIGHの信号がTIM2_CH1に出ます.
dutyは、500/15625*100=3.2%となります.
TIM2_CH1のピンは、STM8S105C6のハードウエアでPD4と決まっています.
TIM2_CH1である理由は、TIM2_OC1Init()をcallしたからです.TIM2_OC2Init()をcallしたらTIM2_CH2に出力されます.
サンプルプログラムの動作結果
test09
下記はオシロで観測した波形です.X軸の一目盛りは0.1秒です.
赤いのがTIM2が発生させたトリガです.トリガは1秒ごとに発生していますので、設計通りです.
青いのがワンショット出力です.トリガのpositiveエッジから起算して、0.1秒待ってHIGHになり、0.3秒のところでLOWに戻っています.
そうなる理由は、設定の次のところが利いています.
CfMASTERを1600分周して16MHz/1600=10kHzがカウンタに供給されるように設定します.
Eカウンタが0〜2999までカウントするように設定します.すなわち0.3秒で一周.
L1000でコンパレートするように設定しています.すなわち0.1秒で到達.
その結果、こういう動作をしています.
トリガのpositiveエッジでカウンタが動き始める
→ カウンタが1000を超えるとHIGHになる (0.1秒後)
→ カウンタが2999になるとカウンタが0になり出力はLOWに戻る (0.3秒後)
→ カウンタはそのまま止まっているのでLOWのまま
お気づきの方もいると思いますが、冒頭の図(下に再掲)とはやや趣の異なるワンショット動作です.
トリガと同時にHIGHになってないじゃないかというところが違います.
これはSTM8Sのタイマ機能を使うかぎりは仕方のないことのようです.
それでも、動作としてはワンショットの一種であると言えます.
test09b
このサンプルプログラムがやりたいことは、トリガ入力のnegativeエッジでトリガがかかるようにしたいってことです.
オシロ波形をみると、トリガのnegativeエッジを起点にして、0.1秒後に出力がHIGHになり、0.3秒後にLOWになっていることがわかります.
このように、トリガのnegativeエッジで動かすには、ソースコードをどういじればよいのでしょうか?
ちょっと複雑です.
●void TI2_Config(uint8_t TIM1_ICPolarity, uint8_t TIM1_ICSelection, uint8_t TIM1_ICFilter)
{
TIM1->CCER1 &= (~TIM1_CCER1_CC2E);
TIM1->CCMR2 =
(TIM1->CCMR2 & (~( TIM1_CCMR_CCxS | TIM1_CCMR_ICxF ))) |
(TIM1_ICSelection | ( TIM1_ICFilter << 4));
if (TIM1_ICPolarity != TIM1_ICPOLARITY_RISING) TIM1->CCER1 |= TIM1_CCER1_CC2P;
else TIM1->CCER1 &= (~TIM1_CCER1_CC2P);
TIM1->CCER1 |= TIM1_CCER1_CC2E;
}
まずこのルーチンを main.c の末尾に追加してあります.
そもそもこのルーチンは、ライブラリの中にあるマイナーなルーチンで、stm8s_tim1.hがパブリックに定義してないので、呼び出しができなかったので、main.c にコピペして使うようにしました.
そして、main()の中でつぎのように呼び出しています.
●TI2_Config( TIM1_ICPOLARITY_FALLING, TIM1_ICSELECTION_DIRECTTI, 15 ); // polarity setting, filter setting
第1引数の、TIM1_ICPOLARITY_FALLING がnegativeエッジでトリガをかける設定です.
第2引数の、TIM1_ICSELECTION_DIRECTTI はこのままにしといてください.変えちゃだめです.
第3引数の、15 はトリガ信号がチャタッているときに入れるフィルタを最強に設定しています.
スイッチ由来の信号でなければ0にしといても良いでしょう.
このフィルタは0〜15の値を取れまして、下記の意味を持っています.
0: フィルタなし
1: fMASTERで2クロック後に再チェック
2: fMASTERで4クロック後に再チェック
3: fMASTERで8クロック後に再チェック
4: fMASTER/2で6クロック後に再チェック
5: fMASTER/2で8クロック後に再チェック
6: fMASTER/4で6クロック後に再チェック
7: fMASTER/4で8クロック後に再チェック
8: fMASTER/8で6クロック後に再チェック
9: fMASTER/8で8クロック後に再チェック
10: fMASTER/16で5クロック後に再チェック
11: fMASTER/16で6クロック後に再チェック
12: fMASTER/16で8クロック後に再チェック
13: fMASTER/32で5クロック後に再チェック
14: fMASTER/32で6クロック後に再チェック
15: fMASTER/32で8クロック後に再チェック