STM32 学习笔记_5 调试方法;外部中断

news2024/9/21 8:02:55

调试

OLED:方便,试试更新,但是显示框小。

串口:数据全,但是带电脑不方便。

MDK 自带 debug

OLED 调试

4个引脚的:3.3~5V 电压,地,SCL SDA 的 IIC。

我们把 GND-VCC-SCL-SDA 接到 B6-B9 上,B6 B7接高低电平。代码和51非常像,先使用老师的代码调试即可。

DeBug 调试

编译后点击放大镜d的符号。会显示汇编代码寄存器等信息,这些C编程都不用太管。

debug 从左到右的按钮意思:复位,全速运行,停止,向下一行,跳出当前函数,跳转到光标指定位置。

窗口部分:命令窗口,反汇编窗口,符号窗口(里面可以查看一些寄存器的结构,右键添加到 watch 窗口还可以实时查看值)。

Peripherals-System View 里面可以查看外设实时的值。

中断

可以使程序先停止运行去处理一些事情。

中断优先级:有一定的优先级。

中断嵌套:低优先级中断处理时,可以被高优先级中断中断。

看门狗中断:程序定期喂狗,一段时间不喂触发,可能是卡死了,可以加一些校验是否卡死的逻辑。

PVD 中断:电量低触发,可以提醒充电。

NVIC 可以对中断的优先级分组,他接收多个中断,按优先级顺序分配给 CPU。0最高,15最低。优先级相同的按中断号排队。

有两种调度方法,一种是插队的,需要把当前中断处理完再调度下一个;另一种是不插队的,可以打断当前中断(抢占)。

EXTI

检测 GPIO 电平变化触发中断(PVD RTC USB Ethernet 也包含在内),可以上升 下降 双边沿 或软件触发。

所有 GPIO 引脚都可以,但是同 Pin 的不可以同时做中断引脚(PA1 PB1)。

32有两种触发响应的方式,一种是中断响应,发生响应时去 CPU 触发中断。一种是事件响应,发生响应时转而去触发其他的事件。

外部中断只有 16 个Pin,所以所有 GPIO 通过 AFIO 中断引脚选择,挑选一个 Pin 到 EXTI 边沿检测中。

AFIO 还有一个功能,让有复用功能的引脚重映射的功能。

image-20230423185714575

为了节省线路,9-5, 15-10 会触发同一个中断函数,因此需要通过标志位区分。

image-20230423190008581

边沿检测电路和软件中断时间寄存器只要有一个是1,就让或门结果=1.

触发事件就走下路,触发中断就走中路。

中断屏蔽寄存器:是否开启中断。

请求挂起寄存器:是否开启了当前引脚的中断。

什么时候用外部中断?

比如突发的需要读取的转瞬即逝的信号。比如旋转编码器。

按键需要处理消抖,而且也不是转瞬即逝,建议持续循环读取或者定时器中断读取。

旋转编码器

光栅式内部有红外光,旋转时会遮挡-接收-遮挡-接收,进而测定旋转速度。但是这种无法测定方向。

机械触点式旋转时依次接通触点,且左右旋转不同向会产生有相位差的方波。不适合高速旋转的电机测速。

其内部还有一个按键。

霍尔传感器式感应内部磁铁的旋转。

对射式红外传感器

很简单,内部有一个发送和接收红外线的部分,挡住时信号就会变化。

代码:对射式红外传感器

首先介绍一下 GPIO 里和中断相关的函数。

image-20230424062717573

我们设置中断源就需要最后一个函数,这个函数操作 AFIO 选脚。

//1. RCC 2. GPIO Mode 3. AFIO choose a pin 4. EXTI set trigger mode and IT response/Event response 5. set NVIC priority
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
    //EXTI NVIC don't need open RCC.
    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);

然后看一下 stm32f10x_exti.h 的内容:

image-20230424063229137

复位,初始化,结构体赋初值,软件中断,查看和清除标志位状态,查看和清除中断标志位状态。

EXTI_Initstruct 包含的参数:中断线(决定引脚),线命令(启用或禁用),中断模式(事件,中断),触发(上升,下降,双边沿)。

EXTI_InitTypeDef EXTI_InitStructure;
    EXTI_InitStructure.EXTI_Line=EXTI_Line14;
    EXTI_InitStructure.EXTI_LineCmd=ENABLE;
    EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
    EXTI_Init(&EXTI_InitStructure);

最后配置 NVIC 中断。中断函数信息在 misc.h 中:

image-20230424064523788

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//each chip can only set this group once. 2 means 2 bits for pre-emption priority, 2 bits for subpriority.
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;//choose a bit to open it
    NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//可以去查看一下设置的 EXTI_Mode 允许的范围
    NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
    NVIC_Init(&NVIC_InitStructure);

这样中断初始化函数就定义好了,

