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,一经查实,立即删除!

相关文章

DeepSeek大模型技术深度解析:揭开Transformer架构的神秘面纱

摘要 DeepSeek大模型由北京深度求索人工智能基础技术研究有限公司开发,基于Transformer架构,具备卓越的自然语言理解和生成能力。该模型能够高效处理智能对话、文本生成和语义理解等复杂任务,标志着人工智能在自然语言处理领域的重大进展。 关…

Ubuntu 系统,如何使用双Titan V跑AI

要在Ubuntu系统中使用双NVIDIA Titan V GPU来运行人工智能任务,你需要确保几个关键组件正确安装和配置。以下是基本步骤: 安装Ubuntu操作系统: 下载最新版本的Ubuntu服务器或桌面版ISO文件。使用工具如Rufus(Windows)或…

ROS2---基础操作

工作空间(workspace) workspace是一个存放项目开发相关文件的文件夹。例如我们要开发一个机器人,我们可以创建一个工作空间,然后存放这个机器人不同功能的包(感知(雷达,相机等),运动&#xff0…

护眼好帮手: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…

doris:导入时实现数据转换

Doris 在数据导入时提供了强大的数据转换能力,可以简化部分数据处理流程,减少对额外 ETL 工具的依赖。主要支持以下四种转换方式: 列映射:将源数据列映射到目标表的不同列。 列变换:使用函数和表达式对源数据进行实时…

Bash 基础与进阶实践指南

目录 Bash 简介与基础基本命令与文件操作权限管理与用户管理重定向与管道变量与环境变量通配符与正则表达式Shell 脚本结构与控制流常用内建命令与技巧文本处理常用命令作业控制与进程管理别名与函数实用技巧与注意事项更多 Bash 进阶话题参考资源 1. Bash 简介与基础 1.1 什…

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播放器对应的…

鸿蒙开发在onPageShow中数据加载不完整的问题分析与解决

API Version 12 1、onPageShow()作什么的 首先说明下几个前端接口的区别: ArkUI-X的aboutToAppear()接口是一个生命周期接口,用于在页面即将显示之前调用。 在ArkUI-X中,aboutToAppear()接口是一个重要的生命周期接口,它会在页…

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

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

MinDoc 安装与部署

下载可执行文件 mindoc mindoc_linux_amd64.zip 上传并解压压缩包 cd /opt mkdir mindoc cd mindocunzip mindoc_linux_amd64.zip 创建数据库 CREATE DATABASE mindoc_db DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; 配置数据库 将解压目录下 conf/app.conf.exam…

ESP32-S3模组上跑通esp32-camera(40)

接前一篇文章:ESP32-S3模组上跑通esp32-camera(39) 一、OV5640初始化 2. 相机初始化及图像传感器配置 上一回继续对reset函数的后一段代码进行解析。为了便于理解和回顾,再次贴出reset函数源码,在components\esp32-camera\sensors\ov5640.c中,如下: static int reset…

接口使用实例(2)

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

007 JSON Web Token

文章目录 https://doc.hutool.cn/pages/jwt/#jwt%E4%BB%8B%E7%BB%8D JWT是一种用于双方之间安全传输信息的简洁的、URL安全的令牌标准。这个标准由互联网工程任务组(IETF)发表,定义了一种紧凑且自包含的方式,用于在各方之间作为JSON对象安全地传输信息。…

【 AI agents】letta:2024年代理堆栈演进(中英文翻译)

The AI agents stack AI 代理堆栈 November 14, 2024 11月 14, 2024原文: The AI agents stack官方教程教程学习笔记: 【memgpt】letta 课程1/2:从头实现一个自我编辑、记忆和多步骤推理的代理Understanding the AI agents landscape 了解 AI 代理环境 Although we see a …

vim操作简要记录

操作容易忘记,记录一下基本使用的 :wq保存退出 :w :q :q! :wq! i I a A 方向键 h左 j下 k上 l右 dd删除方行(这其实是剪切行操作,不过一般用作删除,长按可删除,不过按.执行上一次操作删除更快) .执行上…