5.1 ~ 5.2 EXTI外部中斷
視頻選集(12/50)[5-2] 對射式紅外傳感器計次&旋轉(zhuǎn)編碼器計次
0. 庫函數(shù)
0.1 AFIO配置
/**
* @brief 配置AFIO數(shù)據(jù)選擇器,以選擇想要作為中斷引腳的GPIO端口
* @param GPIO_PortSource: 選擇某個GPIO作為中斷源
* @param GPIO_PinSource: 指定端口
* @retval None
*/
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
0.2 EXTI配置
/**
* @brief 根據(jù) EXTI_InitStruct 中指定的參數(shù)初始化 EXTI 外設(shè)。
* @param 指向 EXTI_InitTypeDef 結(jié)構(gòu)體的指針,該結(jié)構(gòu)體包含 EXTI 的配置信息
* @retval None
*/
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
typedef struct
{
uint32_t EXTI_Line; // 指定要配置的中斷線
EXTIMode_TypeDef EXTI_Mode; // 指定EXTI模式
EXTITrigger_TypeDef EXTI_Trigger; // 指定觸發(fā)信號的有效邊沿
FunctionalState EXTI_LineCmd; // 指定中斷線的新狀態(tài)
}EXTI_InitTypeDef;
/** @defgroup EXTI_Lines
* @{
*/
#define EXTI_Line0 ((uint32_t)0x00001) /*!< External interrupt line 0 */
#define EXTI_Line1 ((uint32_t)0x00002) /*!< External interrupt line 1 */
#define EXTI_Line2 ((uint32_t)0x00004) /*!< External interrupt line 2 */
#define EXTI_Line3 ((uint32_t)0x00008) /*!< External interrupt line 3 */
#define EXTI_Line4 ((uint32_t)0x00010) /*!< External interrupt line 4 */
#define EXTI_Line5 ((uint32_t)0x00020) /*!< External interrupt line 5 */
#define EXTI_Line6 ((uint32_t)0x00040) /*!< External interrupt line 6 */
#define EXTI_Line7 ((uint32_t)0x00080) /*!< External interrupt line 7 */
#define EXTI_Line8 ((uint32_t)0x00100) /*!< External interrupt line 8 */
#define EXTI_Line9 ((uint32_t)0x00200) /*!< External interrupt line 9 */
#define EXTI_Line10 ((uint32_t)0x00400) /*!< External interrupt line 10 */
#define EXTI_Line11 ((uint32_t)0x00800) /*!< External interrupt line 11 */
#define EXTI_Line12 ((uint32_t)0x01000) /*!< External interrupt line 12 */
#define EXTI_Line13 ((uint32_t)0x02000) /*!< External interrupt line 13 */
#define EXTI_Line14 ((uint32_t)0x04000) /*!< External interrupt line 14 */
#define EXTI_Line15 ((uint32_t)0x08000) /*!< External interrupt line 15 */
#define EXTI_Line16 ((uint32_t)0x10000) /*!< External interrupt line 16 Connected to the PVD Output */
#define EXTI_Line17 ((uint32_t)0x20000) /*!< External interrupt line 17 Connected to the RTC Alarm event */
#define EXTI_Line18 ((uint32_t)0x40000) /*!< External interrupt line 18 Connected to the USB Device/USB OTG FS
Wakeup from suspend event */
#define EXTI_Line19 ((uint32_t)0x80000) /*!< External interrupt line 19 Connected to the Ethernet Wakeup event */
typedef enum
{
EXTI_Mode_Interrupt = 0x00,
EXTI_Mode_Event = 0x04
}EXTIMode_TypeDef;
typedef enum
{
EXTI_Trigger_Rising = 0x08,
EXTI_Trigger_Falling = 0x0C,
EXTI_Trigger_Rising_Falling = 0x10
}EXTITrigger_TypeDef;
// 在中斷函數(shù)中查看和清除標志位
/**
* @brief 檢查指定的中斷線是否被開啟
* @param EXTI_Line: 指定要檢查的中斷線
* @retval 中斷線的狀態(tài) (SET or RESET).
*/
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
/**
* @brief 清除 EXTI 的標志位
* @param EXTI_Line: 指定要清除的中斷線
* @retval None
*/
void EXTI_ClearITPendingBit(uint32_t EXTI_Line)
// 在主程序中查看和清除標志位
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
void EXTI_ClearFlag(uint32_t EXTI_Line);
本質(zhì)上,這4個函數(shù)都是對狀態(tài)寄存器的讀寫。上面的兩個函數(shù)只能讀取于中斷有關(guān)的標志位,并且對中斷是否允許做出了判斷;下面的兩個函數(shù)只是一般的讀寫標志位,沒有額外的處理,能不能觸發(fā)中斷的標志位都能讀取
0.3 NVIC配置
/**
* @brief 配置優(yōu)先級分組:搶占優(yōu)先級和響應(yīng)優(yōu)先級。
* @param NVIC_PriorityGroup: specifies the priority grouping bits length.
* This parameter can be one of the following values:
* @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority
* 4 bits for subpriority
* @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority
* 3 bits for subpriority
* @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority
* 2 bits for subpriority
* @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority
* 1 bits for subpriority
* @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority
* 0 bits for subpriority
* @retval None
*/
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
/**
* @brief 根據(jù) NVIC_InitStruct 中指定的參數(shù)初始化 NVIC 外設(shè)。
* @param NVIC_InitStruct: 指向 NVIC_InitTypeDef 結(jié)構(gòu)體的指針,該結(jié)構(gòu)體包含指定 NVIC 外設(shè)的配置信息。
* @retval None
*/
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
typedef struct
{
uint8_t NVIC_IRQChannel; // 指定要啟用或禁用的 IRQ 信道
uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel
specified in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified
in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
will be enabled or disabled.
This parameter can be set either to ENABLE or DISABLE */
} NVIC_InitTypeDef;
1. 對射式紅外傳感器計次
1.1器件
- STM32最小系統(tǒng)板
- ST-LINK V2下載器
- OLED顯示屏
- 對射式紅外傳感器
1.2 實現(xiàn)目標
遮擋模塊槽一次,計數(shù)一次,累積計數(shù)實時顯示在OLED屏幕上
1.3 接線圖
注.我沒有按照圖中的IO口來接LED和按鍵,具體看程序代碼

