STM32+摁键与定时器实现Led灯控制(中断)

中断作为单片机开发必须掌握的内容,它能够在不搭载操作系统的情况下让我们体验多任务处理的快感,保证了高优先级任务的实时性,同时系统中断也能够提供给用户在核心发生错误之后进行处理的机会。STM32F103系列单片机中断非常强大,每个外设都可以产生中断,F103 在内核基础上搭载了一个中断响应系统, 支持为数众多的系统中断和外部中断。

本篇文章介绍了在STM32平台实现摁键中断控制LED亮灭以及定时器中断控制LED灯周期亮灭的功能。文章首先系统的介绍了中断有关的概念,然后通过摁键以及定时器两个实例带领读者直观的了解中断的作用。

中断概念

下面介绍一些中断的概念,这些概念依托于STM32平台,不同的芯片平台会有出入。

  • 中断:程序执行过程中CPU会遇到一些特殊情况,正在执行的程序被打断,cpu中止原来正在执行的程序,保存现场(保存上下文),转到处理异常情况或特殊事件的程序去执行,结束后恢复现场(被打断程序上下文),继续执行。

  • 异常:异常是中断的一种类型,其中断源是芯片内部,中断原因为比如执行了未定义指令、算术溢出、除零运算等发生在CPU内部的意外事件,这些异常的发生,会引起CPU运行相应的异常处理程序。下面是Stm32异常中断。
    • Reset:处理器在工作时, 突然收到复位信号, 就会触发该异常。
    • NMI(Non Maskable Interrupt):不可屏蔽中断,产生这个中断的时候,表示系统发生了致命的错误。
    • HardFault:硬件错误中断,数组越界,野指针,任务堆栈溢出,未初始化硬件却开始操作,或无中断服务函数等,都会导致这个中断产生。(总线地址不可访问等),Memory Management Fault(在只读写的区域尝试执行代码),Usage Fault(除零异常等)等异常都会导致硬件错误中断。
    • MemManage:访问了内存管理单元(MPU)定义的不合法的内存区域,比如向只读区域写入数据。
    • BusFault:在fetch指令、数据读写、fetch中断向量或中断时存储恢复寄存器栈情况下,检测到内存访问错误则产生。
    • UsageFault:检测到未定义指令或在存取内存时有未对齐,检测到除数为0也产生该异常。
    • SVC:系统服务调用,SVC异常由SVC指令触发,在很多系统中SVC机制用于实现应用任务访问系统资源。
    • DebugMon:调试监视器(断电, 数据观察点, 或外部调试请求),大部分debug的时候就是调试的时候遇到。
    • PendSV:可挂起的系统调用,由于PendSV在系统中被设置为最低优先级,因此只有当没有其他异常或者中断在执行时才会被执行。在一个操作系统环境中,当没有其他异常正在执行时,可以使用PendSV来进行上下文的切换。
    • SysTick:系统定时中断,系统定时器中断 一般用在操作系统的延时 。
  • 保存现场:保存现场是当发生异常/中断时,CPU跳转之前,就需要把r0-r3, r12, lr, psr这几个寄存器的值保存到栈中。

  • 恢复现场:STM实现了恢复现场的机制:CPU进入异常/中断服务程序时,LR寄存器保存的并不是中断前下一条指令的地址,而是会保存一个特殊的数值,被称为EXC_RETURN。异常/中断返回时,LR寄存器赋值给PC的值是一个被称为EXC_RETURN的值,而一旦CPU识别到PC的值等于EXC_RETURN的话,那么就会触发异常/中断返回机制,这个机制会帮我们把保存在栈中r0-r3, r12, lr, psr的寄存器的值恢复回去。
  •  中断抢占优先级和子优先级(又称响应优先级):所谓抢占式优先级和响应优先级,具有高抢占式优先级的中断可以在低抢占式优先级中断处理过程中被响应,即中断嵌套。当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。每一个中断源都必须定义2个优先级。
  • 中断优先级分组:一般情况下,系统代码执行过程中,只设置一次中断优先级分组,比如分组2,设置好分组之后一般不会再改变分组。随意改变分组会导致中断管理混乱,程序出现意想不到的执行结果。不同分组方式会影响中断抢占优先级和子优先级范围。

