STM32 開発 (8) STM32F103 オンチップ リソース - タイマー割り込みの詳細な説明


1.基礎知識のポイント

知っておくべきポイント 1
STM32 には合計 8 つのタイマーがあり、2 ~ 5 は高度な PWN 機能を持つ基本タイマー、1 と 8 はモーター処理用の高度なタイマー、6 と 7 は通常のタイマーです。
ここに画像の説明を挿入
CK_CNT = CK_PSC/(PSC + 1)
PSC= CK_PSC/CK_CNT -1
オートロード レジスタの値: CK_CNT/設定する値
注: PSC 範囲 0 ~ 65535 (0 は 1 分周に対応し、65535 は 65536 ポイントの周波数に対応するため、追加します。 1)

知識ポイント 2
STM32 割り込みシステムのコア、つまり NVIC (Nested Vectored Interrupt Controller、ネストされたベクター割り込みコントローラー)、割り込みベクターのネスティングには優先度があります STM32 割り込み優先度:
1、プリエンプティブ優先度 2、レスポンシブ優先度 3、割り込みベクター テーブル

プリエンプティブプライオリティの特徴は、
プリエンプティブプライオリティの低い割り込みの処理中に、プリエンプティブプライオリティの高い割り込みを応答できること、つまり割り込みネスティングです。

レスポンシブ優先度の特徴は、
(1) 2 つの割り込み要因のプリエンプティブ優先度が同じ場合、レスポンス優先度の高い割り込みが先に応答し、2 つの割り込みはネスト関係を持たない (2) 2 つの割り込み要因の
場合割り込み要因のプリエンプティブ優先度が同じ場合、応答優先度の低い割り込みが実行されている場合、応答した応答優先度の低い割り込みの実行が完了するまで、応答優先度の高い割り込みは応答されません。割り込みが到着したとき、別の割り込みが処理されている場合、後の割り込みは前の割り込みが処理されるまで処理されません。

割り込みベクタテーブルの特徴は、
プリエンプティブプライオリティとレスポンスプライオリティが等しい場合、割り込みテーブルの順位に従って決定されることです。

STM32 では、これらの優先度を管理するためにグループ (Group) の概念を設定します。各割り込みには、割り込みのプリエンプティブ優先度とリアクティブ優先度を記述するための専用レジスタがあります。このレジスタでは、STM32 は 4 つのバイナリ ビットを使用して優先度を記述します。4 ビットの割り込み優先度は 2 つのグループに分けることができ、上位ビットから見ると、前にプリエンプティブ優先度が定義され、後ろに応答優先度が定義されます。

グループ 0: 応答優先度を指定するために 4 ビットすべてが使用されます;
グループ 1: 最上位 1 ビットはプリエンプティブ優先度を指定するために使用され、最後の 3 ビットはリアクティブ優先度を指定するために使用されます;
グループ 2: 最上位 2 ビットはプリエンプティブ優先度を指定するために使用され、最後の 2 ビットは応答優先度を指定するために使用されます;
グループ 3: 最上位 3 ビットはプリエンプティブ優先度を指定するために使用され、最後の 1 ビットは応答優先度を指定するために使用されます; グループ 4
:すべての 4 ビット プリエンプティブ プライオリティを指定するために使用されます。

この実験では、タイマー割り込みによって LED ライトを簡単に制御し、タイマー割り込みプロセス全体を理解します。
準備はできたか?私のショータイムを始めてください。


2. 開発環境

1. ハードウェア開発の準備
メインコントローラ:STM32F103ZET6
ここに画像の説明を挿入

2. ソフトウェア開発の準備
ソフトウェア開発は、仮想マシン + VScode + STM32Cube を使用して STM32 を開発し、仮想マシンで直接コンパイルおよびダウンロードします。
この部分は参照できます:ソフトウェア開発環境の構築


3. STM32CubeMX 関連の設定

1. STM32CubeMX の基本構成この実験は、 CubeMX 詳細説明の基本フレームワーク
に基づいて開発されています。

2. タイマーを生成するクロックを構成する
ここに画像の説明を挿入
クロックの構成は非常に重要です。! ! 上の図からわかるように、タイマーはタイマーの周波数を 72M で直接分周する必要がないため、CPU は非常にビジーになります。そのため、以降は72Mを基準に分周処理を行います。

3. 3 つの LED ライト ピンを構成する
ここに画像の説明を挿入

