STM32CubeMX學習筆記(5)——基本定時器接口使用

一溉卓、定時器簡介

STM32F1 系列中,除了互聯(lián)型的產(chǎn)品搬泥,共有 8 個定時器的诵,分為基本定時器,通用定時器和高級定時器佑钾。
基本定時器 TIM6TIM7 是一個 16 位的只能向上計數(shù)的定時器西疤,只能定時,沒有外部 IO休溶。
通用定時器 TIM2/3/4/5 是一個 16 位的可以向上/下計數(shù)的定時器代赁,可以定時,可以輸出比較兽掰,可以輸入捕捉芭碍,每個定時器有四個外部 IO。
高級定時器 TIM1/8 是一個 16 位的可以向上/下計數(shù)的定時器孽尽,可以定時窖壕,可以輸出比較,可以輸入捕捉杉女,還可以有三相電機互補輸出信號瞻讽,每個定時器有 8 個外部 IO。

二熏挎、新建工程

1. 打開 STM32CubeMX 軟件速勇,點擊“新建工程”

2. 選擇 MCU 和封裝

3. 配置時鐘
RCC 設(shè)置,選擇 HSE(外部高速時鐘) 為 Crystal/Ceramic Resonator(晶振/陶瓷諧振器)


選擇 Clock Configuration坎拐,配置系統(tǒng)時鐘 SYSCLK 為 72MHz
修改 HCLK 的值為 72 后烦磁,輸入回車养匈,軟件會自動修改所有配置

4. 配置調(diào)試模式
非常重要的一步,否則會造成第一次燒錄程序后續(xù)無法識別調(diào)試器
SYS 設(shè)置都伪,選擇 Debug 為 Serial Wire

5. 配置GPIO
GPIO 設(shè)置呕乎,在右邊圖中找到 LED 燈對應引腳,選擇 GPIO_Output陨晶,輸出低電平點亮猬仁,可以添加自定義標簽


三、TIM6基本定時器

3.1 參數(shù)配置

Timers 中選擇 TIM6 設(shè)置珍逸,并勾選 Activated 激活

Parameter Settings 進行具體參數(shù)配置逐虚。

Tclk 即內(nèi)部時鐘CK_INT聋溜,經(jīng)過APB1預分頻器后分頻提供谆膳,如果APB1預分頻系數(shù)等于1,則頻率不變撮躁,否則頻率乘以2漱病,庫函數(shù)中APB1預分頻的系數(shù)是2,即PCLK1=36M把曼,如圖所以定時器時鐘Tclk=36*2=72M杨帽。

定時器溢出時間:

Tout = 1 / (Tclk / (psc + 1)) ? (arr + 1)

  • 定時器時鐘Tclk:72MHz
  • 預分頻器psc:71
  • 自動重裝載寄存器arr:999

即 Tout = 1/(72MHz/(71+1))?(999+1) = 1ms

  • Prescaler(時鐘預分頻數(shù)):72-1 則驅(qū)動計數(shù)器的時鐘 CK_CNT = CK_INT(即72MHz)/(71+1) = 1MHz
  • Counter Mode(計數(shù)模式):Up(向上計數(shù)模式) 基本定時器只能是向上計數(shù)
  • Counter Period(自動重裝載值):1000-1 則定時時間 1/CK_CLK*(999+1) = 1ms
  • auto-reload-preload(自動重裝載):Enable(使能)
  • TRGO Parameters(觸發(fā)輸出):不使能 在定時器的定時時間到達的時候輸出一個信號(如:定時器更新產(chǎn)生TRGO信號來觸發(fā)ADC的同步轉(zhuǎn)換)

3.2 配置NVIC

使能定時器中斷


3.3 生成代碼

輸入項目名和項目路徑


選擇應用的 IDE 開發(fā)環(huán)境 MDK-ARM V5

每個外設(shè)生成獨立的 ’.c/.h’ 文件
不勾:所有初始化代碼都生成在 main.c
勾選:初始化代碼生成在對應的外設(shè)文件。 如 GPIO 初始化代碼生成在 gpio.c 中嗤军。

點擊 GENERATE CODE 生成代碼

3.4 修改中斷回調(diào)函數(shù)

打開 stm32f1xx_it.c 中斷服務(wù)函數(shù)文件注盈,找到 TIM6 中斷的服務(wù)函數(shù) TIM6_IRQHandler()
中斷服務(wù)函數(shù)里面就調(diào)用了定時器中斷處理函數(shù) HAL_TIM_IRQHandler()

打開 stm32f1xx_hal_tim.c 文件,找到定時器中斷處理函數(shù)原型 HAL_TIM_IRQHandler()叙赚,其主要作用就是判斷是哪個定時器產(chǎn)生哪種事件中斷老客,清除中斷標識位,然后調(diào)用中斷回調(diào)函數(shù) HAL_TIM_PeriodElapsedCallback()震叮。

