iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 11
4
IoT

熟悉Arduino的Maker必看!30天帶你快速入門基於STM32嵌入式開發~系列 第 11

[Day 11]-【STM32系列】 Interrupts 中斷處理介紹篇(上)

我們今天要進入一個非常重要的主題,叫做Interrupt中斷,這對於在微處理機的設計甚至未來在OS的設計都有很大的關係,而且這是一個很重要的概念需要軟體和硬體配合,他才能做接下來這樣的工作。

什麼是中斷(Interrupts)?

Interrupts中文意思是中斷,所以一定跟事情被中斷、打斷有關嘛。
我舉一個例子吧,當你正在看電視,突然電話響起,於是你把手邊事情放下,接起電話,事情處理完然後回來繼續工作,這就是中斷(interrupts),而中斷源就是電話響起。

微控制器的 CPU 遇到中斷時,也會停下手邊工作,到指定的位置(接電話)執行一段程式,執行完之後再回來處理剛剛的工作。

很重要,當CPU發生中斷通常會做這幾個動作:

  1. 發生中斷
  2. 儲存目前 CPU 狀態,例如暫存器 (register)、程式計數器(program counter、PC) ,通常由硬體或 OS 完成
  3. 經由 IVT 查詢對應的 ISR 起始位址並跳至該處
  4. 完整執行 ISR
  5. 回復之前儲存的中斷點繼續執行原本的任務

中斷的定義:

中斷是指電腦在執行某一程式的過程中,由於電腦系統內、外的某種原因,而必須終止原程式的執行,轉去執行相應的處理程式,待處理結束之後,再回來繼續執行被終止的原程式過程。

我們甚麼時候需要用到中斷(Interrupts)?

https://ithelp.ithome.com.tw/upload/images/20200926/20120093OVg7Af0wya.png

想像你正在用電腦,可能一邊打著報告,一邊查資料,背景還在放音樂,是同時好多事情在處理。過去我們學習的方式都是用輪詢,如果用輪詢的方式同時進行這些程式可能會相當的複雜。所以我們需要認識中斷,那它可以幫助我們在同時多工的處理上,會相對起來必較方便。

Interrupts vs Polling

為甚麼我們需要中斷,我用一個簡單的例子解釋原因,在STM32L0 開發板上,有兩個LED和兩個按鈕。
假設我們要開發一個專案,如果我們按下左邊藍色按鈕,程式會點亮綠色LED,在之前的文章中,我們了解了如何控制GPIO的輸出以控制IO的High、Low變化,以及GPIO如何輸入以讀取IO的邏輯狀態。

有兩種方式我們能input按鈕目前的邏輯狀態,一種是輪詢(Polling),一種是中斷(Interrupts)。輪詢的方法就像你每隔幾秒鐘拿起電話來檢查你是否正在接到電話。中斷方法就像等待電話響起。哪種方法更加有效呢?毫無疑問的,是中斷方法更合適。你可以自由地做自己的事情,只有在電話響起時接起電話,

//輪詢(Polling)方法
while(1){
    read_button_input;
    if(pushed)
        exit;
}

這是一個例子將輪詢寫成程式,在while迴圈中,程式會不斷讀取按鈕的輸入,直到按鈕被按下,程式才離開while迴圈。接著點亮LED。輪詢的方法就是CPU不斷的去問,問你的按鈕輸入了嗎?問是否正在接到電話呢?直到按鈕被按下,LED才被點亮。顯而易見,輪詢的方法簡單但沒有效率。

//中斷(Interrupts)方法
interrupt_requestion(){
    turn_on_led;
    exit;
}

中斷比輪詢顯得有效率的多了,當按下按鈕,則會產生一個脈衝訊號,稱為中斷請求,CPU收到中斷請求後,將自動暫停執行原本執行的程式,並開始執行中斷的程式,中斷程序完成之後,處理器回到剛才被打斷的地方,繼續執行主程式,

在微控制器中,中斷的來源有很多,諸如 Reset, 外部中斷, Timer溢出可以中斷, USART接收傳輸資料可以中斷, ADC轉換完成可以中斷...等。

下面是Interrupts、Polling範例程式碼,使用輪詢和中斷當按鈕被按下,GreenLED點亮。

//輪詢(Polling)方法
#include "main.h"
#include "stm32l0xx_hal.h"

#define turn_on_LED HAL_GPIO_WritePin( GPIOA, GPIO_PIN_5, GPIO_PIN_SET)

uint8_t btn,pushed = 0;
uint8_t read_button_input(void){
	btn <<= 1;
	btn += HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13);
	btn &= 3;
	if(btn==2){ return 1;}
	return 0;
}


int main(void){

    while(1){
        pushed = read_button_input();
        if(pushed)
            exit;
    }
    turn_on_LED;
}

//中斷(Interrupts)方法
#include "main.h"
#include "stm32l0xx_hal.h"

#define turn_on_LED HAL_GPIO_WritePin( GPIOA, GPIO_PIN_5, GPIO_PIN_SET)

uint8_t btn,pushed = 0;
uint8_t read_button_input(void){
	btn <<= 1;
	btn += HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13);
	btn &= 3;
	if(btn==2){ return 1;}
	return 0;
}

extern TIM_HandleTypeDef htim6;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
    pushed = read_button_input();
    if(pushed) turn_on_LED;
}

int main(void){

HAL_TIM_Base_Start_IT(&htim6);

    while(1){
    }
}

相關連結


結語

今天到此謝謝大家。


上一篇
[Day 10]-【STM32系列】Difference between “timer” and “counter and introductions
下一篇
[Day 12]-【STM32系列】Interrupts 中斷處理應用篇(下)
系列文
熟悉Arduino的Maker必看!30天帶你快速入門基於STM32嵌入式開發~30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
tony287782
iT邦新手 5 級 ‧ 2021-08-08 02:09:01

請問read_button_input裡面做的事是什麼?
為何不用 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)判斷button狀態就好?
感謝

我要留言

立即登入留言