stm32教程:EXTI外部中断应用

早上好啊大佬们,上一期我们讲了EXTI外部中断的原理以及基础代码的书写,这一期就来尝试一下用它来写一些有实际效能的工程吧。

这一期里,我用两个案例代码来让大家感受一下外部中断的作用和使用价值。

旋转编码器计数

整体思路讲解

这里,我们需要使用到 OLED 和 旋转编码器。

先来说一下旋转编码器 ——

我们使用的是EC11旋转编码器,这是一种增量式旋转编码器,拥有A、B、C三个输出通道,其中A、B两相输出正交信号,相位差为90°,C相输出零脉冲信号,用于标识位置。

当编码器正转时,A相的输出信号超前B相90°;当编码器反转时,A相滞后B相90°。我们在程序中可以根据A、B两相信号输出的先后顺序,来判断旋转编码器是正转还是反转

波形图 显示结果就是:

然后对于我们的代码实现思路就很清晰了,

检测A相的下降沿或上升沿,然后判断B相的电平高低,用来区分正转还是反转。

接线

OLEDSTM32
VCC3.3V
GNDGND
SCLPB8
SDAPB9
旋转编码器STM32
VCC3.3V
GNDGND
APA0
BPA1

代码

main.c

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "count.h"int main()
{OLED_Init();External_Init();OLED_ShowString(0, 0, "cnt:", OLED_8X16);OLED_Update();while(1){OLED_ShowNum(32, 0, Count_Get(), 3, OLED_8X16);OLED_Update();}}

count.c

#include "stm32f10x.h"                  // Device headerint16_t cnt = 0;void External_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //打开AFIO的时钟//然后打开 EXTI 和 NVIC 的外设时钟,但是出于它们是一直打开的,所以就不需要了。GPIO_InitTypeDef GPIO_InitStructure;/*配置GPIO*/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(GPIOA, &GPIO_InitStructure);/*重映射GPIO*/GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //将外部中断的0号线映射到GPIOBGPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1); //将外部中断的1号线映射到GPIOB/*配置EXTI*/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); //EXTI中断初始化/*配置NVIC*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组, 2抢占,2响应//这个分组函数一个工程只选择一次,多次调用会覆盖之前的配置NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			//选择配置NVIC的EXTI0线NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;			//选择配置NVIC的EXTI1线NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;			//指定NVIC线路的响应优先级为2NVIC_Init(&NVIC_InitStructure);//这里就是两个中断线的写法,但是这里的中断配置比较随意,因为两种情况不会同时发生
}int16_t Count_Get(void)
{return cnt;
}void EXTI0_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line0) == SET) //判断返回值是否为 SET{// 如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0){if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == 0)		//PA0的下降沿触发中断,此时检测另一相PA1的电平,目的是判断旋转方向{cnt --;					//此方向定义为反转,计数变量自减}}EXTI_ClearITPendingBit(EXTI_Line0); //重置中断判断位,否则会卡死在中断函数中}
}void EXTI1_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line1) == SET) //判断返回值是否为 SET{// 如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == 0){if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0)		//PA1的下降沿触发中断,此时检测另一相PA0的电平,目的是判断旋转方向{cnt ++;					//此方向定义为反转,计数变量自减}}EXTI_ClearITPendingBit(EXTI_Line1); //重置中断判断位,否则会卡死在中断函数中}
}

count.h

#ifndef __COUNT_H
#define __COUNT_Hvoid External_Init(void);
int16_t Count_Get(void);#endif

红外避障实现

当车辆行驶时,前方遇到障碍物被我们的红外探测到,就需要停下当前的所有行为,进行避障操作。

对于红外部分内容,大家可以看看之前的一篇文章。

stm32教程:红外循迹模块 & 红外避障模块 & 光电门模块-CSDN博客

整体功能讲解

我们这里主要是来演示一下EXTI外部中断,所以这里就简单模拟一下。

首先是红外避障模块,当它没有探测到物品时,车辆正常行驶。

当它探测到物品时,就需要进行紧急避障。

然后,我们用一个LED灯来模拟车辆状态,车辆正常行驶时,LED灯灭。

车辆进行避障时,LED灯亮

接线

红外STM32
VCC3.3V
GNDGND
OUTPB7

LED我们使用STM32系统板的板载LED

代码

bizhang.c

