I.MX6ull 中断 二 (按键驱动蜂鸣器)

news2024/12/24 2:07:06

 按键中断 KEY0 (UART1_CTS  引脚)触发蜂鸣器

1 修改start.S  添加中断相关定义

中断向量表

.global _start  				/* 全局标号 */

/*
 * 描述:	_start函数,首先是中断向量表的创建
 * 参考文档:ARM Cortex-A(armV7)编程手册V4.0.pdf P42,3 ARM Processor Modes and Registers(ARM处理器模型和寄存器)
 * 		 	ARM Cortex-A(armV7)编程手册V4.0.pdf P165 11.1.1 Exception priorities(异常)
 */
_start:
	ldr pc, =Reset_Handler		/* 复位中断 					*/	
	ldr pc, =Undefined_Handler	/* 未定义中断 					*/
	ldr pc, =SVC_Handler		/* SVC(Supervisor)中断 		*/
	ldr pc, =PrefAbort_Handler	/* 预取终止中断 					*/
	ldr pc, =DataAbort_Handler	/* 数据终止中断 					*/
	ldr	pc, =NotUsed_Handler	/* 未使用中断					*/
	ldr pc, =IRQ_Handler		/* IRQ中断 					*/
	ldr pc, =FIQ_Handler		/* FIQ(快速中断)未定义中断 			*/

2 定义对应的中断函数

2.1 复位函数 

CP15协处理器 

