Linux-Ubuntu之按键中断实验

devtools/2024/12/28 0:05:43/

Linux-Ubuntu之按键中断实验

  • 一, 汇编对中断进行设置
  • 二,C语言模块
      • 1.中断配置
      • 2.GPIO口配置
      • 3.按键配置
      • 4.主函数
  • 三,总结

一, 汇编对中断进行设置

列出对中断向量表,主要用的是IRQ中断和复位中断服务函数,复位中断函数主要用于设置一些寄存器,再跳转到主函数,IRQ中断就是跳转到按键触发的中断,主要有中断ID号配置。

.global _start_start:/* 中断向量表*/ldr pc,=Reset_Handlerldr pc,=Undefined_Handlerldr pc,=SVC_Handlerldr pc,=PreAbort_Handlerldr pc,=DataAbort_Handlerldr pc,=NotUsed_Handlerldr pc,=IRQ_Handlerldr pc,=FIQ_Handler/*复位中断服务函数 */Reset_Handler:cpsid i  /*关闭IRQ */MRC p15,0,r0,c1,c0,0 //读取ARM的SCTLR寄存器内容bic r0,r0,#(1<<12)bic r0,r0,#(1<<11)bic r0,r0,#(1<<2)bic r0,r0,#(1<<1)bic r0,r0,#(1<<0)MCR p15,0,r0,c1,c0,0//写入SCTLR寄存器@ ldr r0,=0x87800000@ dsb@ isb/*设置为IRQ模式 */mrs r0,cpsr /*读取cpsr现在状态 */bic r0,r0,#0x1forr r0,r0,#0x12msr cpsr,r0ldr sp,=0x80600000 /*SP堆栈指针 *//*设置为SYS模式 */mrs r0,cpsr /*读取cpsr现在状态 */bic r0,r0,#0x1forr r0,r0,#0x1fmsr cpsr,r0ldr sp,=0x80400000 /*SP堆栈指针 *//*设置为SVC模式 */mrs r0,cpsr /*读取cpsr现在状态 */bic r0,r0,#0x1forr r0,r0,#0x13msr cpsr,r0ldr sp,=0x80200000 /*SP堆栈指针 */ cpsie i /*打开IRQ*/b main/*未定义中断服务函数 */Undefined_Handler:ldr r0,=Undefined_Handlerbx r0/*SVC中断服务函数 */SVC_Handler:ldr r0,=SVC_Handlerbx r0   /*预取终止中断服务函数 */PreAbort_Handler:ldr r0,=PreAbort_Handlerbx r0 /*数据终止中断服务函数 */DataAbort_Handler:ldr r0,=DataAbort_Handlerbx r0 /*未使用中断服务函数 */NotUsed_Handler:ldr r0,=NotUsed_Handlerbx r0 /*IRQ中断服务函数 */IRQ_Handler:push {lr}push {r0-r3,r12}  //入栈mrs r0,spsr //读取spsrpush {r0}//入栈mrc p15,4,r1,c15,c0,0add r1,r1,#0x2000//接口端地址ldr r0,[r1,#0xc]//保存中断IDpush {r0,r1}cps #0x13 //SVCpush {lr}ldr r2,=system_irqhandler//加载c语言中断blx r2pop {lr}cps #0x12pop {r0,r1}str r0,[r1,#0x10]pop {r0}msr spsr_cxsf,r0pop {r0-r3,r12}pop {lr}subs pc,lr,#4/*FIQ中断服务函数 */FIQ_Handler:ldr r0,=FIQ_Handlerbx r0 /*设置为svr模式 */mrs r0,cpsr /*读取cpsr现在状态 */bic r0,r0,#0x1forr r0,r0,#0x13msr cpsr,r0

二,C语言模块

1.中断配置

设置中断处理函数表,然后对这个中断处理函数表进行初始化配置,当实现中断时候,就是将自己设置的中断函数放到这个中断处理函数表中,这个方法用的是注册中断处理函数。

