四、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:0PIOn_0 ~ PIOn_11的输入/输出数据
31:12保留

4.2.2 方向寄存器 GPIOnDIR

11:0PIOn_0 ~ PIOn_11的输入/输出方向   0为输入, 1为输出  位数0-11与0-11引脚一一对应
31:12保留

4.2.3 中断触发寄存器 GPIOnIS

        相较于基地址偏移量0x8004 即0x500n 8004

11:0PIOn_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_4
    LPC_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_5
    LPC_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 Hz
	while(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 Hz
		else 
			SysTick_Config(SystemCoreClock/200); // 0.005s进一次中断 0.5s翻转一次 1 Hz
		flag1 = !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 Hz
		else 
			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_4
    LPC_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_5
    LPC_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 Hz
		else 
			SysTick_Config(SystemCoreClock/200); // 0.005s进一次中断 0.5s翻转一次 1 Hz
		flag1 = !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 Hz
		else 
			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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构:时间复杂度

文章目录 为什么需要时间复杂度分析&#xff1f;一、大O表示法&#xff1a;复杂度的语言1.1 什么是大O&#xff1f;1.2 常见复杂度速查表 二、实战分析&#xff1a;解剖C语言代码2.1 循环结构的三重境界单层循环&#xff1a;线性时间双重循环&#xff1a;平方时间动态边界循环&…

C++ Primer 自定义数据结构

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

035 搜索之DFS基础

DFS&#xff1a;深度优先搜索——本质上是暴力枚举&#xff0c;尽可能一条路走到底&#xff0c;走不了回退 1.DFS与n重循环 例&#xff1a;给定一个数字x&#xff0c;将其拆分为3个正整数&#xff0c;后一个要求大于前一个&#xff0c;给出方案。 分析&#xff1a;这种情况下…

【系统迁移】将系统迁移到新硬盘中(G15 5520)

文章目录 前言问题描述解决步骤&#xff08;红色为 debug 步骤&#xff09;参考文献 前言 参数&#xff1a; 电脑 dell g15 5520硬盘&#xff1a;1T 自带硬盘 海力士 2230 -> 2T 西数蓝盘 2280 问题描述 电脑硬盘过小&#xff08;且只有一个接口&#xff09;&#xff0c;将…

大模型综合性能考题汇总

- K1.5长思考版本 一、创意写作能力 题目1&#xff1a;老爸笑话 要求&#xff1a;写五个原创的老爸笑话。 考察点&#xff1a;考察模型的幽默感和创意能力&#xff0c;以及对“原创”要求的理解和执行能力。 题目2&#xff1a;创意故事 要求&#xff1a;写一篇关于亚伯拉罕…

openeuler 22.03 lts sp4 使用 cri-o 和 静态 pod 的方式部署 k8s-v1.32.0 高可用集群

前情提要 整篇文章会非常的长…可以选择性阅读,另外,这篇文章是自己学习使用的,用于生产,还请三思和斟酌 静态 pod 的部署方式和二进制部署的方式是差不多的,区别在于 master 组件的管理方式是 kubectl 还是 systemctl有 kubeadm 工具,为什么还要用静态 pod 的方式部署?…

Pluto固件编译笔记

前段时间我已经做到在电脑上交叉编译一个简单的c/c程序&#xff0c;然后复制到pluto上运行。 要做到这一点&#xff0c;其实参考adi pluto官网的wiki就能做到了。 但这样有几个问题&#xff0c;只能做到简易程序&#xff0c;如果程序复杂&#xff0c;要调用更多库而SYSROOT里…

【产品经理学习案例——AI翻译棒出海业务】

前言&#xff1a; 本文主要讲述了硬件产品在出海过程中&#xff0c;翻译质量、翻译速度和本地化落地策略是硬件产品规划需要考虑的核心因素。针对不同国家&#xff0c;需要优化翻译质量和算法&#xff0c;关注市场需求和文化差异&#xff0c;以便更好地满足当地用户的需求。同…

星际智慧农业系统(SAS),智慧农业的未来篇章

新月人物传记&#xff1a;人物传记之新月篇-CSDN博客 相关文章&#xff1a;星际战争模拟系统&#xff1a;新月的编程之道-CSDN博客 新月智能护甲系统CMIA--未来战场的守护者-CSDN博客 “新月智能武器系统”CIWS&#xff0c;开启智能武器的新纪元-CSDN博客 目录 星际智慧农业…

【蓝桥杯嵌入式入门与进阶】4.初读启动文件:粗略阅读,经常翻阅,知己知彼,百战百胜

目录 1.二者差异 1. 1适用芯片型号不同 1.2中断向量表差异 1.2.1 中断数量和种类 1.2.2 部分中断处理函数命名差异 1.2.3. 复位处理描述差异 1.2.4代码注释中的功能描述差异 1.2.5 DMA 通道中断处理函数差异 示例代码对比片段 startup_stm32g431xx.s startup_stm32…

unity中的动画混合树

为什么需要动画混合树&#xff0c;动画混合树有什么作用&#xff1f; 在Unity中&#xff0c;动画混合树&#xff08;Animation Blend Tree&#xff09;是一种用于管理和混合多个动画状态的工具&#xff0c;包括1D和2D两种类型&#xff0c;以下是其作用及使用必要性的介绍&…

C语言 --- 分支

C语言 --- 分支 语句分支语句含义if...else语句单分支if语句语法形式 双分支 if-else 语句语法形式 悬空else含义问题描述 多分支 if-else 语句语法形式 switch...case语句含义语法形式 总结 &#x1f4bb;作者简介&#xff1a;曾与你一样迷茫&#xff0c;现以经验助你入门 C 语…

pytorch实现长短期记忆网络 (LSTM)

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 LSTM 通过 记忆单元&#xff08;cell&#xff09; 和 三个门控机制&#xff08;遗忘门、输入门、输出门&#xff09;来控制信息流&#xff1a; 记忆单元&#xff08;Cell State&#xff09; 负责存储长期信息&…

C++:抽象类习题

题目内容&#xff1a; 求正方体、球、圆柱的表面积&#xff0c;抽象出一个公共的基类Container为抽象类&#xff0c;在其中定义一个公共的数据成员radius(此数据可以作为正方形的边长、球的半径、圆柱体底面圆半径)&#xff0c;以及求表面积的纯虚函数area()。由此抽象类派生出…

GEE | 计算Sentinel-2的改进型土壤调整植被指数MSAVI

同学们好&#xff01;今天和大家分享的是 “改进型土壤调整植被指数MSAVI”&#xff0c;它能够更准确地反映植被生长状态&#xff0c;且广泛应用于植被覆盖监测、生态环境评估等领域。 1. MSAVI 改进型土壤调整植被指数&#xff08;MSAVI&#xff09;是一种针对植被覆盖区域土…

deepseek+vscode自动化测试脚本生成

近几日Deepseek大火,我这里也尝试了一下,确实很强。而目前vscode的AI toolkit插件也已经集成了deepseek R1,这里就介绍下在vscode中利用deepseek帮助我们完成自动化测试脚本的实践分享 安装AI ToolKit并启用Deepseek 微软官方提供了一个针对AI辅助的插件,也就是 AI Toolk…

CodeGPT使用本地部署DeepSeek Coder

目前NV和github都托管了DeepSeek&#xff0c;生成Key后可以很方便的用CodeGPT接入。CodeGPT有三种方式使用AI&#xff0c;分别时Agents&#xff0c;Local LLMs&#xff08;本地部署AI大模型&#xff09;&#xff0c;LLMs Cloud Model&#xff08;云端大模型&#xff0c;从你自己…

[c语言日寄]C语言类型转换规则详解

【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋&#xff1a;这是一个专注于C语言刷题的专栏&#xff0c;精选题目&#xff0c;搭配详细题解、拓展算法。从基础语法到复杂算法&#xff0c;题目涉及的知识点全面覆盖&#xff0c;助力你系统提升。无论你是初学者&#xff0c;还是…

FPGA 使用 CLOCK_DEDICATED_ROUTE 约束

使用 CLOCK_DEDICATED_ROUTE 约束 CLOCK_DEDICATED_ROUTE 约束通常在从一个时钟区域中的时钟缓存驱动到另一个时钟区域中的 MMCM 或 PLL 时使 用。默认情况下&#xff0c; CLOCK_DEDICATED_ROUTE 约束设置为 TRUE &#xff0c;并且缓存 /MMCM 或 PLL 对必须布局在相同…

Ollama 介绍,搭建本地 AI 大模型 deepseek,并使用 Web 界面调用

Ollama 是一个基于 Go 语言的本地大语言模型运行框架&#xff0c;类 Docker产品&#xff08;支持 list,pull,push,run 等命令&#xff09;&#xff0c;事实上它保留了 Docker 的操作习惯&#xff0c;支持上传大语言模型仓库(有 deepseek、llama 2&#xff0c;mistral&#xff0…