关闭I,DCache和MMU  CP15协处理器  附加 (上电之初,我们的内存初始化比较慢一拍,当cpu初始化了,但内存还没准备好之后,就对内存进行数据读,那么势必会造成了指令取址异常,系统就会挂了。

mmu在设备上电之初是没有任何作用的,也就是说,在u-boot的初始化之初执行汇编的那一段代码中,包括后面的初始化一些具体的外设时,访问的都是实际的地址,mmu的打开起不到任何的意义

2 设置处理器9中模式(按需)对应SP指针,要使用中断必须设置 IRQ模式下的SP指针  C12

3 清除bss

4 跳转main函数

Cotex-A7 参考手册 107页面    关闭I,DCache和MMU  SCTLR寄存器 系统控制寄存器

中断向量偏移设置 

将新的中断向量表首地址写入到CP15 的VBAR  寄存器  

mcr p15, 0, r0, c12, c0, 0

注意 读改写顺序  

分支预测(Branch Prediction): 解决处理分支指令导致流水线失败的数据处理方法 。从P5时代开始的一种先进的,解决处理分支指令(if-then-else)导致流水线失败的数据处理方法,由CPU来判断程序分支的进行方向,能够加快运算速度。

/* 复位中断 */	
Reset_Handler:

	cpsid i						/* 关闭全局中断 */

	/* 关闭I,DCache和MMU 
	 * 采取读-改-写的方式。
	 */
	mrc     p15, 0, r0, c1, c0, 0     /* 读取CP15的C1寄存器到R0中       		        	*/
    bic     r0,  r0, #(0x1 << 12)     /* 清除C1寄存器的bit12位(I位),关闭I Cache            	*/
    bic     r0,  r0, #(0x1 <<  2)     /* 清除C1寄存器的bit2(C位),关闭D Cache    				*/
    bic     r0,  r0, #0x2             /* 清除C1寄存器的bit1(A位),关闭对齐						*/
    bic     r0,  r0, #(0x1 << 11)     /* 清除C1寄存器的bit11(Z位),关闭分支预测					*/
    bic     r0,  r0, #0x1             /* 清除C1寄存器的bit0(M位),关闭MMU				       	*/
    mcr     p15, 0, r0, c1, c0, 0     /* 将r0寄存器中的值写入到CP15的C1寄存器中	 				*/

	
#if 0
	/* 汇编版本设置中断向量表偏移 */
	ldr r0, =0X87800000

	dsb   //数据同步指令 
	isb   //指令同步
	mcr p15, 0, r0, c12, c0, 0
	dsb
	isb
#endif
    
	/* 设置各个模式下的栈指针,
	 * 注意:IMX6UL的堆栈是向下增长的!
	 * 堆栈指针地址一定要是4字节地址对齐的!!!
	 * DDR范围:0X80000000~0X9FFFFFFF
	 */
	/* 进入IRQ模式 */
	mrs r0, cpsr
	bic r0, r0, #0x1f 	/* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 	*/
	orr r0, r0, #0x12 	/* r0或上0x13,表示使用IRQ模式					*/
	msr cpsr, r0		/* 将r0 的数据写入到cpsr_c中 					*/
	ldr sp, =0x80600000	/* 设置IRQ模式下的栈首地址为0X80600000,大小为2MB */

	/* 进入SYS模式 */
	mrs r0, cpsr
	bic r0, r0, #0x1f 	/* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 	*/
	orr r0, r0, #0x1f 	/* r0或上0x13,表示使用SYS模式					*/
	msr cpsr, r0		/* 将r0 的数据写入到cpsr_c中 					*/
	ldr sp, =0x80400000	/* 设置SYS模式下的栈首地址为0X80400000,大小为2MB */

	/* 进入SVC模式 */
	mrs r0, cpsr
	bic r0, r0, #0x1f 	/* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 	*/
	orr r0, r0, #0x13 	/* r0或上0x13,表示使用SVC模式					*/
	msr cpsr, r0		/* 将r0 的数据写入到cpsr_c中 					*/
	ldr sp, =0X80200000	/* 设置SVC模式下的栈首地址为0X80200000,大小为2MB */

	cpsie i				/* 打开全局中断 */
#if 0
	/* 使能IRQ中断 */
	mrs r0, cpsr		/* 读取cpsr寄存器值到r0中 			*/
	bic r0, r0, #0x80	/* 将r0寄存器中bit7清零,也就是CPSR中的I位清零,表示允许IRQ中断 */
	msr cpsr, r0		/* 将r0重新写入到cpsr中 			*/
#endif

	b main				/* 跳转到main函数 			 	*/

2.2 未定义 \SVC\预取终止、数据终止、未使用等中断 

以下代码未实现 中断服务函数 死循环处理 

/* 未定义中断 */
Undefined_Handler:
	ldr r0, =Undefined_Handler
	bx r0

/* SVC中断 */
SVC_Handler:
	ldr r0, =SVC_Handler
	bx r0

/* 预取终止中断 */
PrefAbort_Handler:
	ldr r0, =PrefAbort_Handler	
	bx r0

/* 数据终止中断 */
DataAbort_Handler:
	ldr r0, =DataAbort_Handler
	bx r0

/* 未使用的中断 */
NotUsed_Handler:

	ldr r0, =NotUsed_Handler
	bx r0

/* FIQ中断 */
FIQ_Handler:

	ldr r0, =FIQ_Handler	
	bx r0									

2.3 IRQ 编写

2.3.1 流程

复位后使能了IRQ  cpsie i

1  保存中断上下文 push 相关寄存器

2 初始化 GIC控制器

3  设置IRQ中断服务处理函数 system_irqhandler()  此时已经切换到SVC模式(??)

 4 进入IRQ模式后恢复现场

 寄存器R0-R12属于通用寄存器,除了FIQ工作模式,在其他工作模式下这些寄存器都是共用、共享的。R0-R3通常用来传递函数的参数,R4-R11用来保存程序运算的中间结果或者函数的局部变量等,R12常用来作为函数调用过程中的临时寄存器。ARM处理器有多种工作模式,除了这些在各个模式下通用的寄存器,还有一些寄存器在各自的工作模式下独立存在,如R13,R14,R15,CPSR,SPSR寄存器。

mrc p15, 4, r1, c15, c0, 0

/* 从CP15的C0寄存器内的值到R1寄存器中
                                * 参考文档ARM Cortex-A(armV7)编程手册V4.0.pdf P49
                                * Cortex-A7 Technical ReferenceManua.pdf P68 P138
                                */                            

/* IRQ中断!重点!!!!! */
IRQ_Handler:
	push {lr}					/* 保存lr地址 PC 指针*/
	push {r0-r3, r12}			/* 保存r0-r3,r12寄存器 */

	mrs r0, spsr				/* 读取spsr寄存器 */
	push {r0}					/* 保存spsr寄存器 */

	mrc p15, 4, r1, c15, c0, 0 /* 从CP15的C0寄存器内的值到R1寄存器中
								* 参考文档ARM Cortex-A(armV7)编程手册V4.0.pdf P49
								* Cortex-A7 Technical ReferenceManua.pdf P68 P138
								*/							
	add r1, r1, #0X2000			/* GIC基地址加0X2000,也就是GIC的CPU接口端基地址 */
	ldr r0, [r1, #0XC]			/* GIC的CPU接口端基地址加0X0C就是GICC_IAR寄存器,
								 * GICC_IAR寄存器保存这当前发生中断的中断号,我们要根据
								 * 这个中断号来绝对调用哪个中断服务函数
								 */
	push {r0, r1}				/* 保存r0,r1 */
	
	cps #0x13					/* 进入SVC模式,允许其他中断再次进去 */
	
	push {lr}					/* 保存SVC模式的lr寄存器 */
	ldr r2, =system_irqhandler	/* 加载C语言中断处理函数到r2寄存器中*/
	blx r2						/* 运行C语言中断处理函数,带有一个参数,保存在R0寄存器中 */

	pop {lr}					/* 执行完C语言中断服务函数,lr出栈 */
	cps #0x12					/* 进入IRQ模式 */
	pop {r0, r1}				
	str r0, [r1, #0X10]			/* 中断执行完成,写EOIR */

	pop {r0}						
	msr spsr_cxsf, r0			/* 恢复spsr */

	pop {r0-r3, r12}			/* r0-r3,r12出栈 */
	pop {lr}					/* lr出栈 */
	subs pc, lr, #4				/* 将lr-4赋给pc */

当中断处理程序执行完毕后,需要恢复现场并跳转到原始程序中的下一条指令地址,即将r0-r12、pc和cpsr的值回复到栈中。在ARM架构中,lr(返回地址寄存器)存储了当前指令执行完成后的返回地址,因为指令在执行过程中会将pc(程序计数器)的值加上8(取指+译指+执 行)),因此需要在lr的基础上减4才能得到正确的返回地址。 lr = pc +8

2.3.2 system_irqhandler 通用中断驱动文件编写

system_irqhandler  此函数有一个中断号 参数, 不同的中断源对应不同的中断处 理函数,I.MX6U 有 160 个中断源,所以需要 160 个中断处理函数,我们可以将这些中断处理 函数放到一个数组里面,中断处理函数在数组中的标号就是其对应的中断号。当中断发生以后 函数 system_irqhandler 根据中断号从中断处理函数数组中找到对应的中断处理函数并执行即可。

编写前先移植bsp内api 有关中断相关文件 (imx6ull目录)

#ifndef __IMX6UL_H

#define __IMX6UL_H

/***************************************************************

Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.

文件名 :    imx6ul.h

作者     : 左忠凯

版本     : V1.0

描述     : 包含一些常用的头文件。

其他     : 无

论坛     : www.wtmembed.com

日志     : 初版V1.0 2019/1/3 左忠凯创建

***************************************************************/

#include "cc.h"

#include "MCIMX6Y2.h"

#include "fsl_common.h"

#i
nclude "fsl_iomuxc.h"

#include "core_ca7.h"



#endif

在 int目录下 实现 system_irqhandler  函数

1 bsp.init.h 声明中断服务函数形式  注册中断 初始化等 函数 

#ifndef _BSP_INT_H
#define _BSP_INT_H
#include "imx6ul.h"
/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 bsp_int.c
作者	   : 左忠凯
版本	   : V1.0
描述	   : 中断驱动头文件。
其他	   : 无
论坛 	   : www.wtmembed.com
日志	   : 初版V1.0 2019/1/4 左忠凯创建
***************************************************************/

/* 中断服务函数形式 */ 
typedef void (*system_irq_handler_t) (unsigned int giccIar, void *param);

 
/* 中断服务函数结构体*/
typedef struct _sys_irq_handle
{
    system_irq_handler_t irqHandler; /* 中断服务函数 */
    void *userParam;                 /* 中断服务函数参数 */
} sys_irq_handle_t;


/* 函数声明 */
void int_init(void);
void system_irqtable_init(void);
void system_register_irqhandler(IRQn_Type irq, system_irq_handler_t handler, void *userParam);
void system_irqhandler(unsigned int giccIar); 
void default_irqhandler(unsigned int giccIar, void *userParam); 

2 bsp_int.c 

结构体 sys_irq_handle_t 包含一个中断处理函数和中断处 理函数的用户参数。一个中断源就需要一个 sys_irq_handle_t 变量,I.MX6U 有 160 个中断源, 因此需要 160 个 sys_irq_handle_t 组成中断处理数组。并注册

#include "bsp_int.h"
/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 bsp_int.c
作者	   : 左忠凯
版本	   : V1.0
描述	   : 中断驱动文件。
其他	   : 无
论坛 	   : www.wtmembed.com
日志	   : 初版V1.0 2019/1/4 左忠凯创建
***************************************************************/

/* 中断嵌套计数器 */
static unsigned int irqNesting;

/* 中断服务函数表 */
static sys_irq_handle_t irqTable[NUMBER_OF_INT_VECTORS];

/*
 * @description	: 中断初始化函数
 * @param		: 无
 * @return 		: 无
 */
void int_init(void)
{
	GIC_Init(); 						/* 初始化GIC 							*/
	system_irqtable_init();				/* 初始化中断表 							*/
	__set_VBAR((uint32_t)0x87800000); 	/* 中断向量表偏移,偏移到起始地址   				*/
}

/*
 * @description	: 初始化中断服务函数表 
 * @param		: 无
 * @return 		: 无
 */
void system_irqtable_init(void)
{
	unsigned int i = 0;
	irqNesting = 0;
	
	/* 先将所有的中断服务函数设置为默认值 */
	for(i = 0; i < NUMBER_OF_INT_VECTORS; i++)
	{
		system_register_irqhandler((IRQn_Type)i,default_irqhandler, NULL);
	}
}

/*
 * @description			: 给指定的中断号注册中断服务函数 
 * @param - irq			: 要注册的中断号
 * @param - handler		: 要注册的中断处理函数
 * @param - usrParam	: 中断服务处理函数参数
 * @return 				: 无
 */
void system_register_irqhandler(IRQn_Type irq, system_irq_handler_t handler, void *userParam) 
{
	irqTable[irq].irqHandler = handler;
  	irqTable[irq].userParam = userParam;
}

/*
 * @description			: C语言中断服务函数,irq汇编中断服务函数会
 						  调用此函数,此函数通过在中断服务列表中查
 						  找指定中断号所对应的中断处理函数并执行。
 * @param - giccIar		: 中断号
 * @return 				: 无
 */
void system_irqhandler(unsigned int giccIar) 
{

   uint32_t intNum = giccIar & 0x3FFUL;
   
   /* 检查中断号是否符合要求 */
   if ((intNum == 1023) || (intNum >= NUMBER_OF_INT_VECTORS))
   {
	 	return;
   }
 
   irqNesting++;	/* 中断嵌套计数器加一 */

   /* 根据传递进来的中断号,在irqTable中调用确定的中断服务函数*/
   irqTable[intNum].irqHandler(intNum, irqTable[intNum].userParam);
 
   irqNesting--;	/* 中断执行完成,中断嵌套寄存器减一 */

}

/*
 * @description			: 默认中断服务函数
 * @param - giccIar		: 中断号
 * @param - usrParam	: 中断服务处理函数参数
 * @return 				: 无
 */
void default_irqhandler(unsigned int giccIar, void *userParam) 
{
	while(1) 
  	{
//todo
   	}
}



,代码中 默认中断处理函数为循环 未实现 

3 GPIO 按键中断

3.1 修改 GPIO 驱动文件 加入GPIO中断处理 

1 设置触发方式 GPIO_ICR1/GPIO_ICR2 

2 使能GPIO对应的中断确定 中断ID 设置 GPIO_IMR寄存器

3 处理完中断后 清除中断标志位  清除 GPIO_ISR寄存器对应位

4 GIC配置  a 使能中断ID GPIO1_IO18对应 ID 67+32 = 99  b设置中断优先级  c 注册GPIO1_io18中断处理函数

.h

#ifndef _BSP_GPIO_H
#define _BSP_GPIO_H
#define _BSP_KEY_H
#include "imx6ul.h"
/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 bsp_gpio.h
作者	   : 左忠凯
版本	   : V1.0
描述	   : GPIO操作文件头文件。
其他	   : 无
论坛 	   : www.wtmembed.com
日志	   : 初版V1.0 2019/1/4 左忠凯创建
	 	 V2.0 2019/1/4 左忠凯修改
	 	 添加GPIO中断相关定义

***************************************************************/

/* 
 * 枚举类型和结构体定义 
 */
typedef enum _gpio_pin_direction
{
    kGPIO_DigitalInput = 0U,  		/* 输入 */
    kGPIO_DigitalOutput = 1U, 		/* 输出 */
} gpio_pin_direction_t;

/*
 * GPIO中断触发类型枚举
 */
typedef enum _gpio_interrupt_mode
{
    kGPIO_NoIntmode = 0U, 				/* 无中断功能 */
    kGPIO_IntLowLevel = 1U, 			/* 低电平触发	*/
    kGPIO_IntHighLevel = 2U, 			/* 高电平触发 */
    kGPIO_IntRisingEdge = 3U, 			/* 上升沿触发	*/
    kGPIO_IntFallingEdge = 4U, 			/* 下降沿触发 */
    kGPIO_IntRisingOrFallingEdge = 5U, 	/* 上升沿和下降沿都触发 */
} gpio_interrupt_mode_t;	

/*
 * GPIO配置结构体
 */	
typedef struct _gpio_pin_config
{
    gpio_pin_direction_t direction; 		/* GPIO方向:输入还是输出 */
    uint8_t outputLogic;            		/* 如果是输出的话,默认输出电平 */
	gpio_interrupt_mode_t interruptMode;	/* 中断方式 */
} gpio_pin_config_t;


/* 函数声明 */
void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config);
int gpio_pinread(GPIO_Type *base, int pin);
void gpio_pinwrite(GPIO_Type *base, int pin, int value);
void gpio_intconfig(GPIO_Type* base, unsigned int pin, gpio_interrupt_mode_t pinInterruptMode);
void gpio_enableint(GPIO_Type* base, unsigned int pin);
void gpio_disableint(GPIO_Type* base, unsigned int pin);
void gpio_clearintflags(GPIO_Type* base, unsigned int pin);

#endif

bsp.gpio.c

#include "bsp_gpio.h"
/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 bsp_gpio.h
作者	   : 左忠凯
版本	   : V1.0
描述	   : GPIO操作文件。
其他	   : 无
论坛 	   : www.wtmembed.com
日志	   : 初版V1.0 2019/1/4 左忠凯创建
		 V2.0 2019/1/4 左忠凯修改:
		 修改gpio_init()函数,支持中断配置.
		 添加gpio_intconfig()函数,初始化中断
		 添加gpio_enableint()函数,使能中断
		 添加gpio_clearintflags()函数,清除中断标志位
		 
***************************************************************/

/*
 * @description		: GPIO初始化。
 * @param - base	: 要初始化的GPIO组。
 * @param - pin		: 要初始化GPIO在组内的编号。
 * @param - config	: GPIO配置结构体。
 * @return 			: 无
 */
void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config)
{
	base->IMR &= ~(1U << pin);
	
	if(config->direction == kGPIO_DigitalInput) /* GPIO作为输入 */
	{
		base->GDIR &= ~( 1 << pin);
	}
	else										/* 输出 */
	{
		base->GDIR |= 1 << pin;
		gpio_pinwrite(base,pin, config->outputLogic);	/* 设置默认输出电平 */
	}
	gpio_intconfig(base, pin, config->interruptMode);	/* 中断功能配置 */
}

