实验目的
实现对射式红外传感器计次
效果: 每触发一次对射式红外传感器,便进入外部中断,计数器加一,打印在OLED屏幕上
实验用品
stm32f103c8t6最小系统板,面包板,跳线,杜邦线,对射式红外传感器,OLED显示屏
知识
EXTI外部中断:
功能:
•EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
特点:
•支持的触发方式:上升沿/下降沿/双边沿/软件触发
•支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断
•通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
在高中化学中我们知道结构决定性质,性质决定功能。那么EXTI也同理,他的功能和特点是由他的结构决定的。不同的是,化学中的物质都是由于他的结构使得他存在这些性质,被人们所发现。而EXTI外部中断则是人们根据自己的需求设计出这种结构,也就是被人们发明出来。
于是我们接下来学习其结构,看看其结构是如何实现功能的。
EXTI结构:
工作原理:
每个GPIO口有16条线分别将每个引脚和AFIO(中断引脚选择)连接,AFIO从各GPIO的相同引脚(如PA0,PB0,PC0)中选择一个连在EXIT中,EXTI向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
AFIO结构:
工作原理:
上图为AFIO引脚中断选择的结构,每个数据选择器只能从PA0,PB0····等相同引脚中选择一个,接入EXIT
EXTI边缘检测与控制:
上图为EXIT内部框图,信号由输入线进入边沿检测电路,与边沿检测电路相连的上升沿下降沿触发选择寄存器可以用来选择触发方式为上升沿下降沿还是双边沿触发。随后信号进入或门的输入端(与软件触发寄存器一起进入)。由于或门的性质(任意为一,值为一)所以边缘检测电路或者软件有中断事件发生均会使中断信号继续传递。之后中断信号可以触发中断,也可以触发事件。对于正常触发中断,会有一个请求挂起寄存器,通过请求挂起寄存器,我们可以知道中断信号来自于哪个通道。信号通过请求挂起寄存器,与中断屏蔽寄存器,一起进入与门。由于与门的性质(任意为零,输出为零)所以与门与中断屏蔽寄存器共同起到了开关的作用。如果中断屏蔽寄存器为1,那么输出必为一,即允许中断。如果中断屏蔽寄存器为0,那么输出必为0,即禁止中断。随后信号被输入至NVIC中断控制器
实验步骤
根据该实验的内容,我们可以将该程序分为两个模块:
计数器模块,OLED模块
其中OLED模块直接引用他人的库,不需自己编写。
需要我们编写的是:计数器模块
计数器模块:
就如前文所说的结构决定性质,性质决定功能。EXTI的结构也决定了我们所涉及到的函数
首先必定是要进行初始化,将计数器所用的资源配置好。
根据EXTI的结构,我们需要配置:
RCC时钟开启,GPIO,AFIO,EXTI,NVIC初始化配置
涉及的函数:
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
GPIO_Init(GPIOB, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);
EXTI_Init(&EXTI_InitStruct);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_Init(&NVIC_InitStruct);
随后编写中断函数:
中断函数的名称都是固定的,本次用到的是
void EXTI15_10_IRQHandler(void);
在其中用EXTI_GetITStatus(EXTI_Line14)函数判断中断是否来自PB14,是就进入中断
计数器模块:
#include "stm32f10x.h"
#include "OLED.h"
uint16_t count_number=0 ;
void CountSenser_Init(void){
/*初始化GPIOB*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef* GPIO_InitStruct;
GPIO_InitStruct->GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStruct->GPIO_Pin=GPIO_Pin_14;
GPIO_InitStruct->GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,GPIO_InitStruct);
/*初始化AFIO*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);
/*初始化EXIT*/
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line=EXTI_Line14 ;
EXTI_InitStruct.EXTI_LineCmd=ENABLE ;
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStruct);
/*初始化NVIC*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=EXTI15_10_IRQn ;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct);
}
void EXTI15_10_IRQHandler(void){
if(EXTI_GetITStatus(EXTI_Line14)==SET){
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)
{
count_number++;
}
EXTI_ClearITPendingBit( EXTI_Line14);
}
}
uint16_t CountSensor_Get(void)
{
return count_number;
}