接下来写中断函数,中断函数名字固定,在启动文件中,以 IRQHandler 结尾的函数。找到对应端口的。

我们要先判断一下是不是当前的中断线(因为10-15通用),再清除标志位。

void EXTI15_10_IRQHandler(void){
    if(EXTI_GetITStatus(EXTI_Line14)==SET){
        EXTI_ClearITPendingBit(EXTI_Line14);
    }
}

然后在 main.c 中 include 该文件,并打开调试,在中断函数里打一个断点,然后全速运行,试一下挡住红外线会不会在中断处中断。

image-20230424070621393

成功停下了~

然后我们写一个示例,触发一次中断计数器++,并在 OLED 上打印计数器值。

则我们在 CountSensor 里定义一个全局变量,且写一个 Get 函数。

uint16_t Count_Get(void){
    return count;
}

main 里获取这个值并展现在 OLED 上就能记录了有几次挡住。

这里不建议在中断函数里对 OLED 进行操作,因为我们的中断本来就是暂停程序去执行的,如果程序正处理着 OLED 函数,被我们中断了,我们又在中断里操作了 OLED,就会出问题。因此我们这里采取的是设定一个变量,主函数可以访问其值,然后在主函数中再操作 OLED。

代码:旋转编码器

机械旋转编码器左拧右拧时触发触点接通。我们设置左拧-1,右拧+1,根据 OLED 上的数值判断现在拧到什么地步了。

数据处理:检测到左拧(A下降沿,B低电平),返回-1,右拧(B下降沿,A低电平),返回+1,主函数 count+返回值。

下图为右拧(顺时针),先检测B下降沿,再检测A低电平,即可确认确实是顺时针,count++。

img

#include "stm32f10x.h"                  // Device header

int16_t count;
void Encoder_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_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO_InitStructure);
    
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
    
    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);
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
    NVIC_Init(&NVIC_InitStructure);
    
    NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
    
    NVIC_Init(&NVIC_InitStructure);
    
}

int16_t Counter_Get(void){
    int16_t temp=count;
    count=0;
    return temp;
}

void EXTI0_IRQHandler(void){
    if(EXTI_GetITStatus(EXTI_Line0)==SET){
        if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)==0){count--;
        }
        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}

void EXTI1_IRQHandler(void){
    if(EXTI_GetITStatus(EXTI_Line1)==SET){
        if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0)==0){count++;
        }
        EXTI_ClearITPendingBit(EXTI_Line1);
    }
}

#include "stm32f10x.h"
#include "Delay.h"
#include "Encoder.h"
#include "OLED.h"
int main(void){
    int16_t count;
    OLED_Init();
    OLED_ShowChar(1,1,'A');
    OLED_ShowString(1,3,"Hello World!");
    Encoder_Init();
    while(1){
        count+=Counter_Get();
        OLED_ShowNum(2,1,count,5);
    }
}

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

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

相关文章

微信小程序国际化

