蓝桥杯嵌入式省一教程:(三)按键扫描与定时器中断

在第一讲中曾经提到,GPIO有输入输出两种模式。在点亮LED时,我们已经使用了GPIO输出模式,在按键识别中,我们将要使用GPIO输入模式。首先来看看按键的电路原理图(下图在选手资源数据包——CT117E-M4产品手册中):

5a14e3d2439242e7837513f285762649.png

其中,B1~B4为4个不同的按键,它们通过PB0、PB1、PB2、PA0四个端口以上拉电阻的方式连接到单片机中。当按键松开时,PB0等端口处于高电平状态;当按键按下后,端口处于低电平状态。因此,我们可以把这些端口设置为GPIO输入+上拉电阻(pull-up)模式,通过读取其电平的高低状态来判断按键是否被按下。(所谓上下拉电阻,其实决定的就是GPIO输入端口断路时的初始电平状态,有关介绍可以自行搜索)

例如,需要判断B1是否被按下时,我们只需要判断PB0的电平状态:

if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0) == GPIO_PIN_RESET)//读取PB0的电平状态,判断是否为低电平
{/* 执行任务 */
}

在主循环中,利用按键扫描,我们就可以通过不同的按键操作来执行不一样的任务,例如:

while (1)
{//B1按下,点亮LD1和LD2if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET){LED_On(LD1|LD2);}//B2按下,点亮LD3和LD4if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET){LED_On(LD3|LD4);}//B3按下,点亮LD5和LD6if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET){LED_On(LD5|LD6);}//B4按下,点亮LD7和LD8if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){LED_On(LD7|LD8);}
}

不仅是按键,GPIO输入模式与输出模式一样,均广泛应用于各种需要读取外部电路电平的场景。有关GPIO输入的函数如下:

/*** @brief  Read the specified input port pin.* @param  GPIOx where x can be (A..G) to select the GPIO peripheral for STM32G4xx family* @param  GPIO_Pin specifies the port bit to read.*         This parameter can be any combination of GPIO_PIN_x where x can be (0..15).* @retval The input port pin value.*/
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)

然而,这种方法在实际中并不常用。可以想象,除了判断按键是否按下以外,一个嵌入式系统一定还有其他的许多任务需要执行。倘若在主循环中一直判断按键是否被按下,则会占用CPU,效率低下,同时也可能因为在执行其他任务,响应不及时。因此,我们更常用的是采用中断的方式来判断按键是否被按下。

先来普及一下什么是中断。我们知道,CPU是按照顺序依次执行主函数中的指令的。中断是指打断CPU当前正在执行的指令,跳到中断程序中执行,随后跳会主函数原来的位置继续执行原指令。例如在生活中,我们的主程序是写代码,这时电话铃响,我们不得不停下手中的工作,进入中断——接电话,接完电话后又继续回到写代码的工作中。正如打断我们的有可能是电话铃声,有可能是门铃声,也有可能是短信铃声等等,打断CPU的中断方式也是多种多样的,如GPIO外部中断、定时器中断、定时器捕获中断等等……

考虑到比赛中对按键的判断涉及到长短按,我们在考虑程序执行效率而采用中断的同时,要考虑判断长短按的方法,这就涉及到按键按下的时间问题。在单片机中,与时间有关的问题,都是通过定时器来实现的。因此,下面我们来介绍定时器中断

先来介绍一下与定时器有关的概念。在单片机中,有一个晶振(石英晶体振荡器),它通常决定了单片机的时钟频率。通过对时钟的分频,可以得到许许多多的时钟源。不同的硬件通过采用不同的时钟源,再对其进行分频,就得到了独属于这个硬件自己的时钟频率,定时器亦是如此。

参照官方例程(LCD的例程),我们按如下步骤配置时钟树:

(1)开启外部高速时钟

cb8dc1038b1546b88dc5c1b41c516b6e.png

(2)勾选HSE,将时钟频率设置为80MHz后按回车

9078d69cf972485a9e2ad26f543bfed5.png

(3)所得到的定时器频率即可以在上图右侧圆圈处查看

这样我们就得到了时钟频率为80MHz的定时器。

下面我们来开启定时器中断。我们设置TIM4如下:

86bc4ddd2d654419a32ea6b54841d70e.png

其中,定时器频率按照如下公式计算:(具体原理请自行搜索)

eq?f%3D%5Cfrac%7Bf_%7B0%7D%7D%7B%5Cleft%20%28Prescaler+1%20%5Cright%20%29%5Cleft%20%28%20Counter%20Period+1%20%5Cright%20%29%7D%3D%5Cfrac%7B80%2C000%2C000%7D%7B80%5Ctimes%2010000%7D%3D100Hz

