iT邦幫忙

2021 iThome 鐵人賽

DAY 14
0
Arm Platforms

STM32 基礎入門教學系列 第 15

【Day15】:STM32輾壓Arduino的功能—TIM(下)

TIMER+NVIC中斷

今天我們來使用Timer的中斷功能吧!
設定與昨天大致相同,只是我們現在需要開啟中斷。
https://ithelp.ithome.com.tw/upload/images/20210907/2014152519H82QVcKI.jpg
另外要注意的是什麼時候會進中斷
https://ithelp.ithome.com.tw/upload/images/20210907/201415259JfLcZbMDZ.png
在不同的模式下進中斷的時機不同,上數與下數都是在一個周期的最後進入,而中心對齊則是數到頭尾都會進入中斷。

小程式1-實作Counter

我們來自己實作一個counter來計時,利用中斷的方式,設置PSC=15,ARR=1000,當這個counter數到1000的時候就會進入中斷,稍微計算一下就可以知道每1ms會進入一次中斷(PSC將時鐘訊號降低1/16,變成1MHz,1000次會進入中斷,又變為1kHz)。我們宣告兩個變數,ms與sec,分別為毫秒與秒。當每次進入中斷就把ms++,只要ms=1000代表經過1s了,我們就將ms歸零,sec加一。實際程式碼如下

程式碼

HAL_TIM_Base_Start_IT(&htim2);

這一行程式碼是不是與上次很相似啊,只是這次尾端加上了"IT",意思為interrupt,

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim){
	if(htim->Instance == TIM2){
		ms++;
		if(ms==1000){
			ms = 0;
			sec++;
		}

	}
}

這一段函式其實在tim.c當中已經被定義過了,而我們這邊是重新定義這個函式,可以在以下的地方打開這個檔案直接搜尋這個函式
https://ithelp.ithome.com.tw/upload/images/20210907/201415256fHcaCWEKd.jpg
函式內容如下
https://ithelp.ithome.com.tw/upload/images/20210907/20141525V8RhmAvmzX.jpg
函式的開頭有__weak,用在函式前,代表這個函式是弱定義,當你的程式碼其他地方有對這個函式就其他地方做定義,就會以新的定義為主,那有人可能會問,這樣他定義這個有什麼用呢?
就是給你複製的...通常不熟悉的人很難記住函式的API,照著打出來,因此你可以先到tim.c當中找到這些程式碼,直接複製到main.c當中,就可以直接使用了。

由於上述兩段程式碼分別在程式的不同地方,直接附上整段程式碼看起來會非常的亂,讀者可能也難以理解,因此以下會直接說明這兩段程式碼的位置

第一段程式碼放在main裡面不需要放在迴圈當中,他不需要被重複的執行,只要start一次就可以了。
第二段程式碼就是放在一般函式定義的地方,因此在main以外的任何地方都可以,我通常習慣放在底下的Begin和End之間,接近程式碼尾端的位置。
記得要新增sec與ms兩個全域變數,才能使用現場表達式監看喔

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

了解程式碼的原理就寫好完整的程式碼執行看吧,應該可以利用現場表達式的功能看到ms與sec兩個變數,看會不會如預期的一樣sec會每秒增加1囉。

小程式2-實作HAL_Delay微秒級版本

第二個小程式我們要來實作微秒級的delay,函式庫裡的HAL_Delay()只能實現毫秒級的delay。
這個實作不會用到中斷,只會需要再介紹一個新的函式!

昨天我們講過底下這個函式可以獲得現在counter數到的值,

__HAL_TIM_GET_COUNTER()

另一個函式可以設定counter的值,這個函式一樣是用#define的方式定義的,我們可以在tim.h的文件中找到。

__HAL_TIM_SET_COUNTER()

實作delay的思路是,每次呼叫這個函式我們就將counter的值歸零,然後讓程式進到一個while的迴圈當中,只要counter的值小於傳進來的參數,就繼續在迴圈執行,大於等於時則跳出迴圈,這樣就可以讓程式卡在這個地方不繼續持行下去,達到delay的效果。底下為這個函式的設計:

void microDelay(int t){
	__HAL_TIM_SET_COUNTER(&htim2,0);
	while(__HAL_TIM_GET_COUNTER(&htim2) < t){
	}
}

我們再另外設計一個小程式來檢測我們的microDelay(),到底有沒有成功delay
在while迴圈當中,每次延遲1000微秒,再把ms加一,而當ms等於1000,sec加1,這部分的思路與第一個實作很類似。

/* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  microDelay(1000);
	  ms++;
	  if(ms==1000){
		  sec++;
		  ms=0;
	  }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

一樣記得在全域宣告ms與sec兩個變數
執行後的結果應該要與小實作一相同,不過我們一個是利用中斷,一個是利用實作微秒級的delay來達成。

小結

這兩天介紹了TIM最最最基本的功能以及幾個函式。我們再來複習一次吧!程式開始都一定要讓TIMER啟用,而要啟用中斷的函式與一般的啟動函式略有不同

  1. HAL_TIM_Base_Start();
  2. HLA_TIM_Base_Start_IT();
    另外我們也介紹了兩個利用define來定義的函式
  3. __HAL_TIM_GET_COUNTER()
  4. __HAL_TIM_SET_COUNTER()
    這兩個函式可以獲得CNT的值

上一篇
【Day14】:STM32輾壓Arduino的功能—TIM(上)
下一篇
【Day16】:Counter的硬體實現
系列文
STM32 基礎入門教學30

尚未有邦友留言

立即登入留言