/*
 * @description	 : 读取指定GPIO的电平值 。
 * @param - base	 : 要读取的GPIO组。
 * @param - pin	 : 要读取的GPIO脚号。
 * @return 		 : 无
 */
 int gpio_pinread(GPIO_Type *base, int pin)
 {
	 return (((base->DR) >> pin) & 0x1);
 }

/*
 * @description	 : 指定GPIO输出高或者低电平 。
 * @param - base	 : 要输出的的GPIO组。
 * @param - pin	 : 要输出的GPIO脚号。
 * @param - value	 : 要输出的电平,1 输出高电平, 0 输出低低电平
 * @return 		 : 无
 */
void gpio_pinwrite(GPIO_Type *base, int pin, int value)
{
	 if (value == 0U)
	 {
		 base->DR &= ~(1U << pin); /* 输出低电平 */
	 }
	 else
	 {
		 base->DR |= (1U << pin); /* 输出高电平 */
	 }
}

/*
 * @description  			: 设置GPIO的中断配置功能
 * @param - base 			: 要配置的IO所在的GPIO组。
 * @param - pin  			: 要配置的GPIO脚号。
 * @param - pinInterruptMode: 中断模式,参考枚举类型gpio_interrupt_mode_t
 * @return		 			: 无
 */
void gpio_intconfig(GPIO_Type* base, unsigned int pin, gpio_interrupt_mode_t pin_int_mode)
{
	volatile uint32_t *icr;
	uint32_t icrShift;

	icrShift = pin;
	
	base->EDGE_SEL &= ~(1U << pin);

	if(pin < 16) 	/* 低16位 */
	{
		icr = &(base->ICR1);
	}
	else			/* 高16位 */
	{
		icr = &(base->ICR2);
		icrShift -= 16;
	}
	switch(pin_int_mode)
	{
		case(kGPIO_IntLowLevel):
			*icr &= ~(3U << (2 * icrShift));
			break;
		case(kGPIO_IntHighLevel):
			*icr = (*icr & (~(3U << (2 * icrShift)))) | (1U << (2 * icrShift));
			break;
		case(kGPIO_IntRisingEdge):
			*icr = (*icr & (~(3U << (2 * icrShift)))) | (2U << (2 * icrShift));
			break;
		case(kGPIO_IntFallingEdge):
			*icr |= (3U << (2 * icrShift));
			break;
		case(kGPIO_IntRisingOrFallingEdge):
			base->EDGE_SEL |= (1U << pin);
			break;
		default:
			break;
	}
}