实现原理

摁键检测

EXTI(External interrupt/event controller):外部中断/事件控制器,管理了控制器的 20个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。 EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。

实现流程大体分为以下三个部分:

  1. 配置GPIO相应引脚:通过按键产生一个电平信号,然后经EXTI处理传入NVIC产生中断的,所以要配置连接按键的GPIO引脚,主要是设置相应的引脚模式为浮空输入
  2. 配置EXTI并映射GPIO引脚:打开相关的时钟,使用GPIO_EXTILineConfig()函数映射中断IO口,然后配置EXIT,包括中断源,触发类型等。
  3. 编写中断服务函数:stm32f10x_it.c中提前根据中断向量表生成了空的中断函数,我们只需要找到对应的中断函数编写中断服务内容即可。

定时器

定时器(Timer)最基本的功能就是定时了,本例我们使用的是通用定时器,它的时钟源经过以下路径计算得到:SYSCLK经过PLL的得到为72M,AHB时钟 =SYSCLK,APB1时钟=72M/2=36M,最终CK_INT的时钟频率倍频两倍为72M. 计数器的最终的频率还需要经过PSC预分频计算才能得到,基本定时器计数过程主要涉及到三个寄存器内容,分别是计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动重载寄存器(TIMx_ARR),这三个寄存器都是 16 位有效数字,即可设置值为 0至 65535。

定时事件生成时间主要由 TIMx_PSC 和 TIMx_ARR两个寄存器值决定,这个也就是定时器的周期。比如我们需要一个 1s周期的定时器,具体这两个寄存器值该如何设置? 假设,我们先设置 TIMx_ARR寄存器值为 9999,即当 TIMx_CNT从 0开始计算,刚好等于 9999时生成事件,总共计数 10000次,那么如果此时时钟源周期为 100us即可得到刚好 1s的定时周期。 接下来问题就是设置 TIMx_PSC寄存器值使得 CK_CNT 输出为 100us 周期(10000Hz)的时钟。预分频器的输入时钟 CK_PSC为 90MHz,所以设置预分频器值为(9000-1)即可满足。 


嵌入式程序

