第二節: 外部中斷學習(用CubeMX學習STM32)


STM32外部中斷


《用CubeMX學習STM32》

注釋 點擊上面藍字進入完整專欄,這個系列所有文章都會整合到這個專欄


STM32外部中斷

前言: 關於中斷簡單介紹

中斷的流程:

中斷流程圖:
在這里插入圖片描述

中斷方式傳送數據具有可以有效提高單片機工作效率, 適合於實時控制系統等優點, 相對於查詢方式更為常用。

當CPU處理某件事情的時候, 外部發生的某一事件(如電平的改變、脈沖邊沿跳變、定時器/計數器溢出等)請求CPU迅速處理, 於是CPU暫時中斷當前的工作, 轉去處理發生的事件。 處理完該事件后, 再回到原來中斷處, 繼續工作。 這樣的過程稱為中斷 上圖為中斷流程圖

這個中斷的概念是不是有點晦澀難懂? 主要是這個是書上的內容, 所以不是很形象. 我再解釋一遍:想象一個場景,

1、當有一天你正在和川建國同志吃飯(你和他吃飯這個事情就是主程序);
2、突然有個電話打給你, 說有個十五億的小單子需要你去處理一下(這件事就是中斷源),
3、 你停止吃飯, 川建國同志在這等你, 你去處理你的十五億小合同(就是響應中斷請求, 簽合同過程就是中斷服務程序),
4、處理完合同之后你又回到餐桌繼續和他就餐(這就是返回主程序, 然后繼續執行主程序).

這樣解釋是不是清晰一點.

在這里插入圖片描述

   關於STM32F407的中斷介紹可以看一下原子的或者火哥的pdf, 如果實在看得下去, 看官方手冊也行。 這里就不贅述, 通過Cube配置以及編程過程理解這個外部中斷會好很多, 通過現象再回去看本質

   同樣的, 還使用前面兩篇博客所用到的工程即可, 也可以自己新建一個, 當做對自己的測試

2-1. 使用核心板自帶按鍵

操作簡介 :    通過板子上的兩個按鈕控制LED燈的亮滅 WK_UP按鍵按下則進入中斷, 並翻轉LED0的狀態, KEY0按下時翻轉LED1的狀態. 兩者雖然功能一樣, 但卻有質的區別

   這里要做的和按鍵那一篇一樣, 只是把其中一個按鍵改為中斷, 而不是作為GPIO_input 所以可以看完上一篇直接看這一篇繼續。 點擊下方藍字可以看上一篇的博客

第一節補充: 按鍵操作(CubeMX加HAL庫學STM32系列)


Step1 <CubeMX配置>


RCC&SYS配置這些都不用動, 時鍾樹的配置也不用動

(1) RCC&SYS以及時鍾樹配置不用改變

在這里插入圖片描述
在這里插入圖片描述

(2)更改一下PA0引腳配置:

把WKUP按鍵對應的PA0引腳模式由GPIO_input改為GPIO_EXIT0, 再把GPIO的配置更改一下即可 具體操作見下圖

注 : 如果是用的原來的工程, 只改這個即可, 其他的LED引腳和按鍵引腳不用動, 如果是自己又新建了一個工程, 那其他引腳按照前面兩篇的介紹配置, 然后這個PA0按照這一篇配置就好了, 問題不大

在這里插入圖片描述

對應GPIO配置改為下圖

在這里插入圖片描述

(3)中斷NVIC配置

我們設置了中斷, 在NVIC里面要記得使能PA0引腳的中斷

在這里插入圖片描述

NVIC ( Nested Vectored Interrupt Controller ) : 中斷向量控制器

在中斷向量表里面使能EXIT line0中斷

關於搶占優先級和子優先級: 當你使用多個中斷的時候會用到這個。 就是為了防止多個中斷沖突, 所以需要給他們每個中斷排個號, 就不會亂了。 搶占優先級高的先執行, 若搶占優先級相同, 再看子優先級

(4)以上配置完之后就可以Generate CODE


Step2 <程序編寫>


(1) 中斷服務函數

