四、GPIO中断实现按键功能
4.1 GPIO简介
输入输出(I/O)是一个非常重要的概念。I/O泛指所有类型的输入输出端口,包括单向的端口如逻辑门电路的输入输出管脚和双向的GPIO端口。而GPIO(General-Purpose Input/Output)则是一个常见的术语,指的是通用输入输出接口。
下面有请DeepSeek发言
LPC1110系列Cortex-M0微控制器的GPIO口的结构特点:
| 1 | 端口可由软件配置为输入输出 |
| 2 | 引脚默认为输入(所以点灯时需要改下方向) |
| 3 | 端口引脚的读写操作可屏蔽 |
| 4 | 每个单独引脚可被用作外部中断输入引脚 |
| 5 | 每个GPIO中断可配置为 高、低电平、下降、上升沿或双边沿触发 |
| 6 | 可对单独端口的中断级别进行配置 |
4.2 GPIO口的寄存器
所有GPIO寄存器都为32位
GPIO端口基址为
| 端口0 | 0x5000 0000 |
| 端口1 | 0x5001 0000 |
| 端口2 | 0x5002 0000 |
| 端口3 | 0x5003 0000 |
4.2.1 数据寄存器 GPIOnDATA
用于读取输入引脚的状态数据或者配置输出引脚的输出状态
对应端口位置后四位范围为 0000 ~ 3FFC
| 11:0 | PIOn_0 ~ PIOn_11的输入/输出数据 |
| 31:12 | 保留 |
4.2.2 方向寄存器 GPIOnDIR
| 11:0 | PIOn_0 ~ PIOn_11的输入/输出方向 0为输入, 1为输出 位数0-11与0-11引脚一一对应 |
| 31:12 | 保留 |
4.2.3 中断触发寄存器 GPIOnIS
相较于基地址偏移量0x8004 即0x500n 8004
| 11:0 | PIOn_x 0为边沿触发,1为电平触发 |
| 31:12 | 保留 |
4.2.4 中断双边沿触发寄存器 GPIOnIBE
相较于基地址偏移量0x8008 即0x500n 8008
| 11:0 | 0为通过4.2.5中寄存器GPIOnIEV控制PIOn_x的中断 1为通过PIOn_x上双边沿触发中断 |
| 31:12 | 保留 |
4.2.5 中断事件寄存器 GPIOnIEV
相较于基地址偏移量0x800C 即0x500n 800C
| 11:0 | 0为上升沿或者高电平触发中断 1为下降沿或者低电平触发中断 具体边沿还是电平 看4.2.3中GPIOnIS的设置 |
| 31:12 | 保留 |
4.2.6 中断屏蔽寄存器 GPIOnIE
相较于基地址偏移量0x8010 即0x500n 8010
| 11:0 | 0为中断被屏蔽 1为中断不被屏蔽 |
| 31:12 | 保留 |
4.2.7 原始中断状态寄存器 GPIOnIRS
相较于基地址偏移量0x8014 即0x500n 8014
屏蔽之前的中断状态
| 11:0 | 0为无中断 1为满足中断要求 |
| 31:12 | 保留 |
4.2.8 屏蔽中断状态寄存器 GPIOnMIS
相较于基地址偏移量0x8018 即0x500n 8018
考虑了屏蔽操作之后是否有中断
| 11:0 | 0为无中断,或者中断被屏蔽 1为满足中断要求 |
| 31:12 | 保留 |
4.2.9 中断清除寄存器 GPIOnIC
相较于基地址偏移量0x801C 即0x500n 801C
| 11:0 | 0无操作 1为清除PIOn_x上的边沿检测逻辑 |
| 31:12 | 保留 |
4.3 LPC上的GPIO按键