1.4 程序
注.OLED部分我是直接用的資料里的程序,所以沒有寫筆記
main.c文件如下:
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "Sensor_Dinf.h"
/*------------------------------主函數(shù)------------------------------*/
int main(void)
{
/*-----硬件初始化-----*/
OLED_Init(); // OLED初始化
Sensor_Dinf_Init(); // 對射式紅外傳感器初始化
/*-----OLED顯示-----*/
OLED_ShowString(1, 1, "COUNT:");
while(1){
OLED_ShowNum(1, 8, GetCOUNT(), 3);
}
}
Sensor_Dinf.c文件如下:
#include "stm32f10x.h" // Device header
#include "Delay.h"
uint8_t COUNT = 0; // 存儲計數(shù)
/*------------------------------對射式紅外傳感器初始化函數(shù)------------------------------
@DO A1
*/
void Sensor_Dinf_Init(void)
{
/*-----變量聲明-----*/
GPIO_InitTypeDef GPIO_InitStruct; // 定義包含配置參數(shù)的結(jié)構(gòu)體變量
EXTI_InitTypeDef EXTI_InitStruc;
NVIC_InitTypeDef NVIC_InitStruct;
/*-----時鐘使能-----*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 開啟GPIOA的時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 開啟AFIO的時鐘
// EXTI和NVIC的時鐘是一直開啟的,不需要手動使能
/*-----GPIO配置-----*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉輸入:懸空時默認高電平
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化A1端口
/*-----AFIO配置-----*/
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1); // 將PA1引腳連接到EXTI1中斷線路
/*-----EXTI配置-----*/
EXTI_InitStruc.EXTI_Line = EXTI_Line1; // 指定EXTI1中斷線路
EXTI_InitStruc.EXTI_LineCmd = ENABLE; // 開啟中斷
EXTI_InitStruc.EXTI_Mode = EXTI_Mode_Interrupt; // 選擇中斷模式
EXTI_InitStruc.EXTI_Trigger = EXTI_Trigger_Falling; // 選擇下降沿觸發(fā)
EXTI_Init(&EXTI_InitStruc); // 初始化EXTI1
/*-----NVIC配置-----*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 優(yōu)先級分組:2位搶占,2位響應(yīng)
NVIC_InitStruct.NVIC_IRQChannel = EXTI1_IRQn; // 指定通道
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; // 該工程中斷只有一個,所以搶占和響應(yīng)優(yōu)先級可以隨意配置
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStruct);
}
/*------------------------------讀取計數(shù)值函數(shù)------------------------------
@Return COUNT
*/
uint8_t GetCOUNT(void)
{
return COUNT;
}
/*------------------------------EXTI1外部中斷函數(shù)------------------------------
@Brief 光線被遮擋時發(fā)生由低到高的跳變,遮擋物拿開時發(fā)生由高到低的跳變,進入中斷。計次加1
@Pin A1
*/
void EXTI1_IRQHandler(void)
{
// Delay_ms(500); // 中斷里面不要加延時。此處僅為測試
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
COUNT ++;
}
EXTI_ClearITPendingBit(EXTI_Line1);// 清除中斷標志位
}
Sensor_Dinf.h文件如下:
#ifndef __SENSOR_DINF_H
#define __SENSOR_DINF_H
void Sensor_Dinf_Init(void);
uint8_t GetCOUNT(void);
#endif
2. 旋轉(zhuǎn)編碼器計次
2.1 器件
- STM32最小系統(tǒng)板
- ST-LINK V2下載器
- OLED顯示屏
- 旋轉(zhuǎn)編碼器
2.2 實現(xiàn)目標
- 旋轉(zhuǎn)編碼器順時針旋轉(zhuǎn)時,編碼盤每轉(zhuǎn)過一格,計數(shù)值+1
- 旋轉(zhuǎn)編碼器逆時針旋轉(zhuǎn)時,編碼盤每轉(zhuǎn)過一格,計數(shù)值-1
- 累計計數(shù)值為有符號數(shù),可正可負,其數(shù)值實時顯示在OLED屏上
2.3 接線圖

