定時器TIM配置微妙延時函數
文章目錄
開胃小菜(BOOT0、BOOT1)
在STM32系列微控制器中,Boot0和Boot1是兩個用于 選擇啟動模式 的引腳。
主要功能是決定芯片啟動時加載哪個存儲區域的代碼
這兩個引腳的狀態組合決定了微控制器從哪個內存位置開始執行代碼,從而影響啟動過程和運行的固件。
Boot0
這個引腳通常用于選擇啟動模式。
例如,在STM32F103RCT6芯片中
如果Boot0引腳被拉高(通常連接到VCC),則微控制器將從Flash存儲器啟動;
如果Boot0引腳被拉低(通常連接到GND),則將從SRAM啟動。
這是一種常見的配置,但具體行為可能會根據不同的STM32系列略有變化,所以最好查閱相應芯片的數據手冊以獲取準確信息。
Boot1(如果有)
有些STM32芯片可能還有一個Boot1引腳,用于進一步擴展啟動模式的選擇。
結合Boot0和Boot1的不同電平狀態,可以選擇從不同的存儲介質啟動,如系統存儲器、用戶閃存或其他。
不同STM32芯片上有不同的配置和選項,Boot0和Boot1的功能,需要查看該芯片的參考手冊或數據表來確定
三種定時器
stm32f103芯片一般包含了以下類型的定時器:
高級控制定時器(TIM1,TIM8)
STM32F1系列微控制器中功能最強大的定時器,通常用于電機控制等高級應用,支持多達4路的PWM輸出、捕獲和比較模式等多種功能。高級控制定時器可以實現復雜的波形生成和電機控制策略,如PID控制、死區時間設置等。
通用定時器(TIM2, TIM3, TIM4, TIM5)
通用定時器是最常用的定時器類型,適用于多種用途,可以用于生成脈沖寬度調制(PWM)信號(PWM輸出、輸入捕獲和輸出比較)、計數外部事件等。通用定時器通常具有多個通道,每個通道都可以獨立地進行配置和使用。
基本定時器(TIM6, TIM7)
基本定時器相對簡單,通常用于 簡單的計數 或產生基本的 時間延遲 。它們的功能不如通用定時器豐富,但在一些簡單的應用場合非常有用。
TIM6配置Delay_us()
采用的是stm32f103芯片,8M外接晶振,所以系統時鐘為72MHz。
使用軟件stm32cubeode
.IOS 配置如下:
Prescaler-------------------分頻系數
Counter Mode------------計數模式(方向)
Counter Period ----------重裝載值
auto-reloadpreload------自動重載預載
Prescaler (分頻系數)
設置適當的預分頻系數,可以調整定時器計數器的時鐘頻率,從而改變定時器計數的速度。
確保定時器以所需的頻率進行計數,這對于生成精確的時間延遲或周期性事件至關重要。
比如說,上面設置的是72分頻,已知系統時鐘頻率是 72 M H z 72MHz 72MHz
所以定時器時鐘就是 72 M H z / 72 = 1 M H z 72MHz/72 = 1MHz 72MHz/72=1MHz ,即 定時器每計數一次耗時 1 u s 1us 1us
Counter Mode (計數模式)
在大多數定時器中,計數模式可以是 向上計數 、向下計數 或 雙向計數 。
這決定了定時器計數器的計數方向。
選擇正確的計數模式對于滿足特定應用的需求非常重要。
向上計數:從0開始計數到65535
向下計數:從65535開始計數到0
雙向計數:計數器從一個設定的值開始,向上計數到最大值,然后向下計數到最小值,如此循環。
雙向計數通常用于需要測量周期性事件或信號的頻率和持續時間
Counter Period (重載值)
定時器計數器在達到該值后產生事件(如中斷或復位)的周期長度。
設置合適的重載值定義了定時器計數器的周期,這可以用于生成特定的時間間隔或頻率。
通俗來講
向上計數:計數器從0開始計數,計數到65535(重載值),就會觸發事件。
向下計數:計數器從65535(重載值)開始計數,計數到0,就會觸發事件。
auto-reload preload (自動重載預載)
當設置此功能時,每當計數器達到預設的重載值(65535)時,它會自動重新加載預設值(65535),從而使定時器能夠無縫地繼續計數。這允許定時器持續運行,無需軟件干預,適用于需要連續或周期性操作的應用。
代碼
設置分頻系數,由于初始化的時候已經設置好了,這里可以不設置了;
設置重裝載值,寫延時函數的話,
向上計數這一行絕對不能要
向下技術根據實際情況來設置
寫定時器中斷服務函數也需要
部分博主無腦搬運,工程師們可要仔細辨認
計數值歸零,實際上就是將0賦值給計數器的初始值
可以F12跳轉到宏定義
/*** @brief Set the TIM Counter Register value on runtime.* @param __HANDLE__ TIM handle.* @param __COUNTER__ specifies the Counter register new value.* @retval None*/
#define __HAL_TIM_SET_COUNTER(__HANDLE__, __COUNTER__) ((__HANDLE__)->Instance->CNT = (__COUNTER__))
實際上就是一個賦值
寫成這樣也可以
__HAL_TIM_SET_COUNTER(&htim6,0);//把定時器計數值歸零
開啟定時器,獲取計數值,如果計數值達到輸入 u s us us 次,則關閉定時器
__HAL_TIM_GET_COUNTER(&htim6) //獲取計數值
重要問題
為什么向上計數時 第201行 不能要?
舉個例子:
比如我輸入的是1000,也就是Timer6_Delay_us(1000);(即us = 1000;)
我們看看這個函數的原型
/*** @brief Set the TIM Autoreload Register value on runtime without calling another time any Init function.* @param __HANDLE__ TIM handle.* @param __AUTORELOAD__ specifies the Counter register new value.* @retval None*/
#define __HAL_TIM_SET_AUTORELOAD(__HANDLE__, __AUTORELOAD__) \do{ \(__HANDLE__)->Instance->ARR = (__AUTORELOAD__); \(__HANDLE__)->Init.Period = (__AUTORELOAD__); \} while(0)
倒數第二行
(__HANDLE__)->Init.Period = (__AUTORELOAD__); \
Period 是不是很眼熟?-------->重裝載值!!!
也就是將重裝載值設置成了999(1000-1),每次計數到999,就會從0重新開始
也就是計數值最大只能到達999(1000-1)
再看跳出 while 循環的條件
while(1){Count = __HAL_TIM_GET_COUNTER(&htim6);if(Count > us)break;}
這里的計數值 Count 最大值只能到達999(1000-1),而我們輸入的 u s us us == 1000;
那么這個循環就無法終止也就是為什么卡死在這的原因
為什么一開始用著也沒什么事呀?運氣好唄,沒什么干擾
簡單粗暴的毫秒延時,取別名
PS:定時器中斷服務函數
前面說了,如果需要使用定時器中斷服務函數,就需要 第201行 或者 提前就設置好重裝載值
什么意思呢?
向上計數,從0計數到重裝載值,就會自動觸發 定時器中斷服務函數
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim == &htim7) //判斷是哪個定時器請求的中斷 在這個函數里可以if判斷多個定時器請求的中斷{//觸發事件}
}
H A L HAL HAL 庫提供了一個回調函數 HAL_TIM_PeriodElapsedCallback
當定時器的周期完成時,這個回調函數會被調用,觸發事件。
即計數器的值達到了自動重載寄存器 ARR 的值并發生溢出或更新事件
這個函數通常在定時器的中斷服務例程中被調用,允許用戶執行一些事件
參數 htim 是一個指向 TIM_HandleTypeDef
結構體的指針,包含了定時器的控制和狀態信息。
這個回調函數通常用于處理定時器周期到達時的中斷服務例程(ISR)。
┈┈┈┈▕▔╲┈┈┈┈┈┈┈ ┈┈┈┈▕▔╲┈┈┈┈┈┈┈ ┈┈┈┈▕▔╲┈┈┈┈┈┈┈┈
┈┈┈┈┈▏▕┈┈┈┈┈┈┈ ┈┈┈┈┈▏▕┈┈┈┈┈┈┈ ┈┈┈┈┈▏▕┈┈┈┈┈┈┈ ┈
┈┈┈┈┈▏ ▕▂▂▂▂▂┈┈┈┈┈┈┈▏ ▕▂▂▂▂▂┈┈┈┈┈┈┈▏ ▕▂▂▂▂▂┈┈┈
▂▂▂▂╱┈┈▕▂▂▂▂▏┈ ▂▂▂▂╱┈┈▕▂▂▂▂▏┈ ▂▂▂▂╱┈┈▕▂▂▂▂▏┈┈
▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈ ▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈ ▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈
▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈ ▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈ ▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈
▔▔▔▔╲▂▂▕▂▂▂▂▏┈ ▔▔▔▔╲▂▂▕▂▂▂▂▏┈ ▔▔▔▔╲▂▂▕▂▂▂▂▏┈┈