#include "stm32f10x.h"                  // Device headervoid LED_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //PC13是板载的LEDGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_SetBits(GPIOC, GPIO_Pin_13);
}void LED_Turn(void)
{if (GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13) == 0)		//获取输出寄存器的状态,如果当前引脚输出低电平{GPIO_SetBits(GPIOC, GPIO_Pin_13);					//则设置PC13引脚为高电平,高电平灭}else													//否则,即当前引脚输出高电平{GPIO_ResetBits(GPIOC, GPIO_Pin_13);					//则设置PC13引脚为低电平,低电平亮}
}void External_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //打开AFIO的时钟//然后打开 EXTI 和 NVIC 的外设时钟,但是出于它们是一直打开的,所以就不需要了。GPIO_InitTypeDef GPIO_InitStructure;/*配置GPIO*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);/*重映射GPIO*/GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource7); //将外部中断的7号线映射到GPIOB/*配置EXTI*/EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line7;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //改成双向,上升沿切换为避障,下降沿切换为正常行驶。EXTI_Init(&EXTI_InitStructure); //EXTI中断初始化/*配置NVIC*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组, 2抢占,2响应//这个分组函数一个工程只选择一次,多次调用会覆盖之前的配置NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;			//选择配置NVIC的EXTI9_5线NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1NVIC_Init(&NVIC_InitStructure);
}void EXTI9_5_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line7) == SET) //判断返回值是否为 SET{LED_Turn();EXTI_ClearITPendingBit(EXTI_Line7); //重置中断判断位,否则会卡死在中断函数中}
}

bizhang.h

#ifndef __BIZHANG_H
#define __BIZHANG_Hvoid LED_Init(void);
void LED_Turn(void);
void External_Init(void);#endif

main.c

#include "stm32f10x.h"                  // Device header
#include "bizhang.h"int main()
{LED_Init();External_Init();while(1){}}

尾声

OK,那么这一期就到这里了,如果需要这期的代码,可以私信我。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/69735.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

护眼好帮手:Windows显示器调节工具

在长时间使用电脑的过程中,显示器的亮度和色温对眼睛的舒适度有着重要影响。传统的显示器调节方式不仅操作繁琐,而且在低亮度下容易导致色彩失真。因此,今天我想为大家介绍一款适用于Windows系统的护眼工具,它可以帮助你轻松调节显…

Mysql进阶学习

目录 一.Mysql服务器内部架构(了解) 二.Mysql引擎 2.1 innodb引擎 2.2 myisam引擎 三.索引 3.1索引分类 3.2mysql索引数据结构 3.3聚簇索引和非聚簇索引 3.4回表查询 3.5索引下推 四.事务 数据库事务特征 事务隔离性,隔离级别 事务实现原理 五.锁 ①…

解锁维特比算法:探寻复杂系统的最优解密码

引言 在复杂的技术世界中,维特比算法以其独特的魅力和广泛的应用,成为通信、自然语言处理、生物信息学等领域的关键技术。今天,让我们一同深入探索维特比算法的奥秘。 一、维特比算法的诞生背景 维特比算法由安德鲁・维特比在 1967 年提出…

使用 postman 测试思源笔记接口

思源笔记 API 权鉴 官方文档-中文:https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md 权鉴相关介绍截图: 对应的xxx,在软件中查看 如上图:在每次发送 API 请求时,需要在 Header 中添加 以下键值对&a…

sizeof和strlen的对比与一些杂记

1.sizeof和strlen的对比 1.1sizeof (1)sizeof是一种操作符 (2)sizeof计算的是类型或变量所占空间的大小,单位是字节 注意事项: (1)sizeof 返回的值类型是 size_t,这是一…

实测数据处理(Wk算法处理)——SAR成像算法系列(十二)

系列文章目录 《SAR学习笔记-SAR成像算法系列(一)》 《wk算法-SAR成像算法系列(五)》 文章目录 前言 一、算法流程 1.1、回波信号生成 2.2 Stolt插值 2.3 距离脉冲压缩 2.4 方位脉冲压缩 2.5 SAR成像 二、仿真实验 2.1、仿真参数…

FFmpeg rtmp推流直播

文章目录 rtmp协议RTMP协议组成RTMP的握手过程RTMP流的创建RTMP消息格式Chunking(Message 分块) rtmp服务器搭建Nginx服务器配置Nginx服务器 librtmp库编译推流 rtmp协议 RTMP(Real Time Messaging Protocol)是由Adobe公司基于Flash Player播放器对应的…