/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
這個函數(shù)不應該被改變胧砰,如果需要使用回調(diào)函數(shù),請重新在用戶文件中實現(xiàn)該函數(shù)苇瓣。

HAL_TIM_PeriodElapsedCallback() 按照官方提示我們應該再次定義該函數(shù)尉间,__weak 是一個弱化標識,帶有這個的函數(shù)就是一個弱化函數(shù)击罪,就是你可以在其他地方寫一個名稱和參數(shù)都一模一樣的函數(shù)哲嘲,編譯器就會忽略這一個函數(shù),而去執(zhí)行你寫的那個函數(shù)媳禁;而 UNUSED(htim) 撤蚊,這就是一個防報錯的定義,當傳進來的定時器號沒有做任何處理的時候损话,編譯器也不會報出警告侦啸。其實我們在開發(fā)的時候已經(jīng)不需要去理會中斷服務(wù)函數(shù)了槽唾,只需要找到這個中斷回調(diào)函數(shù)并將其重寫即可而這個回調(diào)函數(shù)還有一點非常便利的地方這里沒有體現(xiàn)出來,就是當同時有多個中斷使能的時候光涂,STM32CubeMX會自動地將幾個中斷的服務(wù)函數(shù)規(guī)整到一起并調(diào)用一個回調(diào)函數(shù)庞萍,也就是無論幾個中斷,我們只需要重寫一個回調(diào)函并判斷傳進來的定時器號即可忘闻。

接下來我們就在 stm32f1xx_it.c 這個文件的最下面添加 HAL_TIM_PeriodElapsedCallback()

/* USER CODE BEGIN 1 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    static uint32_t time = 0;
    if(htim->Instance == TIM6)  // 定時器6基地址
    {
        // 自定義應用程序
        time++;           // 每1ms進來1次
        if(time == 1000)  // 每1秒LED燈翻轉(zhuǎn)一次
        {
            HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);
            time = 0;
        }
    }
}
/* USER CODE END 1 */

3.5 添加定時器啟動函數(shù)

現(xiàn)在進入 main 函數(shù)并在 while 循環(huán)前加入開啟定時器函數(shù) HAL_TIM_Base_Start_IT()钝计,這里所傳入的 htim6 就是剛剛定時器初始化后的結(jié)構(gòu)體。

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM6_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim6);  
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

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

現(xiàn)在實驗現(xiàn)象是每1秒LED燈翻轉(zhuǎn)一次

3.6 HAL庫與標準庫代碼比較

STM32CubeMX 使用 HAL 庫生成的代碼:

/**
  * @brief TIM6 Initialization Function
  * @param None
  * @retval None
  */
static 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 = 72-1;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 1000-1;
  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 */
}

/**
  * @brief This function handles TIM6 global interrupt.
  */
void TIM6_IRQHandler(void)
{
  /* USER CODE BEGIN TIM6_IRQn 0 */

  /* USER CODE END TIM6_IRQn 0 */
  HAL_TIM_IRQHandler(&htim6);
  /* USER CODE BEGIN TIM6_IRQn 1 */

  /* USER CODE END TIM6_IRQn 1 */
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    static uint32_t time = 0;
    if(htim->Instance == TIM6)
    {
        // 自定義應用程序
        time++;
        if(time == 1000)
        {
            HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);
            time = 0;
        }
    }
}

HAL_TIM_Base_Start_IT(&htim6); 

使用 STM32 標準庫的代碼:

/**
 @brief 定時器中斷配置(使用TIM6基本定時器)
 @param 無
 @return 無
*/
void BASIC_TIM_Config(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    /*
    可以從上圖看出基本定時器和通用定時器使用APB1總線,
    高級定時器使用APB2總線齐佳。
    */
    // 開啟定時器時鐘,即內(nèi)部時鐘 CK_INT=72M
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

    /*
    預分頻將輸入時鐘頻率按1~65536之間的值任意分頻,分頻值決定了計數(shù)頻率私恬。
    計數(shù)值為計數(shù)的個數(shù),當計數(shù)寄存器的值達到計數(shù)值時,產(chǎn)生溢出,發(fā)生中斷。
    如系統(tǒng)時鐘為72MHz,預分頻 TIM_Prescaler = 71,
    計數(shù)值 TIM_Period = 1000,
    則 TIM_Period * (TIM_Prescaler + 1) / 72000000 = 0.001,
    即每1ms產(chǎn)生一次中斷炼吴。
    */
    // 自動重裝載寄存器周的值(計數(shù)值)
    TIM_TimeBaseStructure.TIM_Period = 1000;
 
    // 累計 TIM_Period 個頻率后產(chǎn)生一個更新或者中斷
    // 時鐘預分頻數(shù)為 71本鸣,
    // 則驅(qū)動計數(shù)器的時鐘 CK_CNT = CK_INT / (71+1)=1M
    TIM_TimeBaseStructure.TIM_Prescaler = 71;

    // 時鐘分頻因子 ,基本定時器沒有硅蹦,不用管
    //TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;

    // 計數(shù)器計數(shù)模式荣德,基本定時器只能向上計數(shù),沒有計數(shù)模式的設(shè)置
    //TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;

    // 重復計數(shù)器的值童芹,基本定時器沒有涮瞻,不用管
    //TIM_TimeBaseStructure.TIM_RepetitionCounter=0;

    /*
    完成時基設(shè)置
    */
    // 初始化定時器
    TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);

    /*
    為了避免在設(shè)置時進入中斷,這里需要清除中斷標志位。
    如果是向上計數(shù)模式(基本定時器采用向上計數(shù)),
    則采用函數(shù) TIM_ClearFlag(TIM6, TIM_FLAG_Update),
    清除向上溢出中斷標志假褪。
    */
    // 清除計數(shù)器中斷標志位
    TIM_ClearFlag(TIM6, TIM_FLAG_Update);

    // 使能計數(shù)器
    TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);

    // 開啟計數(shù)器
    TIM_Cmd(TIM6, ENABLE);

    // 暫時關(guān)閉定時器的時鐘署咽,等待使用
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, DISABLE);
}

/**
 @brief NVIC初始化(使用TIM6基本定時器)
 @param 無
 @return 無
*/
void BASIC_TIM_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    // 設(shè)置中斷組為 0
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    // 設(shè)置中斷來源
    NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn ;
    // 設(shè)置主優(yōu)先級為 0
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    // 設(shè)置搶占優(yōu)先級為 3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

#define BASIC_TIM_IRQHandler TIM6_IRQHandler
// 1ms發(fā)生一次中斷,time 記錄中斷次數(shù)
uint16_t time;

void BASIC_TIM_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
    {
        time++;
        TIM_ClearITPendingBit(TIM6, TIM_FLAG_Update);
    }
}

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

MX_TIM6_Init(); 對應 BASIC_TIM_Config();BASIC_TIM_NVIC_Config();
HAL_TIM_Base_Init(&htim6) 對應 TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure)
HAL_TIM_Base_Start_IT(&htim6); 對應 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

四、注意事項

用戶代碼要加在 USER CODE BEGIN NUSER CODE END N 之間生音,否則下次使用 STM32CubeMX 重新生成代碼后宁否,會被刪除。


? 由 Leung 寫于 2021 年 1 月 14 日

? 參考:STM32CubeMX系列教程3:基本定時器
    STM32CubeMX實戰(zhàn)教程(四)——基本定時器(還是點燈)
    《嵌入式-STM32開發(fā)指南》第二部分 基礎(chǔ)篇 - 第4章 定時器(HAL庫)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末久锥,一起剝皮案震驚了整個濱河市家淤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瑟由,老刑警劉巖絮重,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異歹苦,居然都是意外死亡青伤,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門殴瘦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來狠角,“玉大人,你說我怎么就攤上這事蚪腋》岣瑁” “怎么了姨蟋?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長立帖。 經(jīng)常有香客問我眼溶,道長,這世上最難降的妖魔是什么晓勇? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任堂飞,我火速辦了婚禮,結(jié)果婚禮上绑咱,老公的妹妹穿的比我還像新娘绰筛。我一直安慰自己,他們只是感情好描融,可當我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布铝噩。 她就那樣靜靜地躺著,像睡著了一般稼稿。 火紅的嫁衣襯著肌膚如雪薄榛。 梳的紋絲不亂的頭發(fā)上讳窟,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天让歼,我揣著相機與錄音,去河邊找鬼丽啡。 笑死谋右,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的补箍。 我是一名探鬼主播改执,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼坑雅!你這毒婦竟也來了辈挂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤裹粤,失蹤者是張志新(化名)和其女友劉穎终蒂,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體遥诉,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡拇泣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了矮锈。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片霉翔。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖苞笨,靈堂內(nèi)的尸體忽然破棺而出债朵,到底是詐尸還是另有隱情子眶,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布序芦,位于F島的核電站壹店,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏芝加。R本人自食惡果不足惜硅卢,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望藏杖。 院中可真熱鬧将塑,春花似錦、人聲如沸蝌麸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽来吩。三九已至敢辩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間弟疆,已是汗流浹背戚长。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留怠苔,地道東北人同廉。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像柑司,于是被迫代替她去往敵國和親迫肖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容