参考文件: 国际化(微信小程序TS 微信小程序国际化 一、环境目录 注意:一定要注意项目目录结构,新建文件夹miniprogram,并把前面新建的文件移到这个目录中 二、安装根目录依赖 在NEW-FAN-CLOCK1 中安装根目录依赖 npm i -D gulp minipro…

provide和inject,Teleport,Fragment

作用:实现祖孙组件间通信 套路:父组件有一个provide选项来提供数据,子组件有一个inject选项来开始使用这些数据 父组件 只要provide了,那么后代都能拿到,父子之间一般使用props,祖孙组件一般采用provide 响应式数据判断 isRef:…

TIA博途中文本列表的具体使用方法介绍与示例

TIA博途中文本列表的具体使用方法介绍与示例 一、 文本列表的概念 应用场景:设备的当前操作模式、当前的运行流程、当前的运行状态等 功能介绍:  根据信号数值的不同,显示不同的文本  通过下拉列表选择不同的文本给变量赋值  通过文本列表实现配方元素数值的选择输入…

直播系统开发中如何优化API接口的并发

概述 在直播系统中,API接口并发的优化是非常重要的,因为它可以提高系统的稳定性和性能。本文将介绍一些优化API接口并发的方法。 理解API接口并发 在直播系统中,API接口是用于处理客户端请求的关键组件。由于许多客户端同时连接到系统&…

云计算与多云混合云架构的比较与选择

第一章:引言 随着互联网的迅速发展,云计算逐渐成为了一个热门话题。而随着企业的不断发展,多云混合云架构逐渐成为了一种重要的技术架构。本文将从中国国内资深IT专家的角度,对云计算和多云混合云架构进行比较和选择的分析&#…

IPSec数据报文封装格式详解

以下遵循GMT 0022-2014 IPSec VPN 技术规范。 IPsec提供两种封装协议AH(鉴别头,Authentication Header)和ESP(封装安全载荷,Encapsulation Security Payload)。 AH可以提供无连接的完整性、数据源鉴别和抗重…

Linux 进程通讯 - 共享内存机制

共享内存机制,就是在物理内存中划分一段内存,多个进程间可以共同访问这段内存,也可对这段内存做修改操作,从而达到进程通讯的效果! 共享内存机制是允许两个或多个进程(不相关或有亲缘关系)访问…

JavaWeb02(servlet)

目录 一.servlet 1.1 什么是servlet? 1.2 实现接口,初始代码 1.3 学会配置和映射 1.4 掌握servlet的生命周期 生命周期的各个阶段 1.5 获取servlet初始化参数和上下文参数 1.5.1 初始代码 推荐使用 1.5.2 初始化参数 1.5.3 上下文参数 1.6 servlet应用:处理用户登…

融云 CTO 岑裕:出海技术前沿探索和排「坑」实践

在本文中,你将看到以下内容: 全球通信网络在接入点、链路加速、服务商、协议等层面的动态演进; 进入到具体市场,禁运国、跨国拦截、区域一致性差等细节“坑点”如何应对; 融云如何从技术侧帮助开发者应对本地化用户体…

首发支持NOA的单征程3行泊一体域控,这家Tier1开“卷”

NOA正成为智能驾驶下半场的竞争焦点之一。 显然,NOA所处的L2/L2区间,在技术上仍然属于驾驶辅助领域,但在传统L2级ADAS功能的基础上增强了部分场景的功能ODD。在部分政策允许的国家和地区,可以实现有条件的「解放双手」。 高工智…

centos搭建vue3运行环境

一、安装 nodejs 1.下载&解压 Node.js官网:Download | Node.js cd /usr/local/src/wget -c https://nodejs.org/dist/v16.18.1/node-v16.18.1-linux-x64.tar.xz xz -d node-v16.18.1-linux-x64.tar.xz tar -xf node-v16.18.1-linux-x64.tarmv node-v…

threejs学习随笔(入门篇)

前言:three.js和webgl Three.js经常会和WebGL混淆, 但也并不总是,three.js其实是使用WebGL来绘制三维效果的。 WebGL是一个只能画点、线和三角形的非常底层的系统. 想要用WebGL来做一些实用的东西通常需要大量的代码, 这就是Thre…

C语言函数大全-- p 开头的函数

C语言函数大全 本篇介绍C语言函数大全-- p 开头的函数 1. perror 1.1 函数说明 函数声明函数功能void perror(const char *s);用于将当前错误码对应的错误信息打印到标准输出设备(通常是终端)。 参数: s : 用于描述错误类型或…

班级页面设计——【3-相关活动页面】内容使用HTML以及css和Javascripts技术

系列文章目录 班级页面设计——【1-登陆注册页面】_网页制作实现登录注册 班级页面设计——【2-主界面部分】_班级首页展示 文章目录 系列文章目录 前言 一、页面效果介绍 1.1、页面展示 1.2、简单介绍 二、代码展示部分 2.1、html代码部分 2.2、css代码部分 前言 …

C++(继承中)

目录: 1.基类和派生类对象赋值转换 2.派生类当中的6个默认成员函数 --------------------------------------------------------------------------------------------------------------------------- 派生类对象可以赋值给 基类的对象/基类的指针/基类的引用&am…

“量子计算+个性化医疗”!富士通和BSC利用张量网络推进新研究

​ (图片来源:网络) 富士通和巴塞罗那超级计算中心(BSC)正在签署一项合作协议,通过利用临床数据促进个性化医疗,并使用张量网络推进量子模拟技术。 双方将于2023年5月开始联合研究,第一个合作项目旨在利用不…

CSGO搬砖,每天1-2小时,23年最强副业非它莫属(内附操作流程)

自从我学会了CSGO搬运,我发现生活也有了不小的改变,多了一份收入,生活质量也就提高了一份。 其实刚接触CSGO,我压根就不相信这么能挣钱,因为在印象中,游戏供玩家娱乐竞技的,作为我这种技术渣渣…

VUE3如何定义less全局变量

默认已经安装好了less,这里不过多讲。 (1)首先我们需要下载一个插件依赖: npm i style-resources-loader --save-dev (2)VUE3里配置vue.config.js文件内容 代码: const path require("p…

U盘安装Windows11和ubuntu20.04双系统

准备: 一台PC电脑(我的是两个固态硬盘) 一个U盘(最好不小于32G) 下载安装工具: 老白菜u盘启动盘制作工具_u盘启动_u盘装系统下载尽在老白菜官网 最新UltraISO官方免费下载 - UltraISO软碟通中文官方网…

数据结构与算法(九) 树

大家好,我是半虹,这篇文章来讲树 树是一种常见的数据结构,其定义为:由有限个节点组成的具有层次关系的集合 解决树问题的关键是递归,递归的关键是分解子问题 对于树来说,递归函数只要考虑对单个节点如何处…