f0为时钟频率80MHz,Prescaler为预分频系数,Counter Period为计数周期。这样我们就把TIM4定时器的频率设置为了100Hz,即周期为0.01s。最后,只需要打开中断开关,就完成了定时器中断的配置。

535b9bad5fed426eab77001ec3f2b3a9.png

在Cube中设置好后,想要使用定时器中断,还要在主函数初始化时开启定时器中断(在此处是开启TIM4的定时器中断)

HAL_TIM_Base_Start_IT(&htim4);    //开启TIM4的基本(Base)功能(定时)中断(IT(InTerrupt))

然后编写定时器中断函数(注意:函数名和形参均是固定的,不能修改!!!可参照下图寻找)

b1cf0f581f7d4138b9873108f1b1f9bb.png

 7f0688959f1549148ced2f462da3fb9c.png

0fa20f8f98754da0966acc3fb6c29f03.png

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)    //定时(Period)中断(Elapsed)回调(Callback)函数,回调即从主程序中调到中断程序中
{if (htim->Instance == TIM4)    //如果是TIM4定时器触发的中断{//B1按下,点亮LD1和LD2if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET){LED_On(LD1|LD2);}//B2按下,点亮LD3和LD4if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET){LED_On(LD3|LD4);}//B3按下,点亮LD5和LD6if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET){LED_On(LD5|LD6);}//B4按下,点亮LD7和LD8if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){LED_On(LD7|LD8);}}
}

这样,每当时间过去了0.01s,CPU就会进入定时中断回调函数中,运行我们预先写好的中断程序(在此处是读取按键端口的电平,随后执行相应任务),即定时按键扫描,而不是一直循环扫描按键是否按下,这样就为CPU节省下了大量的时间,大大提高了程序的运行效率。

 

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

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

相关文章

高等数学教材重难点题型总结(三)微分中值定理和导数的应用

第三章,微分中值定理的证明题等,非常重要,需要牢牢掌握 1.证明中值定理对某函数在给定区间上的正确性 2.与中值定理有关的证明题 3.微分中值定理应用于求证不等式 4.洛必达法则求极限 5.洛必达的经典错误反例 6.按某项实现多项式幂展开 7.求带…

以 Java NIO 的角度理解 Netty

文章目录 前言Java NIO 工作原理Selector 的创建ServerSocketChannel 的创建ServerSocketChannel 注册 Selector对事件的处理总结 前言 上篇文章《Netty 入门指南》主要涵盖了 Netty 的入门知识,包括 Netty 的发展历程、核心功能与组件,并且通过实例演示…

rabbitmq的发布确认

生产者将信道设置成 confirm 模式,一旦信道进入 confirm 模式, 所有在该信道上面发布的 消息都将会被指派一个唯一的 ID (从 1 开始),一旦消息被投递到所有匹配的队列之后,broker 就会发送一个确认给生产者(包含消息的唯一 ID)&…

AI巨浪下,数据技术如何驱动智能未来?