/*
 * @description  			: 使能GPIO的中断功能
 * @param - base 			: 要使能的IO所在的GPIO组。
 * @param - pin  			: 要使能的GPIO在组内的编号。
 * @return		 			: 无
 */
void gpio_enableint(GPIO_Type* base, unsigned int pin)
{ 
    base->IMR |= (1 << pin);
}

/*
 * @description  			: 禁止GPIO的中断功能
 * @param - base 			: 要禁止的IO所在的GPIO组。
 * @param - pin  			: 要禁止的GPIO在组内的编号。
 * @return		 			: 无
 */
void gpio_disableint(GPIO_Type* base, unsigned int pin)
{ 
    base->IMR &= ~(1 << pin);
}

/*
 * @description  			: 清除中断标志位(写1清除)
 * @param - base 			: 要清除的IO所在的GPIO组。
 * @param - pin  			: 要清除的GPIO掩码。
 * @return		 			: 无
 */
void gpio_clearintflags(GPIO_Type* base, unsigned int pin)
{
    base->ISR |= (1 << pin);
}


void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config) 函数初始化GPIO 输入输出

gpio_intconfig函数  根据gpio位确定 控制寄存器  低16 GPIO_ICR1 然后设置触发方式

3.2 编写按键中断业务逻辑

设置 GPIO 电器属性

