>[success] **技術支持說明**
> 1.**客服**提供簡單的技術支持,一般自主學習為主
> 2.可到官方問答社區中提問:[**去提問**](https://bbs.csdn.net/forums/nb-iot)
> 3.工程師**會盡快**解答社區問題,但他們是一線開發,【**難以保證**】解答時效,解答辛苦,感謝理解!
<br/>
## **什么是中斷**
通俗地說,中斷是指程序在常規運行時突然遇到一個緊急事件,需要先放下當前的工作去處理這個緊急的事件。我們通過一張邏輯圖來理解一下這個過程:

###
如圖所示,CPU在執行主程序的過程中,在斷點處遇到一個緊急事件了。這個緊急事件請求CPU中斷主程序,并且去處理這個緊急事件。CPU執行中斷處理程序來處理這個緊急事件,這個過程稱為中斷響應。處理完這個緊急事件后,返回至主程序中并且繼續執行主程序。
<br/>
**中斷優先級**與**中斷向量**
* **中斷優先級**:當有多個中斷同時發生時,應該優先處理哪個中斷呢?我們可以給每個中斷定義一個優先級,以解決這個問題。
* **中斷向量**:不同類型的中斷需要不同類型的中斷處理程序來處理,例如用戶突然按下一個按鍵、計時結束等都需要使用不同的中斷處理程序來處理。中斷向量的作用是保證當發生不同類型的中斷時能夠進入對應的中斷處理程序。
<br/>
## **重新設計按鍵 HAL API**
一般地,用戶按下按鍵時,對于CPU來說就是一個緊急事件,因為CPU需要放下當前工作去處理它。因此,這非常使用使用中斷來處理按鍵事件。
###
接下來只需簡單修改一下上節課的工程代碼,便可使其支持中斷機制。打開本節課配套工程代碼的
hal_button.h文件,代碼如下:
```
#ifndef __HAL_BUTTON_H__
#define __HAL_BUTTON_H__
/*定義按鍵連接的GPIO口PA0*/
#define HAL_BUTTON_PORT GPIOA
#define HAL_BUTTON_PIN GPIO_Pin_0
/*定義GPIOA對應的時鐘 */
#define HAL_BUTTON_CLOCK RCC_AHBPeriph_GPIOA
#define HAL_BUTTON_TRIGGER_LEVEL 0
/*如果定義了HAL_BUTTON_USE_IRQ,表示開啟了中斷功能*/
#ifdef HAL_BUTTON_USE_IRQ
/*定義按鍵連接的GPIO口PA0*/
#define HAL_BUTTON_EXTI_PORT EXTI_PortSourceGPIOA
#define HAL_BUTTON_EXTI_PIN EXTI_PinSource0
#endif /* #ifndef HAL_BUTTON_USE_IRQ */
/*
* 按鍵初始化
* @param onClick - 按鍵回調函數,當按鍵被按下時執行此函數
*/
void halButtonInit(void (*onClick)(void));
/*如果沒有定義HAL_BUTTON_USE_IRQ,表示關閉了中斷功能*/
#ifndef HAL_BUTTON_USE_IRQ
/*
* 如果沒有開啟中斷功能,那么仍使用上節課的方式檢測按鍵是否被按下
*/
void halButtonPoll(void);
#endif /* #ifndef HAL_BUTTON_USE_IRQ */
#endif /* #ifndef __HAL_BUTTON_H__ */
```
<br/>
hal_button.c文件的代碼如下:
###
```
#include "hal_button.h"
#include "hal_system.h"
#include "stm32f0xx_gpio.h"
static void (*halButtonOnClick)(void) = 0;
/*
* 按鍵初始化
* @param onClick - 按鍵回調函數,當按鍵被按下時執行此函數
*/
void halButtonInit(void (*onClick)(void))
{
halButtonOnClick = onClick;//保存回調函數
GPIO_InitTypeDef buttonGPIO;//定義GPIO配置
/*如果定義了HAL_BUTTON_USE_IRQ,表示開啟了中斷功能*/
#ifdef HAL_BUTTON_USE_IRQ
EXTI_InitTypeDef buttonEXTI;
NVIC_InitTypeDef buttonNVIC;
#endif
buttonGPIO.GPIO_Mode = GPIO_Mode_IN;//配置為輸入模式
buttonGPIO.GPIO_PuPd = GPIO_PuPd_UP,//配置為上拉
buttonGPIO.GPIO_Speed = GPIO_Speed_2MHz;//速率為2MHz
buttonGPIO.GPIO_Pin = HAL_BUTTON_PIN;//引腳
RCC_AHBPeriphClockCmd(HAL_BUTTON_CLOCK, ENABLE);//使用按鍵時鐘
GPIO_Init(HAL_BUTTON_PORT, &buttonGPIO);//初始化PA0
/*如果定義了HAL_BUTTON_USE_IRQ,表示開啟了中斷功能*/
/*以下代碼的主要作用是配置PA0為低電平輸入觸發中斷,其中涉及多方面內容,可暫時無須深入理解*/
#ifdef HAL_BUTTON_USE_IRQ
buttonEXTI.EXTI_Line = EXTI_Line0;
buttonEXTI.EXTI_Mode = EXTI_Mode_Interrupt;
buttonEXTI.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
buttonEXTI.EXTI_LineCmd = ENABLE;
buttonNVIC.NVIC_IRQChannel = EXTI0_1_IRQn,
buttonNVIC.NVIC_IRQChannelPriority = 0,
buttonNVIC.NVIC_IRQChannelCmd = ENABLE,
EXTI_Init(&buttonEXTI);
NVIC_Init(&buttonNVIC);
SYSCFG_EXTILineConfig(HAL_BUTTON_EXTI_PORT, HAL_BUTTON_EXTI_PIN);//配置PA0
#endif /* #ifndef HAL_BUTTON_USE_IRQ */
}
/*如果沒有定義HAL_BUTTON_USE_IRQ,表示關閉了中斷功能*/
#ifndef HAL_BUTTON_USE_IRQ
/*
* 如果沒有開啟中斷功能,那么仍使用上節課的方式檢測按鍵是否被按下
*/
void halButtonPoll(void)
{
/* 如果按鍵沒有被按下,如果沒有則返回*/
if (GPIO_ReadInputDataBit(HAL_BUTTON_PORT, HAL_BUTTON_PIN) != HAL_BUTTON_TRIGGER_LEVEL) return;
/* 延遲10ms,去除機械按鍵抖動 */
halSystemDelayUs(1000 * 10);
/* 再次檢測按鍵是否被按下,如果沒有則返回*/
if (GPIO_ReadInputDataBit(HAL_BUTTON_PORT, HAL_BUTTON_PIN) != HAL_BUTTON_TRIGGER_LEVEL) return;
/* 等待按鍵松開 */
while(GPIO_ReadInputDataBit(HAL_BUTTON_PORT, HAL_BUTTON_PIN) == HAL_BUTTON_TRIGGER_LEVEL) halSystemDelayUs(1000);
/* 如果定義回調函數,則調用回調函數 */
if (halButtonOnClick != 0) halButtonOnClick();
}
/* 使用中斷*/
#else
/*中斷事件處理函數,用于處理中斷事件。如果發生了中斷,則自動進入此函數*/
void EXTI0_1_IRQHandler()
{
if (EXTI_GetITStatus(EXTI_Line0) != RESET && halButtonOnClick != 0) {
/* 延遲10ms,去除機械按鍵抖動 */
halSystemDelayUs(1000 * 10);
/* 再次檢測按鍵是否被按下*/
if (GPIO_ReadInputDataBit(HAL_BUTTON_PORT, HAL_BUTTON_PIN) == HAL_BUTTON_TRIGGER_LEVEL)
halButtonOnClick();//執行按鍵回調函數
}
EXTI_ClearFlag(EXTI_Line0);//清楚中斷標志
}
#endif /* #ifndef HAL_BUTTON_USE_IRQ */
```
<br/>
## **使用按鍵 HAL API**
編寫好按鍵 HAL API后,按鍵的使用非常簡單。在配套工程的main.c文件中添加如下代碼:
###
```
/*
* 按鍵回調函數,當按鍵被按下后即執行此函數
*/
static void buttonOnClick()
{
halLedToggle();
}
int main(void)
{
halSystemInit();//系統初始化
halLedInit();//LED初始化
halButtonInit(buttonOnClick);//按鍵初始化
while (1)
{
/*如果沒有定義HAL_BUTTON_USE_IRQ,表示關閉了中斷功能*/
#ifndef HAL_BUTTON_USE_IRQ
/*
如果沒有開啟中斷功能,那么仍使用上節課的方式檢測按鍵是否被按下
*/
halButtonPoll();
#endif
}
}
```
增加了中斷功能后,上層應用的修改非常少,代碼仍然非常簡潔。
<br/>
## **全局宏定義**
前述代碼多次使用到HAL_BUTTON_USE_IRQ,這是一個全局宏定義。其定義方式如下:
* 選擇工程魔法棒;
* 選擇C/C++選項卡;
* Define 位置加入宏宏定義如圖所示。

>[danger] 注意,宏與宏之間需要用英文的逗號隔開
<br/>
<br/>
## **商務合作**
如有以下需求,可掃碼添加管理員好友,注明“**商務合作**”
* 項目定制開發,技術范圍:**NB-IoT**、**CATn(4G)**、**WiFi**、**ZigBee**、**BLE Mesh**以及**STM32**、**嵌入式Linux**等;
* 入駐平臺,成為講師;
* 接項目賺外快;
* 善學坊官網:[www.sxf-iot.com](https://www.sxf-iot.com/)

(非商務合作**勿擾**,此處**非**技術支持)
- 課程介紹
- 配套資源下載
- 配套開發套件簡介
- 簡介
- 硬件組成 & 技術參數
- 電路原理圖 & PCB圖
- 撥碼開關使用說明
- 第一部分:無線通信 開發指南
- 1.1.1 NB-IoT:技術簡介
- 1.1.2 NB:CH34x USB轉串口驅動安裝
- 1.1.3 NB:AT 指令開發與測試
- 1.1.4 NB:基礎指令集簡介
- 1.1.5 NB:云端服務器
- 1.1.5.1 PuTTY 簡介與安裝
- 1.1.5.2 登錄云端服務器
- 1.1.6 NB:移遠官方工具簡介
- 1.1.7 NB:使用UDP協議與云端服務器通信
- 1.1.8 NB:使用TCP協議與云端服務器通信
- 1.1.9 NB:使用MQTT協議與云端服務器通信
- 進階課程
- 第二部分:STM32 開發指南
- 2.1 搭建開發環境
- 2.1.1 Keil MDK 簡介與安裝
- 2.1.2 STM32 Pack 簡介與安裝
- 2.1.3 CH34x 驅動簡介與安裝
- 2.1.4 其他開發工具
- 2.2 STM32 開發基礎
- 2.2.1 新建工程
- 2.2.2 實現第1個程序
- 2.2.3 Hex 文件燒錄詳解
- 2.3 移植官方標準工程模板
- 2.4 GPIO實驗——LED燈
- 2.5 系統延時應用
- 2.6 GPIO實驗——按鍵
- 2.7 GPIO中斷實驗——按鍵觸發
- 2.8 使用定時器TIM3
- 2.9 串口通信實驗
- 2.10 ADC 實驗
- 2.11 OLED顯示器實驗
- 2.12 SDK 設計思想
- 2.13 SDK 架構解析
- 2.14 多任務應用
- 2.15 輸入型任務:按鍵輸入
- 2.16 輸入型任務:串口接收
- 課外篇:項目實戰
- 基于STM32+NB-IoT的溫濕度采集
- 系統簡介
- 系統搭建
- 系統詳解
- 1.代碼編譯與架構說明
- 2.DHT11溫濕度傳感器
- 3. 數據通信任務說明
- 版權聲明與免責聲明