引言 数据技术是大数据时代的核心驱动力,也是推动各行各业数字化转型和智能化升级的关键因素。随着云计算、人工智能、区块链等新兴技术的不断发展和融合,数据技术也呈现出多模态、混合处理、自动化管理等新的趋势和特点。 8 月 19 日(周六&…

【宝藏系列】嵌入式 C 语言代码优化技巧【超详细版】

【宝藏系列】嵌入式 C 语言代码优化技巧【超详细版】 文章目录 【宝藏系列】嵌入式 C 语言代码优化技巧【超详细版】前言整形数除法和取余数合并除法和取余数通过2的幂次进行除法和取余数取模的一种替代方法使用数组下标全局变量使用别名变量的生命周期分割变量类型局部变量指针…

STM32 F103C8T6学习笔记3:串口配置—串口收发—自定义Printf函数

今日学习使用STM32 C8T6的串口,我们在经过学习笔记2的总结归纳可知,STM32 C8T6最小系统板上有三路串口,如下图: 今日我们就着手学习如何配置开通这些串口进行收发,这里不讲串口通信概念与基础,可以自行网上…

一文读懂HTML

文章目录 HTML的历史HTML的作用HTML的基本语言 HTML的历史 HTML(HyperText Markup Language)的历史可以追溯到20世纪90年代早期,它是互联网发展的重要里程碑之一。以下是HTML的历史概述: 早期阶段(1980年代末 - 1990年…

FLatten Transformer 简化版Transformer

今天在找论文时,看到一篇比较新奇的论文,在这里跟大家分享一下,希望可以给一些人提供一些思路。虽然现在Transformer 比较火,在分割上面也应用的比较多,但是我一直不喜欢用,其中一个原因是结构太复杂了&…

C++:模拟实现list及迭代器类模板优化方法

文章目录 迭代器模拟实现 本篇模拟实现简单的list和一些其他注意的点 迭代器 如下所示是利用拷贝构造将一个链表中的数据挪动到另外一个链表中&#xff0c;构造两个相同的链表 list(const list<T>& lt) {emptyinit();for (auto e : lt){push_back(e);} }void test_…

运动路径规划,ROS发布期望运动轨迹

目录 一、Python实现&#xff08;推荐方法&#xff09; 1.1代码cubic_spline_path.py 1.2使用方法 二、C实现 参考博客 想让机器人/智能车无人驾驶&#xff0c;要有期望路径&#xff0c;最简单的是一条直线&#xff0c;或者是一条光滑曲线。 生成路径的方法有两种&#xf…

【网络编程(二)】NIO快速入门

NIO Java NIO 三大核心组件 Buffer&#xff08;缓冲区&#xff09;&#xff1a;每个客户端连接都会对应一个Buffer&#xff0c;读写数据通过缓冲区读写。Channel&#xff08;通道&#xff09;&#xff1a;每个channel用于连接Buffer和Selector&#xff0c;通道可以进行双向读…

Redis数据库的可视化工具AnotherRedisDesktopManager使用+抖音直播小玩法实践

一、它是什么 Another Redis DeskTop Manager 是一个开源项目&#xff0c;提供了以可视化的方式管理 Redis 的功能&#xff0c;可供免费下载安装&#xff0c;也可以在此基础上进行二次开发&#xff0c;主要特点有&#xff1a; 支持 Windows 平台和 MacOS 平台 支持查询 Key、…

QT中的按钮控件Buttons介绍

目录 Buttons 按钮控件 1、常用属性介绍 2、按钮介绍 2.1QPushButton 普通按钮 2.2QtoolButton 工具按钮 2.3Radio Button单选按钮 2.4CheckButton复选按钮 2.5Commam Link Button命令链接按钮 2.6Dialog Button Box命令链接按钮 Buttons 按钮控件 在Qt里&#xff0c;…

Viobot开机指南

0.前言 本篇旨在让每个拿到Viobot设备的用户都能够第一时间测试它的效果&#xff0c;以及将设备配置到自己的环境下面。 1.上电 首先&#xff0c;我们先要把设备接上电源线和网线&#xff0c;最简单的方式就是网线直连电脑。 电源选用12V1.5A设备自带的电源即可。 2.配置网…

深入学习前端开发,掌握HTML、CSS、JavaScript等技术

课程链接&#xff1a; 链接: https://pan.baidu.com/s/1WECwJ4T8UQfs2FyjUMbxig?pwdi654 提取码: i654 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 --来自百度网盘超级会员v4的分享 课程介绍&#xff1a; 第1周&#xff1a;HTML5基础语法与标签 &#x1f…

web集群学习:搭建 LNMP应用环境

目录 LNMP的介绍&#xff1a; LNMP组合工作流程&#xff1a; FastCGI介绍&#xff1a; 1、什么是 CGI 2、什么是 FastCGI 配置LNMP 1、部署LNMP环境 2、配置LNMP环境 LNMP的介绍&#xff1a; 随着 Nginx Web 服务的逐渐流行&#xff0c;又岀现了新的 Web 服务环境组合—…

【Spring Cloud 八】Spring Cloud Gateway网关

gateway网关 系列博客背景一、什么是Spring Cloud Gateway二、为什么要使用Spring Cloud Gateway三、 Spring Cloud Gateway 三大核心概念4.1 Route&#xff08;路由&#xff09;4.2 Predicate&#xff08;断言&#xff09;4.3 Filter&#xff08;过滤&#xff09; 五、Spring …

如何使用Kali Linux进行密码破解?

今天我们探讨Kali Linux的应用&#xff0c;重点是如何使用它来进行密码破解。密码破解是渗透测试中常见的任务&#xff0c;Kali Linux为我们提供了强大的工具来帮助完成这项任务。 1. 密码破解简介 密码破解是一种渗透测试活动&#xff0c;旨在通过不同的方法和工具来破解密码…

力扣初级算法(数组拆分)

力扣初级算法&#xff08;数组拆分&#xff09; 每日一算法&#xff1a; 力扣初级算法&#xff08;数组拆分&#xff09; 学习内容&#xff1a; 1.问题描述 给定长度为 2n 的整数数组 nums &#xff0c;你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), …, (an, bn) …

机器人CPP编程基础-03变量类型Variables Types

机器人CPP编程基础-02变量Variables 全文AI生成。 C #include<iostream>using namespace std;main() {int a10,b35; // 4 bytescout<<"Value of a : "<<a<<" Address of a : "<<&a <<endl;cout<<"Val…