4. タイマーを構成する
5ms で割り込みをトリガーするようにイベントを構成します。RCC からのクロックは 72M (クロックで構成)
PSC = 72000000/1000000-1 (CK_CNT 1M)
自動ローディング レジスタの値: 1000000/200
このタイマーが 5ms に 1 回中断するように設定します。
ここに画像の説明を挿入

5. タイマー関連の割り込み設定
ここに画像の説明を挿入


四、Vscodeコード解説

1. タイマー 6 関連の構造体を構築する

// Inc/Timer6.h
typedef struct
{
    
    
  uint16_t volatile uRun_Timer;       //系统运行定时器
  
  void (*Timer6_Start_IT)(void);      //定时器6以中断模式启动
} Timer6_t;

extern Timer6_t Timer6;

2. 充填構造

// Src/Timer6.c
static void Timer6_Start_IT(void);      //定时器6以中断模式启动

Timer6_t Timer6 =
{
    
    
  0,
  Timer6_Start_IT
};
 
static void Timer6_Start_IT(void)
{
    
    
  HAL_TIM_Base_Start_IT(&htim6);     //启动定时器6,后面有详解
}

3. タイマー割り込みを再構成して、1 秒の LED 点滅を実現します (割り込み呼び出しについては後で詳しく説明します)。

#define LED1_Toggle HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
#define LED2_Toggle HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
#define LED3_Toggle HAL_GPIO_TogglePin(LED3_GPIO_Port, LED3_Pin);

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    
    
	if(htim->Instance == htim6.Instance)
	{
    
    
		//程序支持运行,指示灯间隔1s闪烁
		if(++Timer6.uRun_Timer >= TIMER6_100mS)
		{
    
    
			Timer6.uRun_Timer = 0;
			
			LED1_Toggle;
			LED2_Toggle;
			LED3_Toggle;
		}
	}
}

ここで、関連するコード kernel/Core/Src/tim.c の新しく生成されたファイルを詳細に分析し
、 Cube で構成されたパラメーターに従って自動生成されたタイマー関数を初期化します。

void MX_TIM6_Init(void)
{
    
    

  /* USER CODE BEGIN TIM6_Init 0 */

  /* USER CODE END TIM6_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {
    
    0};

  /* USER CODE BEGIN TIM6_Init 1 */

  /* USER CODE END TIM6_Init 1 */
  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 72000000/1000000-1;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 1000000/200;
  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
  {
    
    
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
  {
    
    
    Error_Handler();
  }
  /* USER CODE BEGIN TIM6_Init 2 */

  /* USER CODE END TIM6_Init 2 */

}

割り込み HAL_TIM_Base_Start_IT 関数をオンにする

HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
{
    
    
  uint32_t tmpsmcr;

  /* Check the parameters */
  assert_param(IS_TIM_INSTANCE(htim->Instance));        // 检查输入定时器

  /* Check the TIM state */
  if (htim->State != HAL_TIM_STATE_READY)                // 当前定时器状态,不是处于准备状态则返回
  {
    
    
    return HAL_ERROR;
  }

  /* Set the TIM state */
  htim->State = HAL_TIM_STATE_BUSY;                    // 设置当前为忙碌状态

  /* Enable the TIM Update interrupt */
  __HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);            // 开启定时器更新中断

  /* Enable the Peripheral, except in trigger mode where enable is automatically done with trigger */
  // 启用外设,除非在触发模式,其中启用是自动完成触发
  if (IS_TIM_SLAVE_INSTANCE(htim->Instance))
  {
    
    
    tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS;
    if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr))
    {
    
    
      __HAL_TIM_ENABLE(htim);
    }
  }
  else
  {
    
    
    __HAL_TIM_ENABLE(htim);
  }

  /* Return function status */
  return HAL_OK;
}

割り込み処理、割り込み関数は Core/Src/stm32f1xx_it.c に格納

// 定时器6总中断
void TIM6_IRQHandler(void)
{
    
    
  HAL_TIM_IRQHandler(&htim6);
      ->   if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)      // 判断是否为更新中断
          {
    
    
            if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET)    // 获取中断源也就是timer6
            {
    
    
              __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);                    // 清除中断标志位
              HAL_TIM_PeriodElapsedCallback(htim);                        // 调用更新中断处理函数,这函数为__weak弱函数,可重构
            }
          }
}


5. 結果のデモンストレーション

写真の説明を追加してください

おすすめ

転載: blog.csdn.net/weixin_43564241/article/details/129572285