2.4 程序
main.c文件如下:
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "Encoder.h"
/*------------------------------主函數(shù)------------------------------*/
int main(void)
{
/*-----硬件初始化-----*/
OLED_Init(); // OLED初始化
Encoder_Init(); // 旋轉(zhuǎn)編碼器初始化
/*-----OLED顯示-----*/
OLED_ShowString(1, 1, "COUNT:");
while(1){
OLED_ShowSignedNum(1, 8, GetCOUNT(), 5);
}
}
Encoder.c文件如下:
#include "stm32f10x.h" // Device header
int16_t COUNT = 0; // 存儲旋轉(zhuǎn)編碼器的計數(shù)值
/*------------------------------旋轉(zhuǎn)編碼器初始化函數(shù)------------------------------
@A B0
@B B1
*/
void Encoder_Init(void)
{
/*-----變量聲明-----*/
GPIO_InitTypeDef GPIO_InitStruct; // 定義包含配置參數(shù)的結(jié)構(gòu)體變量
EXTI_InitTypeDef EXTI_InitStruc;
NVIC_InitTypeDef NVIC_InitStruct;
/*-----時鐘使能-----*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 開啟GPIOB的時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 開啟AFIO的時鐘
// EXTI和NVIC的時鐘是一直開啟的,不需要手動使能
/*-----GPIO配置-----*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉輸入:懸空時默認高電平
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct); // 初始化B0、B1端口
/*-----AFIO配置-----*/
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0); // 將PB0引腳連接到EXTI0中斷線路
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1); // 將PB1引腳連接到EXTI1中斷線路
/*-----EXTI配置-----*/
EXTI_InitStruc.EXTI_Line = EXTI_Line0 | EXTI_Line1; // 指定EXTI0、1中斷線路
EXTI_InitStruc.EXTI_LineCmd = ENABLE; // 開啟中斷
EXTI_InitStruc.EXTI_Mode = EXTI_Mode_Interrupt; // 選擇中斷模式
EXTI_InitStruc.EXTI_Trigger = EXTI_Trigger_Falling; // 選擇下降沿觸發(fā)
EXTI_Init(&EXTI_InitStruc); // 初始化EXTI0、1
/*-----NVIC配置-----*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 優(yōu)先級分組:2位搶占,2位響應(yīng)
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; // 指定通道
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = EXTI1_IRQn; // 指定通道
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStruct);
}
/*------------------------------獲取計數(shù)值函數(shù)------------------------------
@Return COUNT
*/
int16_t GetCOUNT(void)
{
return COUNT;
}
/*------------------------------EXTI0外部中斷函數(shù)------------------------------
@Brief A相下降沿進入該中斷,若此時B相為高電平,旋轉(zhuǎn)編碼器正轉(zhuǎn),計數(shù)增加
@Pin B0
*/
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) == SET){
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)){
COUNT ++;
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
/*------------------------------EXTI1外部中斷函數(shù)------------------------------
@Brief B相下降沿進入該中斷,若此時A相為高電平,旋轉(zhuǎn)編碼器反轉(zhuǎn),計數(shù)減少
@Pin B1
*/
void EXTI1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1) == SET){
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0)){
COUNT --;
}
EXTI_ClearITPendingBit(EXTI_Line1);
}
}
Encoder.h文件如下:
#ifndef __ENCODER_H
#define __ENCODER_H
void Encoder_Init(void);
int16_t GetCOUNT(void);
#endif
本文來自博客園,作者:LI,Yi-han,轉(zhuǎn)載請注明原文鏈接:http://www.rzrgm.cn/LiYi-han/p/19029306

浙公網(wǎng)安備 33010602011771號