/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 bsp_exit.c
作者	   : 左忠凯
版本	   : V1.0
描述	   : 外部中断驱动。
其他	   : 配置按键对应的GPIP为中断模式
论坛 	   : www.wtmembed.com
日志	   : 初版V1.0 2019/1/4 左忠凯创建
***************************************************************/
#include "bsp_exit.h"
#include "bsp_gpio.h"
#include "bsp_int.h"
#include "bsp_delay.h"
#include "bsp_beep.h"

/*
 * @description			: 初始化外部中断
 * @param				: 无
 * @return 				: 无
 */
void exit_init(void)
{
	gpio_pin_config_t key_config;

	/* 1、设置IO复用 */
	IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0);			/* 复用为GPIO1_IO18 */
/* 2、、配置UART1_CTS_B的IO属性	
	 *bit 16:0 HYS关闭
	 *bit [15:14]: 11 默认22K上拉
	 *bit [13]: 1 pull功能
	 *bit [12]: 1 pull/keeper使能
	 *bit [11]: 0 关闭开路输出
	 *bit [7:6]: 10 速度100Mhz
	 *bit [5:3]: 000 关闭输出
	 *bit [0]: 0 低转换率
	 */
	IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xF080);

	/* 2、初始化GPIO为中断模式 */
	key_config.direction = kGPIO_DigitalInput;
	key_config.interruptMode = kGPIO_IntFallingEdge;
	key_config.outputLogic = 1;
	gpio_init(GPIO1, 18, &key_config);

	GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);				/* 使能GIC中对应的中断 */
	system_register_irqhandler(GPIO1_Combined_16_31_IRQn, (system_irq_handler_t)gpio1_io18_irqhandler, NULL);	/* 注册中断服务函数 */
	gpio_enableint(GPIO1, 18);								/* 使能GPIO1_IO18的中断功能 */
}

