1.实物连接图:
左下角的D0接任意一个空闲的IO口均可,此处接的是PB14。当对射式红外传感器被遮挡住时,D0发送中断信号给PB14并完成相关操作。
2.外部信号流程(代码部分编写的原理):
外部信号总思路:(配置外部中断)GPIO-->AFIO-->EXTI-->NVIC-->(中断函数)CPU
3.代码部分:
main代码部分:
#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:");//在第一行第三列开始显示HelloWorld!1 //注:此处要查找数字的长度,超过就会截断,无法显示 while(1) { OLED_ShowNum(1,7,CountSensor_Count_Get(),5);//在1行7列显示CountSensor_Count_Get返回值,长度为5 } }
红外传感器计数函数.c如下:
#include "stm32f10x.h" // Device header uint16_t CountSensor_Count;//中断触发次数函数
//外部信号总思路:(配置外部中断)GPIO-->AFIO-->EXTI-->NVIC-->(中断函数)CPU
//配置外部中断
void CountSensor_Init(void)//配置外部中断 { //第一步,初始化时钟(注:只有GPIO和AFIO需要开启时钟,且外设和总线要对应) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//初始化时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//初始化AFIO //注:学习时,如果不中断哪个外设接到哪个总线,右键函数名,跳转定义查看(防止APB2接GPIOA等类似错误) //第二步,配置GPIO GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//IPU为上拉输入,默认为高电平 //不知道选什么模式,需要参考数据手册中的第八章:通用和复用功能I/O(GPIO AFIO). GPIO_InitStructure.GPIO_Pin=GPIO_Pin_14; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); //第三步,配置AFIO(不需要开启时钟)---点击gpio.h查看函数(AFIO没用专门的库函数) GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);//选择数据选择器函数,选择引脚。B14脚进,EXTI14出 // 此处推荐跳转函数定义,查找@param的函数参数 //以下内容为Start文件夹里的stm32.GPIO.h相关函数,此处粗略介绍一下(在gpio.h的最后) //void GPIO_AFIODeInit(void);//复位AFIO函数,调用该函数,清除AFIO //void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //锁定GPIO配置,调用函数所指定的引脚,参数被锁定,不能更改。 //void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource); AFIO事件输出功能。 //void GPIO_EventOutputCmd(FunctionalState NewState); AFIO事件输出功能。 //void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);//重影设函数 //void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);//选择数据选择器函数,选择引脚。 //void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);//以太网使用时的函数 //第四步,配置EXTI----可点击exti.h文件查看函数 //将EXTI的第十四个线路配置为中断模式,下降沿触发,开启中断,并将EXTI传递给NVIC EXTI_InitTypeDef EXTI_InitStruct; EXTI_InitStruct.EXTI_Line=EXTI_Line14;//查看函数配置需要跳转定义查找@param,在下方,选择num,再次跳转,选择Line14 EXTI_InitStruct.EXTI_LineCmd=ENABLE;//指定选择中段线的新状态,应选择开启中断 EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;//使用中断模式 EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;//EXTI_Trigger_Falling为下降沿触发 EXTI_Init(&EXTI_InitStruct);//查看函数配置需要跳转定义查找@pram //以下内容为Start文件夹里的stm32.exti.h相关函数,此处粗略介绍一下(在exti.h的最后) //void EXTI_DeInit(void);//清除EXTI配置,恢复成上电默认状态 //void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);//调用后,根据结构体的参数配置EXTI外设,与初始化GPIO一致 //void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);//把参数传递的结构体变量赋默认值。 //void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);//软件触发外部中断。 //以下四个函数是标志位检测时使用的,前两个为主函数里查看和清除标志位,后两个为中断函数中查看和清除标志位 //FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);//主函数查看标志位 //void EXTI_ClearFlag(uint32_t EXTI_Line);//主函数清除标志位 //ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);//中断函数查看标志位 //void EXTI_ClearITPendingBit(uint32_t EXTI_Line);//中断函数清除标志位 //第五步,配置NVIC(不需要开启时钟,因为是内核外设) NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择分组方式:两位抢占,两位响应 //跳转定义,参数查找@param,函数解释查找@brief NVIC_InitTypeDef NVIC_InitStruct;//重定义结构体... NVIC_InitStruct.NVIC_IRQChannel=EXTI15_10_IRQn;//EXTI的15-10都合并到了EXTI15_10_IRQn,所以选择这个参数 NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;//此处配置较随意,设置为1,1 //因为优先级配置多使用于多个优先级同时需要起作用,需要"排次序时",此处只有一个优先级 NVIC_InitStruct.NVIC_IRQChannelSubPriority=1; NVIC_Init(&NVIC_InitStruct);//初始化函数需要配置上面的结构体 //以下内容为Start文件夹里的misc.h(杂糅函数)相关函数,此处粗略介绍一下(在misc.h的最后) //void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);//中断分组,参数是中断分组的方式 //void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);//根据结构体里面指定的参数初始化NVIC //void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);//设置中断向量表 //void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);//系统低功耗配置 } void EXTI15_10_IRQHandler(void)//中断函数 //中断函数都是无参无返回值的,建议从启动文件复制过来,在startup_stm3210x_mds.s文件里(119行) { //判断是不是EXTI14 if(EXTI_GetITStatus(EXTI_Line14)==SET)//中断函数查看标志位 { CountSensor_Count++;//中断触发次数函数++ EXTI_ClearITPendingBit(EXTI_Line14); //中断程序结束后,需要清除中断标志位,跳出中断,否则程序就一直响应中断. } } //统计中断触发次数函数 uint16_t CountSensor_Count_Get(void) { return CountSensor_Count; }
红外传感器.h代码如下:
#ifndef __COUNT_SENSOR_H #define __COUNT_SENSOR_H void CountSensor_Init(void); //void EXTI15_10_IRQHandler(void);//注:中断函数不需要声明,会自动调用的 uint16_t CountSensor_Count_Get(void); #endif