#include "dsp_int.h"static int irqNesting;//记录中断嵌套个数
/*中断处理函数表*/
static sys_irq_handle_t irqTable[NUMBER_OF_INT_VECTORS];/*初始化中断函数表*/
void system_irqtable_int(void)
{unsigned int i=0;irqNesting=0;//初始化时候 清0for(i=0;i<160;i++){irqTable[i].irqHandler = default_irqhandler;//中断处理函数初始化irqTable[i].userParam=NULL;//中断处理函数参数初始化}
}/*默认中断处理函数初始化*/
void default_irqhandler(unsigned int gicciar,void *param)
{while(1){}
}/*注册中断处理函数,当执行按键操作,将这个中断向量表对应位置进行写入*/
void system_register_irqhandler(IRQn_Type irq,system_irq_handler_t handler,void *userParam)
{irqTable[irq].irqHandler = handler;irqTable[irq].userParam = userParam;
}/*中断初始化*/
void int_init(void)
{GIC_Init();//gic的system_irqtable_int();//初始化中断处理表__set_VBAR(0x87800000); //中断向量偏移地址
}/*真正执行的中断处理函数,IRQ_handler会调用此函数*/
void system_irqhandler(unsigned int gicciar)
{uint32_t intnum = gicciar&0x3ff;//中断号 intnumirqNesting++;//进入中断加一if(intnum>=160)return;//超过160,有问题irqTable[intnum].irqHandler(intnum,irqTable[intnum].userParam);irqNesting--;
}

2.GPIO口配置

包括中断使能,设置GPIO的中断触发方式,包括低电平、高电平、上升沿或下降沿触发方式。

#include "dsp_gpio.h"void gpio_init(GPIO_Type *base,int wei,gpio_config_t *gpio_config_init)//相当于设置GDIR和判断DR,输入的话,读取DR值,输出,给DR值
{if(gpio_config_init->section==gpio_in)//设置为输入{base->GDIR &=~(1<<wei);//输入设置为0 }else{base->GDIR |=(1<<wei);//设置为输出,进行写0 或者写1gpio_write(base,wei,gpio_config_init->mode);} gpio_intconfig(base,wei,gpio_config_init->interruptMode);//GPIO初始化中断函数
}
void gpio_write(GPIO_Type *base,int wei,int write_value)
{if(write_value==0){base->DR &= ~(1<<wei);//写0}else {base->DR |= (1<<wei);//写1}
}
unsigned int gpio_read(GPIO_Type *base,int wei)//记录读的是0还是1
{return (base->DR>>wei)&0x01;
}
void gpio_enable(GPIO_Type *base,unsigned int pin)//使能中断
{base->IMR |=(1<<pin);
}
void gpio_disable(GPIO_Type *base,unsigned int pin)//禁止使能中断
{base->IMR &= ~(1<<pin);
}
void gpio_clearintflags(GPIO_Type *base,unsigned int pin)//清除中断标志
{base->ISR |= (1<<pin);
}
void gpio_intconfig(GPIO_Type *base,unsigned int pin,gpio_interrupt_mode_t ping_int_mode)//GPIO初始化中断函数
{volatile  uint32_t *icr;uint32_t icrShift;icrShift=pin;base->EDGE_SEL &=~(1 << pin);if(pin << 16)//低16位,ICR1,即设置高低电平{icr = &(base -> ICR1);}else {icr = &(base -> ICR2);icrShift = icrShift-16;}switch(ping_int_mode){case kGPIO_IntLowLevel:*icr = *icr & (~(3<<(2*icrShift)));//清0break;case kGPIO_IntHighLevel:*icr = *icr & (~(3<<(2*icrShift))); *icr = *icr | (1<<(2*icrShift));   break;case kGPIO_IntRisingEdge:*icr = *icr & (~(3<<(2*icrShift)));*icr = *icr | (2<<(2*icrShift));  break;case kGPIO_IntFallingEdge:*icr = *icr & (~(3<<(2*icrShift)));*icr = *icr | (3<<(2*icrShift));  break;case KGPIO_IntRisingOrFallingEdge:*icr = *icr &(~(3<<(2*icrShift)));base->EDGE_SEL=base->EDGE_SEL|(1<<pin);break;default:break;          }}

3.按键配置

这个部分是实现中断的具体执行操作,前面对中断初始化,就是说怎么样去用中断,给对应中断ID相应的功能怎么样实现,这个按键配置就是具体往里面填函数,来真的实现。然后对按键的GPIO即GPIO1_IO18进行配置,使其使能并且下降沿触发。

#include "dsp_exti.h"
#include "dsp_gpio.h"
#include "dsp_int.h"
#include "dsp_delay.h"
#include "dsp_led.h"
#include "beep.h"void exit_init(void)
{gpio_config_t key_config;/*中断对按键初始化*/IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0);		IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0Xf080);key_config.section= gpio_in;key_config.interruptMode=kGPIO_IntFallingEdge;key_config.mode=1;gpio_init(GPIO1,18,&key_config);/*打开16-31中断*/GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);system_register_irqhandler(GPIO1_Combined_16_31_IRQn,(system_irq_handler_t)gpio1_IO18_irqhandler,NULL);gpio_enable(GPIO1,18);
}/*中断处理函数*/
void gpio1_IO18_irqhandler(unsigned int gocciar,void *param)
{static unsigned char state = 0;delay(15);if(gpio_read(GPIO1,18)==0){beep_mode(state);state=!state;}/*清除中断标志位*/ gpio_clearintflags(GPIO1,18);
}