/*
 * @description			: GPIO1_IO18最终的中断处理函数
 * @param				: 无
 * @return 				: 无
 */
void gpio1_io18_irqhandler(void)
{ 
	static unsigned char state = 0;

	/*
	 *采用延时消抖,中断服务函数中禁止使用延时函数!因为中断服务需要
	 *快进快出!!这里为了演示所以采用了延时函数进行消抖,后面我们会讲解
	 *定时器中断消抖法!!!
 	 */

	delay(10);
	if(gpio_pinread(GPIO1, 18) == 0)	/* 按键按下了  */
	{
		state = !state;
		beep_switch(state);
	}
	
	gpio_clearintflags(GPIO1, 18); /* 清除中断标志位 */
}



按键消抖 GPIO一般采用施密特触发器硬件消抖。按键中断出发后 打开蜂鸣器 清除中断标志位  至此 中断服务函数结束 

注意 bss 清除 代码段的位置 将影响_start  复位后 执行地址,中断向量表偏移地址 不一致 0x87800000

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

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

相关文章

【花雕学AI】ChatGPT帮我快速优化标题:古老的非洲部落,有一种神奇的超音速烫脚舞

关于非洲烫脚舞&#xff0c;直接看看ChatGPT的许多创意&#xff0c;一般人确实想不到&#xff1a; 部落文化的声动震波 非洲之歌:部落的音速节奏 非洲土著的音速脚掌传奇 古老部落的震人心魂之舞 非洲红土之声:脚掌舞的激情 非洲神秘部落的超音速脚掌舞 仙踪般的部落音乐…

