STM32学习笔记之EXTI应用实例:对射式红外传感器计次 |
您所在的位置:网站首页 › 如何关闭红外线遮挡 › STM32学习笔记之EXTI应用实例:对射式红外传感器计次 |
系列文章目录
第N章 STM32学习笔记之OLED屏幕 第N章 STM32学习笔记之EXTI外部中断 第N章 STM32学习笔记之对射式红外传感器计次 目录 系列文章目录 一、对射式红外传感器 1.简介 2.硬件电路 二、软件驱动 1.模块化编程 2.初始化函数 a.开启外设时钟 b.配置GPIO c.配置AFIO d.配置EXTI e.配置NVIC 3.编写中断函数 4.声明初始化函数 5.main函数处理 三、功能实现 1.传感器.c文件 1.传感器.h文件 3.main.c文件 总结 前言: 笔记:跟着B站教学视频做的学习笔记,基于STM32F103C8T6 一、对射式红外传感器 1.简介测速传感器模块,可用于电机转速检测,脉冲计数,位置限位等 输出状态指示灯:输出高电平-灯灭 输出低电平-灯亮遮挡:输出低电平;无遮挡:输出高电平输出形式:数字开关量输出(0到1) 2.硬件电路VCC:接电源正极-3.3V~5V GND:接电源负极 DO:TTL开关信号输出,这里接STMF103C8T6的PB14引脚 AO:此模块不起作用,不用接 二、软件驱动 1.模块化编程新增红外传感器模块.c和.h文件和一些预处理,详情见第N章 STM32.... 2.初始化函数根据EXTI基本结构图可以看出,使用外部中断需要配置GPIO、AFIO、EXTI、NVIC这些外设 a.开启外设时钟外设工作需要先开启时钟,由于EXTI和NVIC外设时钟是一直开启的,所以只需要开启GPIO和AFIO的时钟就好 void CountSensor_Init(void) { //GPIO时钟在APB2总线上 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //AFIO时钟在APB2总线上 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //NVIC和EXTI时钟总是开着的,不需要再开启 } b.配置GPIO 定义一个GPIO结构体GPIO_Mode:根据数据手册得知有三种配置方式,这里配置成上拉输入,即默认为高电平输入方式 GPIO_Pin:这里选择14号口GPIO_Speed:不是很重要,选择50M即可调用GPIO初始化函数对GPIO结构体进行初始化void CountSensor_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); } c.配置AFIOAFIO的库函数是和GPIO在同一个文件里的,可以在GPIO的.h文件里找 调用GPIO_EXTILineConfig()函数来配置AFIO数据选择器,配置完成后就进入到EXTI电路了void CountSensor_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); //因为是PB14,所以两个参数分别是PortSourceGPIOB和PinSource14 GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14); } d.配置EXTI在库函数中找到exti.h文件 定义一个EXTI结构体EXTI_Line:指定配置的中断线,因为需要用PB14所在的第14个线路,所以选择EXTI_Line14EXTI_LineCmd:指定中断线的状态,因为要开启中断,所以选择“ENABLE”EXTI_Mode:指定外部中断线的模式,中断模式和事件模式中,选择“中断模式”EXTI_Trigger:指定触发信号的有效边缘,自我选择“上升沿触发”调用EXTI初始化函数对EXTI结构体进行初始化void CountSensor_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14); 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_Rising; EXTI_Init(&EXTI_InitStruct); } e.配置NVIC因为NVIC是内核外设,它的库函数被ST发配到misc.h(杂项)文件里,在这里找它的库函数 NVIC_PriorityGroupConfig:指定下中断的分组,这里选择两位抢占两位响应定义一个NVIC结构体NVIC_IRQChannel:因为库函数所以兼容所以的F1系列芯片,但是不同的芯片中断通道列表是不一样的,所以有很多条件编译,这里选择MD(中等密度)里的EXTI15_10_IRQn NVIC_IRQChannelCmd:指定中断通道是使能还是失能,选择“ENABLE”NVIC_IRQChannelPreemptionPriority:抢占优先级,这里只有一个中断源,比较随意,设置为1即可NVIC_IRQChannelSubPriority:响应优先级,这里只有一个中断源,比较随意,设置为1即可调用NVIC初始化函数初始化结构体void CountSensor_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14); 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_Rising; EXTI_Init(&EXTI_InitStruct); 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); } 3.编写中断函数在STM32中,中断通道的名字都是固定的,每个中断通道都对应一个中断函数,可以在启动文件里查看,里面以“ IRQHandler ”结尾的字符串就是中断函数的名字 找到“ EXTI15_10_IRQHandler ”这一项,这就是EXTI15_10的中断函数,复制后回到.c文件里编写中断函数 中断函数都是无参无返回值的中断函数名字不要写错,写错就进不来中断void EXTI15_10_IRQHandler(void) { } 中断函数一般先进行一个中断标志位的判断,因为这个函数EXTI10~15都能进来,所以要判断下是不是EXTI14进来的,所以用EXTI_GetFlagStatus函数看下中断标志位是不是1,它的返回值是SET或者RESET,即看下这个返回值是不是等于SETvoid EXTI15_10_IRQHandler(void) { if(EXTI_GetFlagStatus(EXTI_Line14) == SET) { } } 中断程序结束后,一定要再调用下清除中断标志位的函数,因为只要标志位为1,程序就会调到中断函数,不清除中断标志位,它就会一直申请中断,然后不断响应中断,程序就会卡死void EXTI15_10_IRQHandler(void) { if(EXTI_GetFlagStatus(EXTI_Line14) == SET) { EXTI_ClearFlag(EXTI_Line14); } } 4.声明初始化函数在.h文件里声明刚刚编写的传感器初始化函数,这样在别的文件里就能调用该函数了,中断函数不用声明 5.main函数处理声明红外传感器.h文件和调用初始化函数 三、功能实现 1.传感器.c文件定义一个变量“Count”,用于计数 uint16_t Count; 在中断函数里让Count++ void EXTI15_10_IRQHandler(void) { if(EXTI_GetFlagStatus(EXTI_Line14) == SET) { Count ++; EXTI_ClearFlag(EXTI_Line14); } } 写一个Get函数,返回Count值 uint16_t GetCount(void) { return Count; } 1.传感器.h文件声明Get函数 3.main.c文件在OLED屏幕上显示计数,即“Count:0000X” int main() { OLED_Init(); CountSensor_Init(); OLED_ShowString(1,1,"Count:");//显示“Count”这个字符串 while(1) { OLED_ShowNum(1,7,GetCount(),5);//显示计数 } } 最终效果 总结本节内容是基于EXTI外部中断内容来进行的实操,一些外设的初始化步骤基本都差不多,驱动写出来后,至于怎么让其计数就见仁见智了。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |