日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【嵌入式学习-STM32F103-EXTI外部中断】

發(fā)布時間:2024/1/8 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【嵌入式学习-STM32F103-EXTI外部中断】 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄

1、EXTI基礎(chǔ)知識補充

2、編程要點

3、對射式紅外傳感器計次完整代碼(注釋)

4、旋轉(zhuǎn)編碼器計次完整代碼(注釋)

參考江科大32單片機教學(xué)視頻!

1、EXTI基礎(chǔ)知識補充


對于旋轉(zhuǎn)編碼器,正向旋轉(zhuǎn)時,A、B相輸出的波形為下圖(上),反向旋轉(zhuǎn)時,A、B相輸出的波形為下圖(下)。
1、如果把一相的的下降沿用作觸發(fā)中斷,在中斷時刻讀取另一相的電平,此時正轉(zhuǎn)就是高電平,反轉(zhuǎn)就是低電平,這樣就能區(qū)分旋轉(zhuǎn)方向。
(小瑕疵:正轉(zhuǎn)時,由于A相先出現(xiàn)下降沿,旋轉(zhuǎn)編碼器剛開始動,就進入中斷,而反轉(zhuǎn)時,A相后出現(xiàn)下降沿,只有轉(zhuǎn)到位了,才能進入中斷)

2、改進方案:只有在B相下降沿和A相低電平時,才判斷為正轉(zhuǎn),在A相下降沿和B相低電平時,才判斷為反轉(zhuǎn)。這樣能夠保證正轉(zhuǎn)和反轉(zhuǎn)都是轉(zhuǎn)到位了,才執(zhí)行數(shù)字的加減操作。

上圖對應(yīng)的中斷服務(wù)函數(shù)為中斷0服務(wù)函數(shù)和中斷1服務(wù)函數(shù)

//中斷0服務(wù)函數(shù) void EXTI0_IRQHandler(void) {//檢查函數(shù)標(biāo)志位if (EXTI_GetITStatus(EXTI_Line0) == SET){/* 如果出現(xiàn)數(shù)據(jù)亂跳的現(xiàn)象,可再次判斷引腳電平,以避免抖動 */if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0){if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0){Encoder_Count --;}}//清除中斷標(biāo)志位EXTI_ClearITPendingBit(EXTI_Line0);} } //中斷1服務(wù)函數(shù) void EXTI1_IRQHandler(void) {//檢查函數(shù)標(biāo)志位if (EXTI_GetITStatus(EXTI_Line1) == SET){/* 如果出現(xiàn)數(shù)據(jù)亂跳的現(xiàn)象,可再次判斷引腳電平,以避免抖動 */if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0){if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0){Encoder_Count ++;}}//清除中斷標(biāo)志位EXTI_ClearITPendingBit(EXTI_Line1);} }

2、編程要點

1)初始化用來產(chǎn)生中斷的GPIO
2)初始化EXTI
3)配置NVIC
4)編寫中斷服務(wù)函數(shù)

3、對射式紅外傳感器計次完整代碼(注釋)

CountSensor.c

#include "stm32f10x.h" // Device header//我們想要一個數(shù)字來統(tǒng)計中斷觸發(fā)的次數(shù) uint16_t CountSensor_Count;//設(shè)計的外設(shè)包括RCC GPIO AFIO EXTI NVIC void CountSensor_Init(void) {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//EXTI(原因不詳) 和 NVIC(內(nèi)核外設(shè)都不需要開啟時鐘)的時鐘一直都打開,不需要我們開啟時鐘GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉輸入,默認(rèn)為高電平GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);/* 與AFIO相關(guān)的重要的函數(shù)配置 *///GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState); //作用是可用來進行引腳重映射,第一個參數(shù)可以選擇重映射的方式 第二個參數(shù)是新的狀態(tài)GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14); //配置AFIO的數(shù)據(jù)選擇器,來選擇我們想要的中斷引腳//將EXTI的第14個線路配置為中斷模式,下降沿觸發(fā),開啟中斷,這樣PB14的電平信號就能夠通過EXTI通向下一級的NVICEXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line14; //指定我們需要配置的中斷線EXTI_InitStructure.EXTI_LineCmd = ENABLE; //指定選擇的中斷線的新狀態(tài)EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中斷模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿觸發(fā)EXTI_Init(&EXTI_InitStructure);//配置NVIC//中斷分組NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //這個分組方式整個芯片只能用一種,因此這個分組的代碼整個工程只需要執(zhí)行一次即可//中斷初始化NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //優(yōu)先級是在多個中斷源同時申請,產(chǎn)生擁擠時才有作用,這只有一個中斷,隨機匹配即可NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure); }//返回變量CountSensor_Count uint16_t CountSensor_Get(void) {return CountSensor_Count; } //中斷函數(shù)都是無參無返回值 //中斷函數(shù)不需要調(diào)用,它是自動執(zhí)行的 void EXTI15_10_IRQHandler(void) {//中斷標(biāo)志位的判斷,確保是我們想要的中斷源觸發(fā)的這個函數(shù),因為這個函數(shù)EXTI10到15都能進來,因此需要判斷是否是EXTI14 if (EXTI_GetITStatus(EXTI_Line14) == SET){//如果是,我們就執(zhí)行中斷程序/*如果出現(xiàn)數(shù)據(jù)亂跳的現(xiàn)象,可再次判斷引腳電平,以避免抖動*/if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0){CountSensor_Count ++;}//中斷程序結(jié)束后,一定要再調(diào)用一下清除中斷標(biāo)志位的函數(shù),因為只要中斷標(biāo)志位置1,程序就會跳轉(zhuǎn)到中斷函數(shù)//如果你不清除中斷標(biāo)志位,那他就會一直申請中斷,程序就會不斷響應(yīng)中斷,執(zhí)行中斷函數(shù),程序就會卡死在中斷函數(shù)里EXTI_ClearITPendingBit(EXTI_Line14);} }