chatgpt赋能python:Python绘制函数曲线:创造出令人惊叹的图形

Python绘制函数曲线&#xff1a;创造出令人惊叹的图形 随着越来越多的人开始关注数据可视化&#xff0c;Python成为了一种被广泛使用的工具&#xff0c;用于创建各种图形&#xff0c;包括函数曲线。Python图形库的灵活性和适用性使得它成为数据科学和工程领域中最受欢迎的编程…

如何用 ChatGPT 一句话生成 Web 应用?

原型系统的开发对很多不会编程的人来说&#xff0c;原本确实是一道门槛&#xff0c;而且看似难以逾越。而现在&#xff0c;障碍突然间就消失了。 插件 ChatGPT 现在有了一个内容比较丰富的插件系统&#xff0c;而且 Plus 用户已经不再需要填表申请后漫长等待&#xff0c;直接就…

英雄算法联盟 | 六月算法集训顺利开始

文章目录 前言一、集训规划二、星友的反馈1、有觉得题目简单重新找回了自信的2、有拿到题不管三七二十一疯狂输出的3、有为了完成当天作业奋斗到凌晨的4、有自己悟出了坚持就是胜利的道理的5、有发现身边人都在跑而跃跃欲试的6、有上班摸鱼刷题只因为了赶进度的7、有看到大家都…

【微信小程序开发】第 2 节 - 注册小程序开发账号

欢迎来到博主 Apeiron 的博客&#xff0c;祝您旅程愉快 &#xff01; 时止则止&#xff0c;时行则行。动静不失其时&#xff0c;其道光明。 目录 1、缘起 2、注册小程序开发账号 3、总结 1、缘起 开发微信小程序从大的方面来说主要分为三步&#xff1a; ① 注册小程序开发…

【观察】星环科技:布局行业大模型赛道,加速国产化替代进程

以ChatGPT和GPT所代表的大模型&#xff0c;已经在国内形成了“海啸效应”&#xff0c;几乎所有的科技公司都在想方设法进入大模型的赛道。背后的核心驱动力&#xff0c;就在于大模型的最大价值在于普遍提升个人生产力&#xff0c;而各行各业的公司都在积极寻找应用大模型和生成…

黑客使用哪些编程语言

黑客使用哪些编程语言&#xff1f; 使用 Python 分析漏洞利用数据库 克里斯蒂安科赫 迈向数据科学 2021 年&#xff0c;我们与科学家同行一起在德国混沌计算机俱乐部 &#xff08;CCC&#xff09; 进行了一项调查。我们的目标是找出黑客最常使用的编程语言。 本文跟进调查&…

M F C(七)对话框

概念 与用户进行交互的窗口&#xff0c;它的顶级父类为CWND&#xff0c;对话框上面可以有各种控件&#xff0c;控件也是继承自CWND 基本控件功能对应的类静态文本框显示文本&#xff0c;一般不能接收输入信息CStatic图像控件显示图标、方框、和图元文件CStatic编辑器编辑正文…

公网SSH远程连接Termux – 电脑使用安卓Termux 「无需公网IP」