4.主函数

这个主函数与其他不同点在于,调用中断初始化,即对中断向量表进行初始化,然后调用按键的初始化,往中断向量表对应的ID写入这个中断执行函数,当判断为低电平,触发执行中断,执行蜂鸣器的操作。

#include "main.h"#include "dsp_clk.h"#include "dsp_led.h"#include "dsp_delay.h"#include "beep.h"#include "dsp_key.h"#include "dsp_int.h"#include "dsp_exti.h"int main(void){// int key_status=1;int_init();//中断初始化key_init();clk_enable();beep_init();led_init();exit_init();while(1){}return 0;    }

三,总结

按键中断实验,先在汇编中进行说明,然后对中断初始化,GPIO进行配置,最后具体说明实现这个中断会执行什么样操作。模块实现起来比较多,原理相对前面来说复杂一些。


http://www.ppmy.cn/devtools/145026.html

相关文章

云计算中的容器技术(如Docker)是什么?

今天想和大家聊聊容器技术&#xff0c;特别是Docker这个大家可能经常听到的名词。记得我刚接触容器技术时也觉得挺抽象的&#xff0c;让我用简单的比喻来说明吧。 想象一下你在搬家。传统方式是把所有家具、电器分散装车&#xff0c;到了新家还要重新组装、调试。这就像我们以…

设置中 wifi密码框被输入键盘遮挡的处理

适配设备时&#xff0c;设置中链接wifi输入密码界面&#xff0c;输入框被键盘遮挡。修改方案就是提高输入法的位置&#xff0c;让其不受键盘遮挡。 修改如下&#xff1a; 尚未暂存以备提交的变更&#xff1a;&#xff08;使用 "git add <文件>..." 更新要提交…

【开源免费】基于SpringBoot+Vue.JS房屋租赁管理系统(JAVA毕业设计)

本文项目编号 T 091 &#xff0c;文末自助获取源码 \color{red}{T091&#xff0c;文末自助获取源码} T091&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

软件测试经典面试题(答案解析+文档)

1、B/S架构和C/S架构区别 B/S 只需要有操作系统和浏览器就行&#xff0c;可以实现跨平台&#xff0c;客户端零维护&#xff0c;维护成本低&#xff0c;但是个性化能力低&#xff0c;响应速度较慢。 C/S响应速度快&#xff0c;安全性强&#xff0c;一般应用于局域网中&#xf…

大恒相机开发(3)—大恒相机工业检测的实际案例

大恒相机工业检测的实际案例 工业检测的实际案例图像采集性能优化技巧工业环境下的稳定性 工业检测的实际案例 以下是一些使用大恒相机进行工业检测的实际案例&#xff1a; 多特征光学成像系统&#xff1a; 在这个案例中&#xff0c;使用大恒相机构建了一个全方位、多特征的图…

前端 HTTP 请求由 Nginx 反向代理和 API 网关到后端服务的流程

在大型互联网项目中&#xff0c;前端发送请求通过 Nginx 等反向代理和网关组件传递到后端服务的过程是一个复杂且精细的系统流程。从微服务架构的角度&#xff0c;这个过程可以分为以下几个主要步骤&#xff0c;并可能涉及其他中间组件&#xff0c;如监控和日志组件等。 一、前…

随手记:小程序使用uni.createVideoContext视频无法触发播放

官方文档&#xff1a;uni.createVideoContext(videoId, componentInstance) | uni-app官网 背景&#xff1a; 在小程序使用了uni.createVideoContext(videoId).play()&#xff1b;但是视频无法触发播放&#xff0c;后续调研发现&#xff0c;需要再传入this&#xff1a; 解决办…

车载通信框架 --- 智能汽车车载通信架构浅析

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…