CountSensor.h

#ifndef __COUNT_SENSOR_H #define __COUNT_SENSOR_Hvoid CountSensor_Init(void); uint16_t CountSensor_Get(void);#endif

main.c

#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "CountSensor.h"int main(void) {OLED_Init();CountSensor_Init();OLED_ShowString(1, 1, "Count:");while (1){//顯示計次的數(shù)據(jù)OLED_ShowNum(1, 7, CountSensor_Get(), 5);} }

4、旋轉(zhuǎn)編碼器計次完整代碼(注釋)

Encoder.c

#include "stm32f10x.h" // Device header//由于需要正反轉(zhuǎn),因此定義一個帶符號的變量 int16_t Encoder_Count;//初始化PB0和PB1兩個GPIO口的外部中斷 void Encoder_Init(void) { //初始化GPIO和AFIO時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//初始化GPIO,PB0和PB1GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//AFIO中斷引腳選擇GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0); //將第0個線路撥到GPIOB上GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1); //將第1個線路撥到GPIOB上//指定中斷線,同時將第0條線路和第1條線路初始化為中斷模式,下降沿觸發(fā)EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1; EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_Init(&EXTI_InitStructure);//中斷分組NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中斷優(yōu)先級,對兩個通道分別設(shè)置優(yōu)先級NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_Init(&NVIC_InitStructure); }//定義函數(shù),返回變量,在這里不直接返回Encoder_Count變量,而是返回每次調(diào)用這個get函數(shù)后的Count變化值 //因為用count返回的話,return直接跳出函數(shù),count就無法清零 int16_t Encoder_Get(void) {int16_t Temp;Temp = Encoder_Count;Encoder_Count = 0;return Temp; }//中斷0服務(wù)函數(shù) void EXTI0_IRQHandler(void) {//檢查函數(shù)標(biāo)志位if (EXTI_GetITStatus(EXTI_Line0) == SET){/* 如果出現(xiàn)數(shù)據(jù)亂跳的現(xiàn)象,可再次判斷引腳電平,以避免抖動 */if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0){if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0){Encoder_Count --;}}//清除中斷標(biāo)志位EXTI_ClearITPendingBit(EXTI_Line0);} } //中斷1服務(wù)函數(shù) void EXTI1_IRQHandler(void) {//檢查函數(shù)標(biāo)志位if (EXTI_GetITStatus(EXTI_Line1) == SET){/* 如果出現(xiàn)數(shù)據(jù)亂跳的現(xiàn)象,可再次判斷引腳電平,以避免抖動 */if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0){if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0){Encoder_Count ++;}}//清除中斷標(biāo)志位EXTI_ClearITPendingBit(EXTI_Line1);} }/* 中斷編程的建議 1、在中斷函數(shù)里,最好不要執(zhí)行耗時過長的代碼,中斷函數(shù)要簡短快速,別剛進中斷就執(zhí)行一個Delay多少毫秒的代碼 因為中斷時處理突發(fā)的事情,如果你為了一個突發(fā)的事情呆在中斷里不出來,主程序就會收到嚴(yán)重的阻塞 2、最好不要在中斷函數(shù)和主函數(shù)調(diào)用相同的函數(shù)或者操作同一個硬件,如OLED顯示函數(shù),如果既在主函數(shù)里調(diào)用OLED函數(shù) 又在中斷里調(diào)用OLED,OLED就會顯示錯誤 為了避免問題,最好不要在主程序和中斷程序里操作可能產(chǎn)生沖突的硬件 在實現(xiàn)功能的時候,可以在中斷里操作變量或者標(biāo)志位 當(dāng)中斷返回時,我在對這個變量進行顯示和操作 這樣既能保證中斷函數(shù)的簡短快速,又能保證不產(chǎn)生沖突的硬件操作EXTI_GetITStatus() 函數(shù)用于獲取指定的中斷標(biāo)志位的狀態(tài),返回值為標(biāo)志位的狀態(tài),即是否被觸發(fā)。如果返回值為 SET,則表示對應(yīng)的中斷已經(jīng)被觸發(fā);如果返回值為 RESET,則表示對應(yīng)的中斷還未被觸發(fā)。EXTI_ClearITPendingBit() 函數(shù)用于清除指定的中斷標(biāo)志位。當(dāng)某個中斷被觸發(fā)時,對應(yīng)的中斷標(biāo)志位會被置位。在處理完中斷后,需要通過調(diào)用 EXTI_ClearITPendingBit() 函數(shù)來清除該標(biāo)志位,否則會一直保持置位狀態(tài),導(dǎo)致下一次中斷無法正常觸發(fā)。因此,這兩個函數(shù)常常一起使用,以確保外部中斷能夠正常工作。 */

Encoder.h

#ifndef __ENCODER_H #define __ENCODER_Hvoid Encoder_Init(void); int16_t Encoder_Get(void);#endif

main.c

#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "Encoder.h"int16_t Num;int main(void) {OLED_Init();Encoder_Init();OLED_ShowString(1, 1, "Num:");while (1){//因為Get函數(shù)返回的是調(diào)用這個函數(shù)的間隔里旋轉(zhuǎn)編碼器產(chǎn)生的正負(fù)脈沖數(shù),所以返回值直接+=給Num,就能夠?qū)um進行加減操作Num += Encoder_Get();OLED_ShowSignedNum(1, 5, Num, 5);} }

總結(jié)

以上是生活随笔為你收集整理的【嵌入式学习-STM32F103-EXTI外部中断】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。