文章目录 1.安装ssh2.安装cpolar内网穿透3.远程ssh连接配置4.公网远程连接5.固定远程连接地址 转载自cpolar极点云的文章&#xff1a;公网SSH远程连接Termux – 电脑使用安卓Termux 「无需公网IP」 使用安卓机跑东西的时候&#xff0c;屏幕太小&#xff0c;有时候操作不习惯。不…

【Linux】crontab 定时任务

当你需要在Linux系统中定期执行某些任务时&#xff0c;crontab&#xff08;cron table&#xff09;是一个非常有用的工具。它允许你根据预定的时间表创建和管理定时任务。 一、从守护进程到crond进程1.1 Linux 守护进程1.2 任务调度进程crond 二、 crontab 详细介绍2.1 crontab…

AI狂飙突进,存力需作先锋

5月30日&#xff0c;在2023中关村论坛成果发布会上&#xff0c;《北京市加快建设具有全球影响力的人工智能创新策源地实施方案&#xff08;2023-2025年&#xff09;》正式发布。《实施方案》要求&#xff0c;支持创新主体重点突破分布式高效深度学习框架、大模型新型基础架构等…

chatgpt赋能python:Python列表数据相加的完全指南

Python列表数据相加的完全指南 Python中的列表是一种非常方便的数据结构&#xff0c;它允许我们存储和处理一组数据。在这篇文章中&#xff0c;我们将介绍如何在Python中使用列表来进行数据相加的操作&#xff0c;并提供一些实用的技巧和建议。如果你正在寻找Python中关于列表…

linux安装docker并设置国内镜像仓库

前置条件 该方案为centos上安装docker&#xff0c;其他版本linux请参照官方文档&#xff1a;https://docs.docker.com/engine/install/centos/该linux系统没有安装过docker&#xff0c;或者已卸载docker #卸载docker yum remove docker \docker-client \docker-client-latest…

springboot整合kafka入门

kafka基本概念 producer&#xff1a; 生产者&#xff0c;负责发布消息到kafka cluster(kafka集群)中。生产者可以是web前端产生的page view&#xff0c;或者是服务器日志&#xff0c;系统CPU、memory等。 consumer&#xff1a; 消费者&#xff0c;每个consumer属于一个特定的c…

Git提交代码报错 Push failed unable to access

目录 场景 环境&#xff1a; Git配置 场景 Push failed unable to access https://github.com/1790753131/remotRepository3.git/: Failed to connect to github.com port 443 after 21114 ms: Couldnt connect to server Push failed unable to ac…

A JavaScript error occurred in the main processUncaught Exception

A JavaScript error occurred in the main processUncaught Exception: Error: getaddrinfo ENOTFOUND rfw.jnsii.com at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:60:26) &#x1f4a7; 记录一下今天遇到的 b u g \color{#FF1493}{记录一下今天遇到的bug} 记录一…

开放接口签名(Signature)实现

开放接口签名(Signature)实现方案 既然是对外开放&#xff0c;那么调用者一定没有我们系统的Token&#xff0c;就需要对调用者进行签名验证&#xff0c;签名验证采用主流的验证方式&#xff0c;采用Signature 的方式。 字段 类型 必传 说明 appid String 是 应用id tim…

windows server安全设置

Windows服务器安全策略设置 1. Windows服务器安全策略设置 操作系统关闭不必要的服务如smartd&#xff08;一个守护进程&#xff08;帮助程序&#xff09;、Print Spoole&#xff08;管理所有本地和网络打印队列及控制所有打印工作&#xff09;&#xff0c;操作系统关闭默认盘…

名著《MySQL必知必会》讲了个啥

文章目录 第一章 了解SQL第二章 检索数据第三章 排序第四章 过滤数据第五章 高级数据过滤第六章 多表查询内连接&#xff08;交集&#xff09;外连接多表连接UNIONUNION ALL 第七章 单行函数日期和时间函数获取日期、时间日期与时间戳的转换获取月份、星期、星期数、天数等函数…

chatgpt赋能python:Python中创建空列表的两种方法

Python中创建空列表的两种方法 在Python编程中&#xff0c;创建空列表是一项非常常见的任务。Python提供了两种主要的方法来创建一个空列表&#xff0c;分别是“中括号法”和“list()函数法”。本文将介绍这两种方法&#xff0c;它们的优缺点以及如何在你的代码中使用它们。 …