docker搭建redis集群(三主三从)

本篇文章不包含理论解释,直接开始集群(三主三从)搭建 环境 centos7 docker 26.1.4 redis latest (7.4.2) 服务器搭建以及环境配置 请查看本系列前几篇博客 默认已搭建好三个虚拟机并安装配置好docker 相关博客&#xf…

接口使用实例(2)

大家好,今天我们来解答一下昨天留下的一个问题,并且继续来看一些接口使用实例。 通过String类中重写的方法compareTo来实现我们的比较name的需求: 2,用Comparator接口来实现类的比较(比较器) 了解即可,以后会详细讲。 知识点:C…

基于Springboot的社区药房管理系统

博主介绍:java高级开发,从事互联网行业多年,熟悉各种主流语言,精通java、python、php、爬虫、web开发,已经做了多年的设计程序开发,开发过上千套设计程序,没有什么华丽的语言,只有实…

vue框架技术相关概述以及前端框架整合

vue框架技术概述及前端框架整合 1 node.js 介绍:什么是node.js Node.js就是运行在服务端的JavaScript。 Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎。 作用 1 运行java需要安装JDK,而Node.js是JavaScript的运行环…

MATLAB的数据类型和各类数据类型转化示例

一、MATLAB的数据类型 在MATLAB中 ,数据类型是非常重要的概念,因为它们决定了如何存储和操作数据。MATLAB支持数值型、字符型、字符串型、逻辑型、结构体、单元数组、数组和矩阵等多种数据类型。MATLAB 是一种动态类型语言,这意味着变量的数…

密码强度验证代码解析:C语言实现与细节剖析

在日常的应用开发中,密码强度验证是保障用户账户安全的重要环节。今天,我们就来深入分析一段用C语言编写的密码强度验证代码,看看它是如何实现对密码强度的多维度检测的。 代码整体结构 这段C语言代码主要实现了对输入密码的一系列规则验证&a…

蓝桥杯模拟算法:多项式输出

P1067 [NOIP2009 普及组] 多项式输出 - 洛谷 | 计算机科学教育新生态 这道题是一道模拟题&#xff0c;我们需要分情况讨论&#xff0c;我们需要做一下分类讨论 #include <iostream> #include <cstdlib> using namespace std;int main() {int n;cin >> n;for…

Pytorch框架从入门到精通

目录 一、Tensors 1.1 初始化一个Tensor 1&#xff09;赋值初始化 2&#xff09;从 NumPy 数组初始化 3&#xff09;从另一个张量 4&#xff09;使用随机值或常量值 1.2 Tensor 的属性 1.3 对 Tensor 的操作 1.3.1 总体介绍 1.3.2 索引和切片 1.3.3 算术运算 矩阵乘…

2024年数据记录

笔者注册时间超过98.06%的用户 CSDN 原力是衡量一个用户在 CSDN 的贡献和影响力的系统&#xff0c;笔者原力值超过99.99%的用户 其他年度数据

【已解决】黑马点评项目Redis版本替换过程的数据迁移

黑马点评项目Redis版本替换过程的数据迁移 【哭哭哭】附近商户中需要用到的GEO功能只在Redis 6.2以上版本生效 如果用的是老版本&#xff0c;美食/KTV的主页能正常返回&#xff0c;但无法显示内容 上次好不容易升到了5.0以上版本&#xff0c;现在又用不了了 Redis 6.2的windo…

Win11下帝国时代2无法启动解决方法

鼠标右键点图标&#xff0c;选择属性 点开始&#xff0c;输入启用和关闭

android主题设置为..DarkActionBar.Bridge时自定义DatePicker选中日期颜色

安卓自定义DatePicker选中日期颜色 背景&#xff1a;解决方案&#xff1a;方案一&#xff1a;方案二&#xff1a;实践效果&#xff1a; 背景&#xff1a; 最近在尝试用原生安卓实现仿element-ui表单校验功能&#xff0c;其中的的选择日期涉及到安卓DatePicker组件的使用&#…

SpringBoot 基础(Spring)

SpringBoot 基础&#xff08;Spring) Bean 注解标记和扫描 (IoC) 配置类概念 SpringBootConfiguration 或者 Configuration 注解标注的类就是配置类配置类本身也会加入 IoC 容器* Configuration public class configuration1 {}SpringBootConfiguration public class configur…