STM32震动感应控制继电器(使用循环VS使用外部中断EXTI和中断控制器NVIC)
參考:stm32的外部中斷 震動感應 控制 繼電器
作者:點燈小哥
發布時間: 2021-03-05 22:37:01
網址:https://blog.csdn.net/weixin_46016743/article/details/114417161
參考:STM32震動感應燈
作者:一只小阿大:)
發布時間: 2021-07-09 20:10:02
網址:https://blog.csdn.net/qq_44610809/article/details/118613689
目錄
- EXTI外部中斷和NVIC中斷控制器
- EXTI外部中斷簡介
- 中斷觸發方式(上升沿和下降沿)
- EXTI外部中斷結構體(中斷線、觸發方式、使能)
- NVIC中斷控制結構體(中斷通道/源、中斷分組、搶占優先級、子優先級)
- 中斷服務函數名(在啟動頭文件里)
- 中斷函數配置步驟
- 硬件接線及開發環境
- 代碼編寫(使用循環VS使用外部中斷)
- 繼電器模塊(relay.c)
- 震動感應模塊(shake.c)
- EXTI外部中斷配置(exti.c)
- 主函數(main.c)
EXTI外部中斷和NVIC中斷控制器
EXTI外部中斷簡介
STM32 的每個 IO 都可以作為外部中斷的中斷輸入口,這點也是 STM32 的強大之處。STM32F103 的中斷控制器NVIC支持 19 個外部中斷/事件請求。每個中斷設有狀態位,每個中斷/事件都有獨立的觸發和屏蔽設置。STM32F103 的19 個外部中斷為:
線 0~15:對應外部 IO 口的輸入中斷。
線 16:連接到 PVD 輸出。
線 17:連接到 RTC 鬧鐘事件。
線 18:連接到 USB 喚醒事件
從上面可以看出,STM32 供 IO 口使用的中斷線只有 16 個,但是 STM32 的 IO 口卻遠遠不止 16 個,那么 STM32是怎么把 16 個中斷線和 IO 口一一對應起來的呢?
STM32 這樣設計的,GPIO 的管腳GPIOx.0-GPIOx.15(x=A,B,C,D,E,F,G)分別對應中斷線 0~15。這樣每個中斷線對應了最多 7 個 IO 口,以線0為例:它對應了GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0。而中斷線每次只能連接到 1個 IO 口上,這樣就需要通過配置來決定對應的中斷線配置到哪個 GPIO 上了。
下面我們看看 GPIO 跟中斷線的映射關系圖(第二張圖片右側):
中斷觸發方式(上升沿和下降沿)
- 上升沿觸發:數字電平從低電平(數字“0”)變為高電平(數字“1”)的那一瞬間叫作上升沿。 上升沿觸發是當信號有上升沿時的開關動作,當電位由低變高而觸發輸出變化的就叫上升沿觸發。也就是當測到的信號電位是從低到高也就是上升時就觸發,叫做上升沿觸發。
- 下降沿觸發:數字電路中,數字電平從高電平(數字“1”)變為低電平(數字“0”)的那一瞬間叫作下降沿。 [1] 下降沿觸發是當信號有下降沿時的開關動作,當電位由高變低而觸發輸出變化的就叫下降沿觸發。也就是當測到的信號電位是從高到低也就是下降時就觸發,叫做下降沿觸發。
- 邊沿觸發:既可以上升觸發也可以下降觸發
上升沿觸發 就是當電壓從低變高時觸發中斷
下降沿觸發 就是當電壓從高變低時觸發中斷
EXTI外部中斷結構體(中斷線、觸發方式、使能)
-
EXTI_Line:EXTI中斷/事件線選擇,可選EXTI0至EXTI19這20個中斷線
-
EXTI_Mode:EXTI模式選擇,可選為產生中斷模式/產生事件
-
EXTI_Trigger:上升沿/下降沿/雙沿觸發
-
EXTI_LineCmd:使能OR失能
NVIC中斷控制結構體(中斷通道/源、中斷分組、搶占優先級、子優先級)
在misc.h文件中,屬于內核寄存器
中斷通道/中斷源(EXTI外部中斷源、串口中斷源等,注意串口中斷不屬于EXTI外部中斷):
NVIC中斷分組、搶占優先級和子優先級:
STM32 將中斷分為5 個組,組 0 ~ 4。該分組的設置是由 SCB->AIRCR 寄存器的 bit10 ~ 8 來定義的。NVIC中斷分組使用如下的固件庫函數:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC中斷分組 配置成第二組通過這個表,我們就可以清楚的看到組 0~4 對應的配置關系,例如組設置為 3,那么此時所有的 60 個中斷,每個中斷的中斷優先寄存器的高四位中的最高 3 位是搶占優先級,低 1 位是響應優先級。每個中斷,你可以設置搶占優先級為 0 ~ 7,響應優先級為 1 或 0。搶占優先級的級別高于響應優先級。而數值越小所代表的優先級就越高。
優先級原則:第一,如果兩個中斷的搶占優先級和響應優先級都是一樣的話,則看哪個中斷先發生就先執行;第二,高優先級的搶占優先級是可以打斷正在進行的低搶占優先級中斷的。而搶占優先級相同的中斷,高優先級的響應優先級不可以打斷低響應優先級的中斷。
舉例: 假定設置中斷優先級組為 2,然后設置中斷 3(RTC 中斷)的搶占優先級為 2,響應優先級為 1。中斷 6(外部中斷> 0)的搶占優先級為 3,響應優先級為 0。中斷 7(外部中斷 1)的搶占優先級為 2,響應優先級為 0。那么這 3> 個中斷的優先級順序為:中斷 7>中斷 3>中斷 6。 上面例子中的中斷 3 和中斷 7 都可以打斷中斷 6 的中斷。而中斷 7 和中斷 3> 卻不可以相互打斷!
中斷服務函數名(在啟動頭文件里)
中斷函數配置步驟
IO 口外部中斷的一般步驟:
- 1、初始化 IO 口為輸入。
- 2、開啟 AFIO(GPIO復用為中斷)時鐘
- 3、設置 IO 口與中斷線的映射關系(配置GPIOA1為中斷源)。
- 4、初始化線上中斷,設置觸發條件等。
- 5、配置中斷分組(NVIC),并使能中斷。
- 6、編寫中斷服務函數。
通過以上幾個步驟的設置,我們就可以正常使用外部中斷了。
具體函數:
1、初始化IO的輸入
GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);2、開啟IO口復用時鐘
RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);3、設置IO口與中斷線的映射關系
GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);4、初始化中斷線、觸發方式等
EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);5、配置中斷分組(NVIC),并使能中斷
NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)6、編寫中斷服務函數
EXTI4_IRQHandler()7、判斷中斷線中斷狀態,是否發生
EXTI_GetITStatus(uint32_t EXTI_Line);8、清除中斷標志位
EXTI_ClearITPendingBit(uint32_t EXTI_Line);硬件接線及開發環境
硬件平臺
stm32最小系統
軟件平臺
Keil C51是美國Keil Software公司出品的51系列兼容單片機C語言軟件開發系統,與匯編相比,C語言在功能上、結構性、可讀性、可維護性上有明顯的優勢,因而易學易用。Keil提供了包括C編譯器、宏匯編、鏈接器、庫管理和一個功能強大的仿真調試器等在內的完整開發方案,通過一個集成開發環境(μVision)將這些部分組合在一起。運行Keil軟件需要WIN98、NT、WIN2000、WINXP等操作系統。如果你使用C語言編程,那么Keil幾乎就是你的不二之選,即使不使用C語言而僅用匯編語言編程,其方便易用的集成環境、強大的軟件仿真調試工具也會令你事半功倍。
接線圖
代碼編寫(使用循環VS使用外部中斷)
繼電器模塊(relay.c)
relay.c
#include "relay.h" #include "stm32f10x.h" // Device headervoid Relay_Init(void) {GPIO_InitTypeDef Relay_init ;//1.使能GPIOA時鐘 接入PA3口RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA , ENABLE);//2.GPIOA3結構體配置Relay_init.GPIO_Mode = GPIO_Mode_Out_PP;//推挽輸出Relay_init.GPIO_Pin = GPIO_Pin_3;Relay_init.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init( GPIOA , &Relay_init);}單獨新建立relay文件夾,里面新建relay.c和relay.h兩個文件,先將relay.c文件添加到USER里面,寫完第一句代碼#include "relay.h"直接編譯,relay.h會自動包含到relay.c的子目錄下。
若頭文件和.c文件不在同一個文件目錄下編譯將提示找不到頭文件,需要手動添加頭文件路徑。
relay.h
#include "stm32f10x.h"void Relay_Init(void);//先聲明,再定義,再調用震動感應模塊(shake.c)
shake.c
#include "shake.h" #include "stm32f10x.h" // Device headervoid Shake_Init(void) {GPIO_InitTypeDef Shake_init;//1.打開我們的GPIOA時鐘 連接PA1引腳RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//2.配置GPIOA1的配置Shake_init.GPIO_Mode = GPIO_Mode_IPD; //震動傳感器初始為高電平(無振動),有振動就為低電平 檢測從高電平到低電平的變化 所以用下拉模式(這個表述不是很懂)Shake_init.GPIO_Pin = GPIO_Pin_1;Shake_init.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init( GPIOA, &Shake_init);}shake.h
#include "stm32f10x.h"void Shake_Init(void);EXTI外部中斷配置(exti.c)
exti.h
#include "stm32f10x.h" void Exti_Init(void);
exti.c
#include "exti.h" #include "stm32f10x.h" // Device header 固件庫頭文件void Exti_Init(void) {//1.配置GPIOGPIO_InitTypeDef Shake_init;//gpio.h EXTI_InitTypeDef Exti_init; //exti.hNVIC_InitTypeDef Nvic_init; //misc.h//使能GPIO和GPIOA復用的時鐘 如上圖所示RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIO的時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //GPIOA的中斷復用 使能時鐘//設置GPIOA1為中斷源 如上圖所示GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1); //gpio.h 配置的外部中斷源是GPIOA1 是shake震動傳感器(GPIOA pin1的復用)NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC中斷組 選第2組(隨便選)Shake_init.GPIO_Mode = GPIO_Mode_IPD; //震動傳感器初始為高電平 所以用下拉模式 拉到低電平(不是很懂)Shake_init.GPIO_Pin = GPIO_Pin_1;Shake_init.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init( GPIOA, &Shake_init);// 2、配置EXTI外部中斷 Exti_init.EXTI_Line = EXTI_Line1; //中斷線 因為我們用到的中斷源是GPIOA1 所以中斷線選擇Line1 Exti_init.EXTI_Mode = EXTI_Mode_Interrupt;//中斷模式 還一種是事件模式Exti_init.EXTI_Trigger = EXTI_Trigger_Falling;//振動傳感器有振動源————>高電平到底電平 所以選擇下降沿觸發Exti_init.EXTI_LineCmd = ENABLE; //選使能 還一種是靜止模式EXTI_Init(&Exti_init);//頭文件最下面的函數///3、配置中斷控制器(NVIC)Nvic_init.NVIC_IRQChannel = EXTI1_IRQn; //中斷通道 因為我們用到的中斷源是GPIOA1所以選擇中斷通道1Nvic_init.NVIC_IRQChannelCmd = ENABLE; //使能 找到FunctionalState字眼 右鍵gotoNvic_init.NVIC_IRQChannelPreemptionPriority = 1;//因為只配置了一個中斷 搶占優先級、子優先級隨便都設為1NVIC_Init(&Nvic_init);//中斷初始化函數//4.編寫中斷服務函數 寫在main函數里 }主函數(main.c)
main.c
#include "stm32f10x.h" // Device header #include "relay.h"//這個會找不到頭文件,需要手動添加頭文件路徑 點擊魔術棒——選擇C/C++——include path #include "shake.h"//下同 #include "exti.h"void delay(uint16_t time)//ms延時函數 {uint16_t i = 0;while(time--){i=12000;while(i--);} } int main(void) {LED_Init();Relay_Init();Shake_Init();Exti_Init();GPIO_SetBits(GPIOA , GPIO_Pin_3); //初始化繼電器為關閉狀態下面這部分沒有使用外部中斷,直接While()死循環檢測振動模塊電平,從而控制燈的亮滅(繼電器) // while(1) // { // //if內部判斷是否發生電平變化 // if(GPIO_ReadInputDataBit( GPIOA, GPIO_Pin_1) == 0) //如果發生震動 // { // GPIO_ResetBits(GPIOA , GPIO_Pin_3);//拉低開燈 // delay(1000);//延遲1秒 //持續一秒 // GPIO_SetBits(GPIOA , GPIO_Pin_3);//拉高關燈 // }else{ // GPIO_SetBits(GPIOA , GPIO_Pin_3); // } // }}//4.中斷服務函數 中斷的好處:不用一直while()死循環,一直占用CPU void EXTI1_IRQHandler(void)//在啟動文件里 函數名不能變 { if (EXTI_GetITStatus( EXTI_Line1 ) != RESET) //判斷是否發生了中斷 右鍵 EXTI_GetITStatus goto 在exit.h定義 exit.c實現{GPIO_ResetBits(GPIOA , GPIO_Pin_3); //打開繼電器,開燈delay(1000);GPIO_SetBits(GPIOA , GPIO_Pin_3); //關閉繼電器,關燈} EXTI_ClearFlag( EXTI_Line1);//清除中斷標志 不然標志位一直都存在 在exit.h }總結
以上是生活随笔為你收集整理的STM32震动感应控制继电器(使用循环VS使用外部中断EXTI和中断控制器NVIC)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你的灯亮着么阅读笔记3
- 下一篇: 结构体与共用体(联合体)