摁键检测实现LED灯亮灭

  • 中断通用配置
    static void NVIC_Config(void) /* 主要是配置中断源的优先级与打开使能中断通道 */
    {NVIC_InitTypeDef NVIC_InitStruct ;/* 配置中断优先级分组(设置抢占优先级和子优先级的分配),在函数在misc.c */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1) ;/* 配置初始化结构体 在misc.h中 *//* 配置中断源 在stm32f10x.h中 */NVIC_InitStruct.NVIC_IRQChannel = KEY1_EXTI_IRQN ;/* 配置抢占优先级 */NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1 ;/* 配置子优先级 */NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0 ;/* 使能中断通道 */NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;/* 调用初始化函数 */NVIC_Init(&NVIC_InitStruct) ;/* 对key2执行相同操作 */NVIC_InitStruct.NVIC_IRQChannel = KEY2_EXTI_IRQN ;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1 ;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1 ;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;NVIC_Init(&NVIC_InitStruct) ;}
  • 外部中断配置
    void EXTI_Config() /* 主要是连接EXTI与GPIO */
    {GPIO_InitTypeDef GPIO_InitStruct ;EXTI_InitTypeDef EXTI_InitStruct ;NVIC_Config();/* 初始化要与EXTI连接的GPIO *//* 开启GPIOA与GPIOC的时钟 */RCC_APB2PeriphClockCmd(KEY1_EXTI_GPIO_CLK | KEY2_EXTI_GPIO_CLK, ENABLE) ;GPIO_InitStruct.GPIO_Pin = KEY1_EXTI_GPIO_PIN ;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ;GPIO_Init(KEY1_EXTI_GPIO_PORT , &GPIO_InitStruct) ;GPIO_InitStruct.GPIO_Pin = KEY2_EXTI_GPIO_PIN ;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ;GPIO_Init(KEY2_EXTI_GPIO_PORT , &GPIO_InitStruct) ;/* 初始化EXTI外设 *//* EXTI的时钟要设置AFIO寄存器 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE) ;/* 选择作为EXTI线的GPIO引脚 */GPIO_EXTILineConfig( KEY1_GPIO_PORTSOURCE , KEY1_GPIO_PINSOURCE) ;/* 配置中断or事件线 */EXTI_InitStruct.EXTI_Line = KEY1_EXTI_LINE ;/* 使能EXTI线 */EXTI_InitStruct.EXTI_LineCmd = ENABLE ;/* 配置模式:中断or事件 */EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;/* 配置边沿触发 上升or下降 */EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising ;EXTI_Init(&EXTI_InitStruct) ;GPIO_EXTILineConfig( KEY2_GPIO_PORTSOURCE , KEY2_GPIO_PINSOURCE) ;EXTI_InitStruct.EXTI_Line = KEY2_EXTI_LINE ;EXTI_InitStruct.EXTI_LineCmd = ENABLE ;EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling ;EXTI_Init(&EXTI_InitStruct);
    }
    
  • 中断服务函数与主函数
    void EXTI0_IRQHandler(void)
    {if(  EXTI_GetITStatus(KEY1_EXTI_LINE)!=RESET){LED1_TOGGLE;   //LED1的亮灭状态反转}EXTI_ClearITPendingBit(KEY1_EXTI_LINE);}void EXTI15_10_IRQHandler(void)
    {if(  EXTI_GetITStatus(KEY2_EXTI_LINE)!=RESET){LED2_TOGGLE;   //LED2的亮灭状态反转}EXTI_ClearITPendingBit(KEY2_EXTI_LINE);}
    /
    #include "stm32f10x.h"
    #include "bsp_led.h"
    #include "bsp_key.h"int main(void)
    { LED_GPIO_Config();EXTI_Config();while(1) {}
    }

定时器实现LED灯闪烁

代码主要包含以下三个部分:

  1. 定时器初始化:TIM3时钟使能,设置TIM3_ARR和TIM3_PSC的值,设置TIM3_DIER允许更新中断,允许TIM3工作,TIM3中断分组设置。
  2. 编写中断服务函数:实现LED灯亮灭。
  3. 主函数:调用相关接口,完成IO口和定时器启动。
//定时器初始化
void TIM3_Int_Init()
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;NVIC_InitTypeDef    NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能TIM_TimeBaseStructure.TIM_Prescaler =7199;     //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  TIM_TimeBaseStructure.TIM_Period  = 4999;        //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到5000为500msTIM_TimeBaseStructure.TIM_ClockDivision = 0;    //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_ITConfig(TIM3, TIM_IT_Update,ENABLE);NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  //IRQ通道被使能NVIC_Init(&NVIC_InitStructure);     //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设							 
}
//定时器中断服务函数
void TIM3_IRQHandler(void)   //TIM3中断
{if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 {TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源 LED1=!LED1;}
}
//主函数
int main(void){	delay_init();	    	 //延时函数初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2LED_Init();		  	//初始化与LED连接的硬件接口TIM3_Int_Init();   //10Khz的计数频率,计数到5000为500ms  while(1){LED0=!LED0;delay_ms(200);		   }
}

十六宿舍 原创作品,转载必须标注原文链接。

©2023 Yang Li. All rights reserved.

欢迎关注 『十六宿舍』,大家喜欢的话,给个👍,更多关于嵌入式相关技术的内容持续更新中。

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

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

相关文章

GaussDB数据库管理系统介绍

1.GaussDB的发展 2.GaussDB的生态 内部: 云化自动化方案。通过数据库运行基础设施的云化将DBA(数据库管理员)和运维人员的日常工作 自动化。外部: 采用与数据库周边生态伙伴对接与认证的生态连接融合方案,解决开发者/DBA难获取、应用难对接等…

[linux] 怎么批量kill掉挂载运行python 某个.py文件的端口

kill $(ps aux | grep python tools/token_raw_data_for_dsw.py | grep -v grep | awk {print $2}) 使用一系列的命令来查找并终止正在运行的名为"python main.py"的进程。 具体的步骤如下: ps aux命令用于列出当前正在运行的所有进程。grep python ma…

VR虚拟展厅的亮点是什么?有哪些应用?

传统展厅主要是以静态陈列的形式来传达内容,而展示形式则有图片、视频等,虽然视频包含内容多,但是总体具有一定的局限性,客户体验感也较差,往往不能深入了解细节。随着VR技术越来越成熟,VR技术的广泛应用&a…

PHP基础学习

PHP是什么? PHP(全称:PHP:Hypertext Preprocessor,即"PHP:超文本预处理器")是一种通用开源脚本语言。PHP 脚本在服务器上执行。PHP 可免费下载使用。 基础的PHP语法 PHP 脚本可以放…

【谢希尔 计算机网络】第4章 网络层

目录 网络层 网络层的几个重要概念 网络层提供的两种服务 网络层的两个层面 网际协议 IP 虚拟互连网络 IP 地址 IP 地址与 MAC 地址 地址解析协议 ARP IP 数据报的格式 IP 层转发分组的过程 基于终点的转发 最长前缀匹配 使用二叉线索查找转发 网际控制报文协议…

2023年中国互联网视听平台发展趋势分析:未来增速将从2023年开始缓慢提升[图]

互联网视听平台是指基于互联网技术,提供包括音频、影视、综艺节目、直播、短视频等内容的数字化传播平台。互联网视听平台通过电脑端、移动端等多种终端提供在线点播、直播、互动等服务,具有内容丰富、便捷高效、交互性强等特点,是大众获取娱…

js逆向第一课 密码学介绍

什么是密码学? 密码学(Cryptology)是一种用来混淆的技术,它希望将正常的、可识别的信息转变为无法识别的信息。 目前密码学的研究,一种是偏应用,把现有的,别人研究出来的密码学算法,放在一个合…

C语言用awtk开发界面访问http接口

AWTK全称为Toolkit AnyWhere,是ZLG倾心打造的一套基于C语言开发的GUI框架。旨在为用户提供一个功能强大、高效可靠、简单易用、可轻松做出炫酷效果的GUI引擎,并支持跨平台同步开发,一次编程,终生使用。 1. 初识AWTK | AWStudio社区…

react中hooks闭包

import React, { useState } from react;function Counter() {const [count, setCount] useState(0);return (<div><p>Count: {count}</p><button onClick{() > setCount(count 1)}>Increment</button></div>); }在上面的 React 组件…

常见的Elasticsearch操作

在Elasticsearch中&#xff0c;增删改查操作具有明显的标识&#xff0c;通常使用HTTP方法和URI来表示不同的操作类型。以下是一些常见的Elasticsearch操作及其标识&#xff1a; 增&#xff08;Create/Index&#xff09;&#xff1a; HTTP方法&#xff1a; 通常使用PUT或POST方法…

2023年中国调速器产量、销量及市场规模分析[图]

调速器行业是指生产、销售和维修各种调速器设备的行业。调速器是一种能够改变机械传动系统输出转速的装置&#xff0c;通过调整输入和输出的转速比来实现转速调节的功能。 调速器行业分类 资料来源&#xff1a;共研产业咨询&#xff08;共研网&#xff09; 随着工业自动化程度…

CentOS | 添加普通用户并授权sudo

sudo -i adduser peter passwd peter whereis sudoers nano /etc/sudoers添加一行新用户到root组 ## Allow root to run any commands anywhere root ALL(ALL) ALL peter ALL(ALL) ALL如果提升权限后无法cd到其他目录等&#xff0c;修改 /etc/passwd 文件&…

海外跨境商城电商源码-进出口电商平台网站-多语言多商户多货币平台

一、海外跨境商城电商源码简介 海外跨境电商已成为全球经济发展的重要推动力。而海外跨境商城电商源码则是实现全球化电商的关键工具。本文将详细介绍海外跨境商城电商源码及其相关内容。 二、如何理解海外跨境商城电商源码 海外跨境商城电商源码是指一套已经开发好并可直接应用…

ZKP6.2 Discrete-log-based Polynomial Commitments (KZG10)

ZKP学习笔记 ZK-Learning MOOC课程笔记 Lecture 6: Discrete-log-based Polynomial Commitments (Yupeng Zhang) 6.2 KZG polynomial commitment and its variants KZG: [Kate-Zaverucha-Goldberg 2010]Procedure Soundness: q-Strong Bilinear Diffie-Hellman (q-SBDH) a…

致敬技术与创新·20231024程序员节

每年的10月24日&#xff0c;全球的程序员们都会欢庆属于他们的节日——1024程序员节。这个节日旨在致敬那些用代码改变世界的程序员们&#xff0c;以及他们对于技术创新的执着追求。在这一天&#xff0c;让我们一起来了解这个节日的由来、意义&#xff0c;以及如何庆祝这个特殊…

MySQL MVCC机制探秘:数据一致性与并发处理的完美结合,助你成为数据库高手

一、前言 在分析 MVCC 的原理之前&#xff0c;我们先回顾一下 MySQL 的一些内容以及关于 MVCC 的一些简单介绍。&#xff08;注:下面没有特别说明默认 MySQL 的引擎为 InnoDB &#xff09; 1.1 数据库的并发场景 数据库并发场景有三种&#xff0c;分别是&#xff1a; 读-读…

竞赛选题 深度学习人脸表情识别算法 - opencv python 机器视觉

文章目录 0 前言1 技术介绍1.1 技术概括1.2 目前表情识别实现技术 2 实现效果3 深度学习表情识别实现过程3.1 网络架构3.2 数据3.3 实现流程3.4 部分实现代码 4 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习人脸表情识别系…

算法学习(三)利用前序遍历的思想求解层序遍历

给定一个二叉树&#xff0c;返回该二叉树层序遍历的结果&#xff0c;&#xff08;从左到右&#xff0c;一层一层地遍历&#xff09; 例如&#xff1a; 给定的二叉树是{3,9,20,#,#,15,7}, 我的解法&#xff1a; 在前序遍历的基础上&#xff0c;增加一个深度参数&#xff0c;结果…

rapidocr_paddle[gpu]:GPU端推理库来了

简介 rapidocr_paddle系列包是基于PaddlePaddle框架作为推理引擎的&#xff0c;支持CPU和GPU上推理。值得说明的是&#xff0c;这个包和PaddleOCR相比&#xff0c;代码基本都是一样的&#xff0c;只不过这个库将里面核心推理代码抽了出来&#xff0c;更加精简而已。 推荐GPU上…

《java核心卷Ⅰ》知识点总结(可作面试题)

&#x1f6eb; JDK和JRE傻傻分不清?&#x1f6eb; HelloWorld的输出都经历了啥&#xff1f;&#x1f6eb; Java的三个版本都是啥&#xff1f;&#x1f6eb; 关于main方法你都知道啥&#xff1f;main方法被声明为private会怎样&#xff1f;&#x1f6eb; 强制and自动类型转换都…