stm32f4xx_it.c 這個文件里面看到我們要用的中斷服務函數
我們要在中斷里面做什么事情, 就要寫在中斷服務函數里面, 然后中斷到來之后, 單片機就回去處理中斷服務函數里面的工作

在這里插入圖片描述
這個函數里面調用了 HAL_GPIO_EXTI_IRQHandler() 這個函數, 這個函數是處理GPIO外部中斷的函數 可以看到里面的參數是GPIO_PIN_0, 因為我們用的是PA0即GPIOA的0引腳

Go to definition 一下, 可以看這個函數的定義

/**
  * @brief  This function handles EXTI interrupt request. // 這個功能是處理外部中斷請求
  * @param  GPIO_Pin Specifies the pins connected EXTI line // GPIO_Pin指定連接EXTI線的引腳
  * @retval None    // 無返回值
  */
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);     // 清除這個引腳的中斷標識位
    HAL_GPIO_EXTI_Callback(GPIO_Pin);       // 回調外部中斷
  }
}

綜上: 中斷服務函數最終會執行中斷回調函數 HAL_GPIO_EXTI_Callback()

(2) 中斷回調函數

中斷回調函數如下圖 這個函數是空的, 所以我們可以自己重構這個函數, 在它內部實現我們要做的功能

在這里插入圖片描述

我們需要重構中斷回調函數

在main.c里面寫入我們的代碼 :

提示 : 不要忘了把代碼寫在 /* USER CODE BEGIN / / USER CODE END */ 之間

在這里插入圖片描述

/* USER CODE BEGIN 0 */
// 重構中斷回調函數  
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	// 判斷是否為WKUP引腳(即GPIO_PIN_0)進入中斷
	if (WKUP_Pin == GPIO_Pin)
	{
		HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin); // 翻轉LED0的的電平狀態
		/* 	下面這一句話與上面一句是等價的, 因為LED0是我們給這個引腳起的別名, 在main.h文件里面有對應的宏定義	    */
		//HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10); 
	}
}

/* USER CODE END 0 */

(3) 主函數

在主函數里面用KEY0做一個一樣的功能, 作為對比

在這里插入圖片描述

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

    /* USER CODE BEGIN 3 */
	// 在while(1)里面循環掃描, 判斷讀取的按鍵引腳狀態
	// 下面掃描KEY0按鍵的引腳信號
    	if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET)
		{
			HAL_Delay(10);	// 延時10ms, 做一個軟件的消抖, 防止因抖動而檢測到按鍵按下
			if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET)
			{
			// 做一個松手檢測, 若KEY0一直是RESET(低電平),則一直在死循環
			// 當KEY0位SET才會跳出,進而繼續執行下面的對 LED1 的操作
			while(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET);
			HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
		    }
	    }
  }
  /* USER CODE END 3 */

(4) 編譯下載到單片機, 看看單片機什么反應

在這里插入圖片描述

左邊的紅色按鍵是WKUP, 左邊的藍色LED是LED0

在這里插入圖片描述


仔細看一下動圖中的效果可以發現, 中斷的WKUP按鍵的功能並不是很完美, 這是因為沒有消抖導致的, 在中斷里面加個軟件消抖的程序就可以了。

此外, 雖然兩種方式實現的功能是一樣的, 但是他們的區別就在於, KEY0翻轉LED狀態實在while(1)循環里面做的,   這就相當於主函數里面一直循環掃描這個按鍵的狀態, 比較耗費資源.

而WKUP按鍵按下翻轉LED是在中斷里面做的,不影響主函數里面做其他事情. 如果以后做的東西要求寫很多代碼, 最好多多利用中斷,這樣會更高效。只有當事情來了CPU再去處理,其他時間主函數里面正常做其他事情。 這樣既能提高MCU效率, 也不會讓自己的代碼全部寫成一坨在主函數里面


破曉之日, 你的所有努力都會助你看到黎明的第一縷陽光。
請堅信: 你是一道光, 也是一把劍 ! 你終將刺破寒冰和黑夜, 重新定義你的人生 !

Author : 李光輝
date : Sun Dec 29 20:54:17 CST 2019
blog ID: Kevin_8_Lee
blog site : https://blog.csdn.net/Kevin_8_Lee/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM