ティム
タイマーは、最も強力で複雑な 32 構造です。
- 以前 51 で使用されていた関数は、一定間隔で割り込みを生成します。
- 出力比較。PWM 波形の生成、モーターの駆動などによく使用されます。
- 入力キャプチャ、方形波周波数を測定します。
- エンコーダー、直交エンコーダーの波形を読み取ります。
最大タイミング時間: 72M/65536/65536=割り込み頻度、割り込み頻度の逆数が最大タイミング時間です。
タイマーはカスケード接続できます。たとえば、72MHz の最大タイミングは 59.65 秒で、1 回のカスケード * 65536 * 65536 です。
タイプ | シリアルナンバー | バス | 関数 |
---|---|---|---|
高度なタイマー | チーム1、チーム8 | APB2 | 汎用タイマの全機能に、繰り返しカウンタ、不感帯発生、相補出力、ブレーキ入力などの付加機能を搭載。 |
汎用タイマー | TIM2、TIM3、TIM4、TIM5 | APB1 | 基本タイマーのすべての機能を備えており、内部および外部クロック ソースの選択、入力キャプチャ、出力比較、エンコーダ インターフェイス、マスター/スレーブ トリガー モードなどの追加機能を備えています。 |
基本タイマー | TIM6、TIM7 | APB1 | タイミング割り込みとDACをトリガーするマスターモードの機能を備えています |
下から上へとますます複雑で強力になります。f103c8t6 には TM1-4 があり (チップが違うのでマニュアルを参照してください!)、主に汎用タイマーを研究しています。
PSC は RCC を分周します. 例えば 1 を書き込むと 2 分周すると 72MHz/2=36MHz が出力されます. 実際の分周率 = プリスケーラ値 + 1.
カウンタはクロック周波数に従って連続的にインクリメントされ、= クリアされ、レジスタ値が自動的にリロードされると割り込みが生成されます。UI は割り込み、U はイベントです。
DAC を積極的にトリガーする: DAC 割り込みは非常に頻繁に発生し、多くの CPU リソースを占有します。タイマーがスレーブ デバイスを処理して DAC を単独で処理できる場合、多くの CPU リソースを節約できます。上の写真のTRGOです。
基本的なカウンターをベースに、汎用レジスターもダウンカウントとセンターアラインカウント (0-リロード値-0-リロード値...) をサポートします。
オプションの内部 72MHz クロックまたは外部クロックをクロックします。
タイマーのカスケードを実現できます。マニュアルを参照して、どのタイマーとどのカスケードかを確認してください。自己出力端子 CH は自身のクロック入力としても使用可能で、機能拡張は後ほど行います。
4 つの出力がアウトプットコンペア回路で、左側がインプットキャプチャ回路です。
図の影にはバッファ レジスタがあり、バッファ レジスタについてはすぐ下で説明します。
繰り返しカウンターは、割り込みがトリガーされる前に数サイクルを許容します。
出力 CH1-3 は相補波を出力できるので便利です。スイッチング時のストレートスルー現象(2つの反転回路が同時に切り替わるX字型のような現象)を防ぐため、DTGデッドゾーン発生回路により、スイッチング前にデッドゾーンを発生させ、上下の真空管を切り替える前にすべてゼロにリセットされます。
左下のブレーキ入力で、タイマーを異常終了させることができます。
基本的な構造は次のとおりです。
実行中の制御は、アップカウントとダウンカウントを設定するようなものです。
割り込み出力制御は、割り込みが必要かどうかを決定するフラグビットに相当します。
CK_PSC: プリスケーラの入力クロック。
CNT_EN: カウンター イネーブル、ハイ レベル オープン。後続のプリスケーラが 1 になり、周波数が /2 で分割されるため、2 つの立ち上がりエッジが 1 回だけトリガーされます。カウンタ レジスタは、それに応じて連続的にインクリメントされます。
自動リローダーの値に達し、カウンターがゼロになると、イベントが更新されます。
プリスケーラ レジスタが変更された後、すぐには変更されませんが、プリスケーラ バッファは割り込みがトリガーされた後の次のカウント サイクルの後に変更されるため、プリスケーラ バッファを真に制御することができます。
分周の原理はプリスケーラ カウンタに見られます. たとえば、プリスケーラ バッファが 1 に設定されている場合、つまり実際の分周率が 2 の場合、0 をカウントした後に実際の分周率 -1 に達し、 1 となり、カウンタは ++ にクリアされます。
CK_CNT = CK_PSC / (PSC + 1) CK\_CNT=CK\_PSC / (PSC+1)CK_CNT _ _ _=C K _ PSC / ( PSC+1 )
カウンターの場合は次のようになります。
実際の分周係数は +1 の 2 クロック サイクル前の 2 であり、オーバーフローが発生すると更新イベントと割り込みフラグ レジスタ プロンプトが中断されるようになりました。割り込みフラグ レジスタは、割り込みルーチンで手動でクリアする必要があります。
カウンターオーバーフロー頻度:
CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1) CK\_CNT\_OV = CK\_CNT / (ARR + 1) = CK\_PSC / (PSC + 1) / (ARR + 1)C K _ CNT _ O V=C K _ CNT / ( A RR+1 )=C K _ PSC / ( PSC+1 ) / ( A RR+1 )
arr は、自動リロード レジスタの値です。オーバーフロー時間の逆数をとります。
arr にはバッファレジスタもあり、使用するかどうかを選択できます。
図に示すように、arr は 36 に変更されていますが、この一連の割り込みが終了した後、シャドウ レジスタを更新する必要があります。
arr の値がほぼ加算され、arr が縮小する場合、カウンタがオーバーフローしてゼロに戻るまでカウンタを加算する必要がある可能性があるため、これを開いた方がよいでしょう。その後、割り込みなどの小さな問題が発生します。
次にクロックを見てください。クロックはすべての周辺機器に必要なものです。構成は systemInit() 関数にあります。
HSI HSE は内部および外部クロック ソースであり、外部クロック ソースはより安定しています。どちらもシステム クロックを提供し、一部の周辺機器 (AHB APB12) はそれらに依存しています。
LSE OSC は RTC です。
LSI RC は、独立したウォッチドッグ用のクロックです。
SystemInit() は最初に内部クロックを開始し、システムは一時的に 8MHz で動作し、次に外部クロックを開始して周波数逓倍のために PLL フェーズロック ループに入り、安定した 72MHz に達した後に出力します。
そのため、外部クロック回路に問題があり、正常に切り替えられない場合、プログラムの動作が遅く感じる場合があります 8MHzのシステムクロックで動作しています。または、CSS クロック セキュリティ システムが外部回路を強制的に停止する場合があります。CSS は、Advanced Control Timer のブレーキ入力回路にも参加します。
このボードの APB1 プリスケーラ係数は 2、APB2 は 1 です。
AHB プリスケーラの分周係数は、PCLK1 を直接分周します。タイマー 2-7 は次のとおりです。「プリスケーラ係数 = 1 の場合、周波数 = 36MHz は変更されません。それ以外の場合、周波数 * 2」なので、その内部基準クロックは常に 72MHz です。APB2 のタイマー 1、8 も同様です。
すべてのクロックは、AND ゲートとイネーブル回路に接続されています。
コード:タイマー
プロセス:
- RCC。
- クロックソースを設定します。
- クロック ソースのタイム ベース単位を設定します (プリスケーラ、自動リローダ、カウンタ モードの初期化)。
- 割り込み制御を設定(オン)します。
- nvic を構成します。これは、以前に学習した NIVC_Init を使用します。
- 実行コントロールを設定します。
- カウンターを開始します。
必要な機能のリスト:
TimeBaseInit: プリスケーラー、自動リローダー、カウンター モードを初期化します。
TimeBaseStructInit: タイム ベース ユニットに初期値を割り当てます。
Cmd: クロックを開始します。
ITConfig: 対応するクロック割り込みを有効にします。
次の 6 つは、クロック ソース選択、内部クロック、ITRx その他のタイマー クロック、TIx キャプチャ チャネル クロック、ETR モード 1、2 クロック、ETR タイム ベース ユニット、極性、フィルターなどを個別に設定する機能です。
この 5 つの関数は、Init 後にタイムベースユニットの構成を変更する関数です (プリスケーラの変更、カウントモードの変更、プリロードの有無の設定、カウンタ値の変更、自動リロード値の変更など)。
最後に、レジスタをクリアする 4 つの関数があります。
コードは exti とは少し異なります。
#include "stm32f10x.h" // Device header
extern uint16_t cnt;
void Timer_Init(void){
//rcc, set timer source, set psc + set arr + set cnt mode(time base unit), set it controller, set nvic it handler, set running control, enable counter
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_InternalClockConfig(TIM2);//默认也是这个时钟,不写也行
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//滤波器采样,频率越低,采样点数越多,滤波效果越好。不过延迟也越大。采样频率就是内部时钟和这个分频参数共同作用的结果
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
//比如我们想定1s中断一次,CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1),也就是72M / (PSC + 1) / (ARR + 1) = 1
//所以两者赋值可以是10000-1和7200-1,只要两者都在65535以内就行,赋值不唯一
TIM_TimeBaseInitStructure.TIM_Period=10000-1;//arr自动重装器值,72M 计数10000次,耗时 10000/72M s
TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//预分频器值,分7200频,即 10000/(72M/7200) s=1s中断一次。
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器值,高级计数器才用
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);//设为更新中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2,ENABLE);
}
void TIM2_IRQHandler(void){
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){
//这里设置为update
cnt++;
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
ここで cnt 変数は main.c に記述され、extern 変数は「この変数は別のファイルにあります。コンパイラを見つけることができます」と宣言するために使用されます。実際、.h の関数宣言も extern を追加する必要がありますが、省略できます。
開発ボードを起動すると、すぐに割り込みが発生するのがわかりますが、これはなぜですか? TIM_BaseInit の最後の文は次のとおりです。
TIMx->EGR = TIM_PSCReloadMode_Immediate;
自動リロード レジスタに書き込まれた値は、すぐに書き込まれるのではなく、イベントが更新されるまでバッファに書き込まれることがわかっています。最初に、自動リロード レジスタを初期化した後、それを書き込むことができず、割り込みをトリガーできませんでした。
したがって、上記のステートメントである TIM_BaseInit で更新イベントを手動でトリガーする必要があります。その代償は、電源投入直後に割り込みがトリガーされることです。更新イベントと更新中断は同時に発生します。
この割り込みを削除したい場合は、TIM_BaseInit の直後に「TIM_ClearFlag」を指定できます。
次に、TIM2 と PA0 が 1 つのピンであるため、TIM2 を外部クロック モードで構成するように設定し、赤外線シャッターを PA0 に接続した後、手動で光を一度遮断することは、クロックのサイクル。
必要な変更:
- クロックの初期化と GPIOInit、内部クロック構成を外部クロック (モード 2) に変更します。
void Timer_Init(void){
//rcc, set timer source, set psc + set arr + set cnt mode(time base unit), set it controller, set nvic it handler, set running control, enable counter
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x0F);//这里是滤波,太小的话一次红外检测加好多
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=10-1;
TIM_TimeBaseInitStructure.TIM_Prescaler=1-1;//十次红外检测,定时器++
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2, TIM_IT_Update);
TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2,ENABLE);
}
このようにして、タイマーが読み取るための赤外線センサーを介してクロック波形を作成する効果があります。