按键按下引脚低电平,不按是高电平
4.4 按键控制LED闪烁频率
任务:
1. BUTTON(PIO3_5)按键按下,闪烁频率为1Hz,再次按下,恢复闪烁频率为0.5Hz;
2. WEAKUP(PIO1_4)按键按下,闪烁频率为2Hz,再次按下,恢复闪烁频率为0.5Hz;
3. 适当考虑按键防抖功能。
思路:
对于闪烁频率的修改,首先考虑用什么控制LED闪烁,结合上章可以用SysTick,然后按键按下改变SysTick周期即可
对于按键防抖,由于按键固有的物理结构,按下后弹簧一上一下会影响中断,需要用延时函数过滤抖动。

抖动时间大概10ms这样, 我们可以用个延时函数过滤掉这个抖动过程,延时20ms就足够了
代码:
利用之前写过的函数即可,复制个新工程,然后main文件里代码如下
#include <LPC11xx.h>
#include "LED.h"//延时ms函数 // 太粗糙了,而且要根据机器指令与时钟周期关系调整,也就防抖延时用一下
__inline void delay_ms(uint32_t a) //约1ms延时函数
{ uint32_t i;while( a -- != 0){for(i = 0; i<5500; i++);}
}int flag1 = 0, flag2 = 0; // 判断botton 和 wakeup 按键上一次状态
int main()
{LED_Init(); // PIO1_4LPC_IOCON->PIO1_4 &= ~(0x1F); // 清除之前的配置LPC_IOCON->PIO1_4 |= 0x00; // 配置为GPIO功能LPC_GPIO1->DIR &= ~(1UL << 4);// 设置GPIO方向为输入LPC_GPIO1->IS &= ~(0x1 << 4); // 清除第 4 位,设置为边沿触发LPC_GPIO1->IBE &= ~(0x1 << 4); // 清除第 4 位,设置为单边沿触发LPC_GPIO1->IEV &= ~(0x1 << 4); // 清除第 4 位,设置为低电平触发LPC_GPIO1 -> IE |= (0x1<<4); // 使能端口中断LPC_IOCON->PIO1_4 |= (1UL << 5); // 使能滞后模式LPC_GPIO1->IC |= (1UL << 4); // 清除中断标志位NVIC_EnableIRQ(EINT1_IRQn); // 使能GPIO1中断// PIO3_5LPC_IOCON->PIO3_5 &= ~(0x1F); // 清除之前的配置LPC_IOCON->PIO3_5 |= 0x00; // 配置为GPIO功能LPC_GPIO3->DIR &= ~(1UL << 5);// 设置GPIO方向为输入LPC_GPIO3->IS &= ~(0x1 << 5); // 清除第 5 位,设置为边沿触发LPC_GPIO3->IBE &= ~(0x1 << 5); // 清除第 5 位,设置为单边沿触发LPC_GPIO3->IEV &= ~(0x1 << 5); // 清除第 5 位,设置为低电平触发LPC_GPIO3 -> IE |= (0x1<<5); // 使能端口中断LPC_IOCON->PIO3_5 |= (1UL << 5); // 使能滞后模式LPC_GPIO3->IC |= (1UL << 5); //清除中断标志NVIC_EnableIRQ(EINT3_IRQn);SysTick_Config(SystemCoreClock/100); // 0.01s进一次中断 1s翻转一次 0.5 Hzwhile(1){}
}void SysTick_Handler() /// 系统节拍定时器中断函数
{static unsigned long ticks;if(ticks++ >= 99){ticks = 0;LED_Toggle();}
}// GPIO3_5的中断服务函数,处理BUTTON按键按下事件
void PIOINT3_IRQHandler(void)
{if((LPC_GPIO3->MIS & (1UL << 5)) == (1UL << 5))// 检查是否是PIO3_5的中断{ delay_ms(20); // 消抖while((LPC_GPIO3->DATA & (1UL << 5)) == 0);delay_ms(20);if(flag1)SysTick_Config(SystemCoreClock/100); // 0.01s进一次中断 1s翻转一次 0.5 Hzelse SysTick_Config(SystemCoreClock/200); // 0.005s进一次中断 0.5s翻转一次 1 Hzflag1 = !flag1;LPC_GPIO3->IC |= (1UL << 5); // 清除中断标志}
}
// GPIO1_4的中断服务函数,处理WAKEUP按键按下事件
void PIOINT1_IRQHandler(void)
{if((LPC_GPIO1->MIS & (1UL << 4)) == (1UL << 4)) // 检查是否是PIO1_4的中断{delay_ms(20);while((LPC_GPIO1->DATA & (1UL << 4)) == 0);delay_ms(20);if(flag2)SysTick_Config(SystemCoreClock/100); // 0.01s进一次中断 1s翻转一次 0.5 Hzelse SysTick_Config(SystemCoreClock/400); // 0.0025s进一次中断 0.2s翻转一次 2 Hz flag2 = !flag2;LPC_GPIO1->IC |= (1UL << 4); // 清除中断标志}
}
模块化一下,新建Button.c Button.h文件,便于之后移植工程
main.c
#include <LPC11xx.h>
#include "LED.h"
#include "Button.h"int main()
{LED_Init(); WAKEUP_Init();Button_Init();while(1){}
}void SysTick_Handler() /// 系统节拍定时器中断函数
{static unsigned long ticks;if(ticks++ >= 99){ticks = 0;LED_Toggle();}
}
Button.c
#include "Button.h"
int flag1 = 0, flag2 = 0; // 判断botton 和 wakeup 按键上一次状态//延时ms函数 // 太粗糙了,而且要根据机器指令与时钟周期关系调整,也就防抖延时用一下
__inline void delay_ms(uint32_t a) //约1ms延时函数
{ uint32_t i;while( a -- != 0){for(i = 0; i<5500; i++);}
}void WAKEUP_Init(void)
{LPC_SYSCON -> SYSAHBCLKCTRL |= (1UL << 6) | (1UL << 16); // 使能GPIO时钟和IO时钟// PIO1_4LPC_IOCON->PIO1_4 &= ~(0x1F); // 清除之前的配置LPC_IOCON->PIO1_4 |= 0x00; // 配置为GPIO功能LPC_GPIO1->DIR &= ~(1UL << 4);// 设置GPIO方向为输入LPC_GPIO1->IS &= ~(0x1 << 4); // 清除第 4 位,设置为边沿触发LPC_GPIO1->IBE &= ~(0x1 << 4); // 清除第 4 位,设置为单边沿触发LPC_GPIO1->IEV &= ~(0x1 << 4); // 清除第 4 位,设置为低电平触发LPC_GPIO1 -> IE |= (0x1<<4); // 使能端口中断LPC_IOCON->PIO1_4 |= (1UL << 5); // 使能滞后模式LPC_GPIO1->IC |= (1UL << 4); // 清除中断标志位NVIC_EnableIRQ(EINT1_IRQn); // 使能GPIO1中断
}void Button_Init(void)
{LPC_SYSCON -> SYSAHBCLKCTRL |= (1UL << 6) | (1UL << 16); // 使能GPIO时钟和IO时钟// PIO3_5LPC_IOCON->PIO3_5 &= ~(0x1F); // 清除之前的配置LPC_IOCON->PIO3_5 |= 0x00; // 配置为GPIO功能LPC_GPIO3->DIR &= ~(1UL << 5);// 设置GPIO方向为输入LPC_GPIO3->IS &= ~(0x1 << 5); // 清除第 5 位,设置为边沿触发LPC_GPIO3->IBE &= ~(0x1 << 5); // 清除第 5 位,设置为单边沿触发LPC_GPIO3->IEV &= ~(0x1 << 5); // 清除第 5 位,设置为低电平触发LPC_GPIO3 -> IE |= (0x1<<5); // 使能端口中断LPC_IOCON->PIO3_5 |= (1UL << 5); // 使能滞后模式LPC_GPIO3->IC |= (1UL << 5); //清除中断标志NVIC_EnableIRQ(EINT3_IRQn);
}// GPIO3_5的中断服务函数,处理BUTTON按键按下事件
void PIOINT3_IRQHandler(void)
{if((LPC_GPIO3->MIS & (1UL << 5)) == (1UL << 5))// 检查是否是PIO3_5的中断{ delay_ms(20); // 消抖while((LPC_GPIO3->DATA & (1UL << 5)) == 0);delay_ms(20);if(flag1)SysTick_Config(SystemCoreClock/100); // 0.01s进一次中断 1s翻转一次 0.5 Hzelse SysTick_Config(SystemCoreClock/200); // 0.005s进一次中断 0.5s翻转一次 1 Hzflag1 = !flag1;LPC_GPIO3->IC |= (1UL << 5); // 清除中断标志}
}
// GPIO1_4的中断服务函数,处理WAKEUP按键按下事件
void PIOINT1_IRQHandler(void)
{if((LPC_GPIO1->MIS & (1UL << 4)) == (1UL << 4)) // 检查是否是PIO1_4的中断{delay_ms(20);while((LPC_GPIO1->DATA & (1UL << 4)) == 0);delay_ms(20);if(flag2)SysTick_Config(SystemCoreClock/100); // 0.01s进一次中断 1s翻转一次 0.5 Hzelse SysTick_Config(SystemCoreClock/400); // 0.0025s进一次中断 0.2s翻转一次 2 Hz flag2 = !flag2;LPC_GPIO1->IC |= (1UL << 4); // 清除中断标志}
}
Button.h
#ifndef _BUTTON_H_
#define _BUTTON_H_#include <LPC11xx.h>void WAKEUP_Init(void);
void Button_Init(void);#endif
相关文章:
四、GPIO中断实现按键功能
4.1 GPIO简介 输入输出(I/O)是一个非常重要的概念。I/O泛指所有类型的输入输出端口,包括单向的端口如逻辑门电路的输入输出管脚和双向的GPIO端口。而GPIO(General-Purpose Input/Output)则是一个常见的术语,…...
.Net / C# 繁体中文 与 简体中文 互相转换, 支持地方特色词汇
版本号 Nuget 搜索 “OpenCCNET”, 注意别找错, 好多库的名字都差不多 支持 “繁,简” 的互相转换, 支持多个地区常用词汇的转换, 还支持 日文的新旧转换. OpenCC 在 .Net 中的实现 https://github.com/CosineG/OpenCC.NET <PackageReference Include"OpenCCNET"…...
一元函数微积分的几何应用:二维平面光滑曲线的曲率公式
文章目录 前言曲率和曲率半径的定义曲率计算公式参数方程形式直角坐标显式方程形式极坐标形式向量形式 前言 本文将介绍二维平面光滑曲线的曲率定义以及不同形式的曲率及曲率半径公式的推导。 曲率和曲率半径的定义 (关于二维平面光滑曲线的定义以及弧长公式请参…...
数据结构与算法之异步: LeetCode 1114. 按序打印 (Ts版)
按序打印 https://leetcode.cn/problems/print-in-order/description/ 描述 给你一个类: public class Foo {public void first() { print("first"); }public void second() { print("second"); }public void third() { print("third&qu…...
python:求解爱因斯坦场方程
在物理学中,爱因斯坦的广义相对论(General Relativity)是描述引力如何作用于时空的理论。广义相对论由爱因斯坦在1915年提出,并被阿尔伯特爱因斯坦、纳森罗森和纳尔逊曼德尔斯塔姆共同发展。广义相对论的核心方程是爱因斯坦场方程…...
PostgreSQL 数据备份与恢复:掌握 pg_dump 和 pg_restore 的最佳实践
title: PostgreSQL 数据备份与恢复:掌握 pg_dump 和 pg_restore 的最佳实践 date: 2025/1/28 updated: 2025/1/28 author: cmdragon excerpt: 在数据库管理中,备份与恢复是确保数据安全和业务连续性的关键措施。PostgreSQL 提供了一系列工具,以便于数据库管理员对数据进行…...
位运算的概念
文章目录 整数在计算机中的表示二进制表示有符号类型和无符号类型机器数和真值原码、反码和补码原码、反码和补码的表示方法计算机中的表示 位运算与、或、异或和取反移位运算移位运算与乘除法的关系位运算的性质 目录 整数在计算机中的表示 二进制表示 程序中的所有数在计算…...
自主Shell命令行解释器
什么是命令行 我们一直使用的"ls","cd","pwd","mkdir"等命令,都是在命令行上输入的,我们之前对于命令行的理解: 命令行是干啥的?是为我们做命令行解释的。 命令行这个东西实际上是我们…...
Vue.js 的介绍与组件开发初步
Vue.js 的介绍与组件开发初步 Vue.js 的介绍与组件开发初步引言第一部分:Vue.js 基础入门1.1 什么是 Vue.js?1.2 搭建 Vue.js 开发环境安装 Node.js 和 npm安装 Vue CLI创建新项目运行示例 1.3 第一个 Vue.js 示例 第二部分:Vue.js 组件开发基…...
XCCL、NCCL、HCCL通信库
XCCL提供的基本能力 XCCL提供的基本能力 不同的XCCL 针对不同的网络拓扑,实现的是不同的优化算法的(不同CCL库最大的区别就是这) 不同CCL库还会根据自己的硬件、系统,在底层上面对一些相对应的改动; 但是对上的API接口…...
Python教学:文档处理及箱线图等
代码1: import os import pandas as pd import numpy as py import os.path from os import listdir import openpyxl from openpyxl import Workbook import re import matplotlib.pyplot as plt # 导入matplotlib的绘图模块,用于可视化 cwdos.getcwd…...
【Redis】安装配置Redis超详细教程 / Linux版
Linux安装配置Redis超详细教程 安装redis依赖安装redis启动redis停止redisredis.conf常见配置设置redis为后台启动修改redis监听地址设置工作目录修改密码监听的端口号数据库数量设置redis最大内存设置日志文件设置redis开机自动启动 学习视频:黑马程序员Redis入门到…...
【大数据技术】教程05:本机DataGrip远程连接虚拟机MySQL/Hive
本机DataGrip远程连接虚拟机MySQL/Hive datagrip-2024.3.4VMware Workstation Pro 16CentOS-Stream-10-latest-x86_64-dvd1.iso写在前面 本文主要介绍如何使用本机的DataGrip连接虚拟机的MySQL数据库和Hive数据库,提高编程效率。 安装DataGrip 请按照以下步骤安装DataGrip软…...
springboot 启动原理
目标: SpringBootApplication注解认识了解SpringBoot的启动流程 了解SpringFactoriesLoader对META-INF/spring.factories的反射加载认识AutoConfigurationImportSelector这个ImportSelector starter的认识和使用 目录 SpringBoot 启动原理SpringBootApplication 注…...
llama.cpp GGUF 模型格式
llama.cpp GGUF 模型格式 1. Specification1.1. GGUF Naming Convention (命名规则)1.1.1. Validating Above Naming Convention 1.2. File Structure 2. Standardized key-value pairs2.1. General2.1.1. Required2.1.2. General metadata2.1.3. Source metadata 2.2. LLM2.2.…...
使用Pytorch训练一个图像分类器
一、准备数据集 一般来说,当你不得不与图像、文本或者视频资料打交道时,会选择使用python的标准库将原始数据加载转化成numpy数组,甚至可以继续转换成torch.*Tensor。 对图片而言,可以使用Pillow库和OpenCV库对视频而言…...
PythonStyle MVC 开发框架
在 Python 中,MVC(Model - View - Controller,模型 - 视图 - 控制器)是一种常见的软件设计模式,它将应用程序分为三个主要部分,各自承担不同的职责,以提高代码的可维护性、可扩展性和可测试性。…...
HTTP协议的无状态和无连接
无连接 ①无连接的含义 这里所说的无连接并不是指不连接,客户与服务器之间的HTTP连接是一种一次性连接,它限制每次连接只处理一个请求,当服务器返回本次请求的应答后便立即关闭连接,下次请求再重新建立连接。这种一次性连接主要考…...
毫秒级响应的VoIP中的系统组合推荐
在高并发、低延迟、毫秒级响应的 VoIP 场景中,选择合适的操作系统组合至关重要。以下是针对 Ubuntu linux-lowlatency、CentOS Stream kernel-rt 和 Debian 自定义 PREEMPT_RT 的详细对比及推荐: 1. 系统组合对比 特性Ubuntu linux-lowlatencyCentO…...
PWN--格式化字符串
简介 格式化字符串是指在编程过程中,通过特殊的占位符将相关对应的信息整合或提取的规则字符串。格式化字符串包括格式化输入和格式化输出,其本质是程序员调用相关格式化字符串的操作协议规定。错误的或不当的信息配置可能导致程序运行失效或产生未…...
tf.Keras (tf-1.15)使用记录2-基于tf.keras.layers创建层
tf.keras.layers是keras的主要网络创建方法,里面已经有成熟的网络层,也可以通过继承的方式自定义神经网络层。 在keras的model定义中,为了保证所有对数据的操作都是可追溯、可保存、可反向传播,需要保证对数据的任何操作都是基于t…...
面试经典150题——栈
文章目录 1、有效的括号1.1 题目链接1.2 题目描述1.3 解题代码1.4 解题思路 2、2.1 题目链接2.2 题目描述2.3 解题代码2.4 解题思路 3、最小栈3.1 题目链接3.2 题目描述3.3 解题代码3.4 解题思路 4、逆波兰表达式求值4.1 题目链接4.2 题目描述4.3 解题代码4.4 解题思路 5、基本…...
FBX SDK的使用:读取Mesh
读取顶点数据 要将一个Mesh渲染出来,必须要有顶点的位置,法线,UV等顶点属性,和三角面的顶点索引数组。在提取这些数据之前,先理解FBX SDK里面的几个概念: Control Point 顶点的位置,就是x,y,z…...
EtherCAT主站IGH-- 49 -- 搭建xenomai系统及自己的IGH主站
EtherCAT主站IGH-- 49 -- 搭建xenomai系统及自己的IGH主站 0 Ubuntu18.04系统IGH博客、视频欣赏链接一 移植xenomai系统1,下载安装工具包2,下载linux内核及xenomai2.1,下载linux内核2.2,下载xenomai2.3,下载补丁ipipe2.4,解压缩包3,打补丁4,配置内核5,编译内核6,安装编译好的内…...
Java控制台登录系统示例代码
实现一个简单的登录系统需要包括用户输入用户名和密码、验证用户信息等功能。以下是一个简单的Java控制台登录系统示例代码。这个系统使用一个简单的用户信息存储方式(如数组或哈希表),并提供基本的登录验证功能。 示例代码 import java.ut…...
S4 HANA明确税金汇差科目(OBYY)
本文主要介绍在S4 HANA OP中明确税金汇差科目(OBYY)相关设置。具体请参照如下内容: 1. 明确税金汇差科目(OBYY) 以上配置点定义了在外币挂账时,当凭证抬头汇率和税金行项目汇率不一致时,造成的差异金额进入哪个科目。此类情况只发生在FB60/F…...
Web-3.0(Solidity)基础教程
Solidity 是 以太坊智能合约编程语言,用于编写 去中心化应用(DApp)。如果你想开发 Web3.0 应用,Solidity 是必学的。 Remix - Ethereum IDE(在线编写 Solidity) 特性Remix IDEHardhat适用场景适合 初学者 …...
深入理解linux中的文件(上)
1.前置知识: (1)文章 内容 属性 (2)访问文件之前,都必须打开它(打开文件,等价于把文件加载到内存中) 如果不打开文件,文件就在磁盘中 (3&am…...
背包问题和单调栈
背包问题(动态规划) 动态五步曲 dp数组及下标索引的含义递推公式dp数组如何初始化遍历顺序打印dp数组 01背包:n种物品,有一个,二维数组遍历顺序可以颠倒,(滚动数组)一维数组遍历顺序不可颠倒…...
Airflow:深入理解Apache Airflow Task
Apache Airflow是一个开源工作流管理平台,支持以编程方式编写、调度和监控工作流。由于其灵活性、可扩展性和强大的社区支持,它已迅速成为编排复杂数据管道的首选工具。在这篇博文中,我们将深入研究Apache Airflow 中的任务概念,探…...
