DA14580外设篇之GPIO中断

 

1、GPIO中断描述

    DA14580的GPIO中断有6个,1个 键盘接口中断(KBRD)、5个独立中断线(IRQ0~IRQ4)。

1.1、IRQ0~IRQ4中断线

 

    一共有5组独立的中断线,每组中断线支持所有的IO管脚配置为中断输入源,一个中断线只能配置1个IO管脚,一个IO管脚可以配置多个中断线。因此最大只能配置5个管脚的独立中断。(每个中断线的消抖时间是共用的)

 

1.2、KBRD键盘接口中断

    键盘接口中断的中断输入源可以配置为所有的IO管脚,所有的管脚可以同时使能键盘中断。但不能独立配置每个管脚的中断方式(按下中断/松开中断、高电平中断/低电平中断)。

 

DA14580内部有一个键盘控制器,键盘控制器可以扫描GPIO管脚的状态。通过配置可以让它产生一个中断给CPU(KEYBR_IRQ)。

 

2、GPIO中断寄存器

2.1、GPIO_IRQ0_IN_SEL_REG 中断线0,中断源选择

 

符号描述
15:6 Reserved                                               
5:0     KBRD_IRQ0_SE 0: no input selected
 1: P0[0] is selected
 2: P0[1] is selected
 3: P0[2] is selected
 4: P0[3] is selected
 5: P0[4] is selected
 6: P0[5] is selected
 7: P0[6] is selected
 8: P0[7] is selected
 9: P1[0] is selected
10: P1[1] is selected
11: P1[2] is selected
12: P1[3] is selected
13: P1[4] is selected
14: P1[5] is selected
15: P2[0] is selected
16: P2[1] is selected
17: P2[2] is selected
18: P2[3] is selected
19: P2[4] is selected
20: P2[5] is selected
21: P2[6] is selected
22: P2[7] is selected
23: P2[8] is selected
24: P2[9] is selected
25: P3[0] is selected
26: P3[1] is selected
27: P3[2] is selected
28: P3[3] is selected
29: P3[4] is selected
30: P3[5] is selected
31: P3[6] is selected

32: P3[7] is selected

其它值,不选择任何管脚

2.2、GPIO_IRQ1_IN_SEL_REG 中断线1,中断源选择(参考GPIO_IRQ0_IN_SEL_REG )

2.3、GPIO_IRQ2_IN_SEL_REG 中断线2,中断源选择(参考GPIO_IRQ0_IN_SEL_REG )

2.4、GPIO_IRQ3_IN_SEL_REG 中断线3,中断源选择(参考GPIO_IRQ0_IN_SEL_REG )

2.5、GPIO_IRQ4_IN_SEL_REG 中断线4,中断源选择(参考GPIO_IRQ0_IN_SEL_REG )

 

2.6、GPIO_DEBOUNCE_REG 消抖寄存器

 

符号描述
15:14 Reserved
13DEB_ENABLE_KBRD1: 使能键盘(KBRD)消抖计数器
12DEB_ENABLE4

1: 使能中断线4(IRQ4)消抖计数器

11DEB_ENABLE31: 使能中断线3(IRQ3)消抖计数器
10DEB_ENABLE21: 使能中断线2(IRQ2)消抖计数器
9DEB_ENABLE11: 使能中断线1(IRQ1)消抖计数器
8DEB_ENABLE01: 使能中断线0(IRQ0)消抖计数器
7:6 Reserved
5:0DEB_VALUE消抖时间,0~63ms  (IRQ0~IRQ4共用)


2.7、 GPIO_RESET_IRQ_REG 中断复位寄存器(处理完中断后要复位中断,否则一直进入中断)

 

符号描述
15:6 Reserved
5RESET_KBRD_IRQ写1复位键盘(KBRD)中断,    读返回0
4RESET_GPIO4_IRQ写1复位中断线4(IRQ4)中断,读返回0
3RESET_GPIO3_IRQ写1复位中断线3(IRQ3)中断,读返回0
2RESET_GPIO2_IRQ写1复位中断线2(IRQ2)中断,读返回0
1RESET_GPIO1_IRQ写1复位中断线1(IRQ1)中断,读返回0
0RESET_GPIO0_IRQ写1复位中断线0(IRQ0)中断,读返回0

2.8、GPIO_INT_LEVEL_CTRL_REG    IRQx中断电平控制寄存器

 

符号描述
15:13 Reserved
12EDGE_LEVELN4同 EDGE_LEVELN0
11                             EDGE_LEVELN3                                                                         同 EDGE_LEVELN0
10EDGE_LEVELN2同 EDGE_LEVELNO
9           EDGE_LEVELN1同 EDGE_LEVELNO
8           EDGE_LEVELN0

中断线0的中断方式:

0:产生中断时,不用等待按键松开,复位中断后(GPIO_RESET_IRQ_REG对应位置1),继续产生新的中断。

 

1:产生中断时,等待按键松开,复位中断后,直到下次按下按键才会产生中断。

 

这里面的按键按下,可以是高电平,也可以是低电平,由INPUT_LEVEL0位决定。

 

个人理解:
0:为电平中断,如果电平一直保持时,复位中断后,它会一直产生新的中断(每次中断的间隔=DEB_VALUE)。高电平还是低电平由INPUT_LEVEL0位决定。

1:为边沿中断,因此电平一直保持时,也只触发一次中断。上升沿还是下降沿中断高由INPUT_LEVEL0位决定。

4INPUT_LEVEL4 
3INPUT_LEVEL3 
2INPUT_LEVEL2 
1INPUT_LEVEL1 
0INPUT_LEVEL0

中断线0的中断电平:

0:高电平中断

1:低电平中断

这个位和EDGE_LEVELN0配合用


2.9、KBRD_IRQ_IN_SEL0_REG  键盘控制寄存器0

符号描述
15KBRD_REL

0:按下产生中断,松开不中断

1:按下和松开都产生中断

按下是高电平还是低电平由KBRD_LEVEL决定

14         KBRD_LEVEL       

0:高电平中断

1:低电平中断

13:8KEY_REPEAT

 可设置值N = 0~63,单位ms。 

 N = 0: 按下时只中断一次。

 N > 0: 一直按下时,每N毫秒就中断一次。

7KBRD_P07_EN使能P0[7] 键盘中断
6KBRD_P06_EN使能P0[6] 键盘中断
5KBRD_P05_EN使能P0[5] 键盘中断
4KBRD_P04_EN使能P0[4] 键盘中断
3KBRD_P03_EN使能P0[3] 键盘中断
2KBRD_P02_EN使能P0[2] 键盘中断
1KBRD_P01_EN使能P0[1] 键盘中断
0KBRD_P00_EN使能P0[0] 键盘中断

2.10、KBRD_IRQ_IN_SEL1_REG  键盘控制寄存器1

 

符号描述
15KBRD_P15_EN使能P1[5] 键盘中断
14KBRD_P14_EN使能P1[4] 键盘中断
13KBRD_P13_EN使能P1[3] 键盘中断
12KBRD_P12_EN使能P1[2] 键盘中断
11KBRD_P11_EN使能P1[1] 键盘中断
10KBRD_P10_EN使能P1[0] 键盘中断
9KBRD_P29_EN使能P2[9] 键盘中断
8KBRD_P28_EN使能P2[8] 键盘中断
7KBRD_P27_EN使能P2[7] 键盘中断
6KBRD_P26_EN使能P2[6] 键盘中断
5KBRD_P25_EN使能P2[5] 键盘中断
4KBRD_P24_EN使能P2[4] 键盘中断
3KBRD_P23_EN使能P2[3] 键盘中断
2KBRD_P22_EN使能P2[2] 键盘中断
1KBRD_P21_EN使能P2[1] 键盘中断
0KBRD_P20_EN使能P2[0] 键盘中断

2.11、KBRD_IRQ_IN_SEL2_REG  键盘控制寄存器2

 

 

 

符号描述
15:8 Reserved
7KBRD_P37_EN使能P3[7] 键盘中断
6KBRD_P36_EN使能P3[6] 键盘中断
5KBRD_P35_EN使能P3[5] 键盘中断
4KBRD_P34_EN使能P3[4] 键盘中断
3KBRD_P33_EN使能P3[3] 键盘中断
2KBRD_P32_EN使能P3[2] 键盘中断
1KBRD_P31_EN使能P3[1] 键盘中断
0KBRD_P30_EN使能P3[0] 键盘中断

 

3、中断函数介绍

 

 

3.1、GPIO_EnableIRQ

使能管脚中断

GPIO_EnableIRQ( GPIO_PORT port, GPIO_PIN pin, IRQn_Type irq, bool low_input,
					 bool release_wait, uint8_t debounce_ms )
参数描述
port端口:GPIO_PORT_0 ~ GPIO_PORT_3
pin管脚:GPIO_PIN_0 ~ GPIO_PIN_15
irq

5个中断线

GPIO0_IRQn

GPIO1_IRQn

GPIO2_IRQn

GPIO3_IRQn

GPIO4_IRQn

low_input为true时低电平产生中断,为false时高电平产生中断
release_wait

为true时为边沿中断,为false时为电平中断

如:

low_input = true        release_wait = true      下降沿中断

low_input = false       release_wait = true      上升沿中断

 

low_input = true        release_wait = false      低电平中断(只要是低就一直触发中断)

low_input = false       release_wait = false      高电平中断(只要是高就一直触发中断)

debounce_ms按键消抖,单位为ms, 最大63

3.2、GPIO_ResetIRQ

复位中断标志

GPIO_ResetIRQ( IRQn_Type irq )
参数       描述
irq                     

中断类型:GPIO0_IRQn、GPIO1_IRQn、GPIO2_IRQn、GPIO3_IRQn、GPIO4_IRQn

3.3、GPIO_RegisterCallback

注册中断回调函数

GPIO_RegisterCallback(IRQn_Type irq, GPIO_handler_function_t callback)
参数描述
irq                     中断类型:GPIO0_IRQn、GPIO1_IRQn、GPIO2_IRQn、GPIO3_IRQn、GPIO4_IRQn
callback回调函数,中断时会自动调用这个函数。

3.4、GPIO_SetIRQInputLevel

设置中断电平,高电平中断还是低电平中断,和前面的low_input作用一样。

GPIO_SetIRQInputLevel(IRQn_Type irq, GPIO_IRQ_INPUT_LEVEL level)
参数描述
irq中断类型:GPIO0_IRQn、GPIO1_IRQn、GPIO2_IRQn、GPIO3_IRQn、GPIO4_IRQn
level

中断电平    

GPIO_IRQ_INPUT_LEVEL_HIGH 

GPIO_IRQ_INPUT_LEVEL_LOW 

3.5、GPIO_GetIRQInputLevel

获取中断电平,返回GPIO_IRQ_INPUT_LEVEL_HIGH 或 GPIO_IRQ_INPUT_LEVEL_LOW 

3.6、GPIO0_Handler

GPIO0_IRQn中断时会调用该函数。

 

3.7、GPIO1_Handler

GPIO1_IRQn中断时会调用该函数。

3.8、GPIO2_Handler

GPIO2_IRQn中断时会调用该函数。

3.9、GPIO3_Handler

GPIO3_IRQn中断时会调用该函数。

3.10、GPIO4_Handler

GPIO4_IRQn中断时会调用该函数。

 

3.11、KEYBRD_Handler

KEYBRD中断时会调用该函数。(该函数在gpio.c里面没有写出,可以自己添加)

void KEYBRD_Handler(void)
{
	GPIOSetBits16(GPIO_RESET_IRQ_REG ,RESET_KBRD_IRQ,1);
} 

复位KEYBRD中断时,不能调用GPIO_ResetIRQ,因为这个函数值针对IRQ0~IRQ4的中断复位,可以写成下面这样

GPIOSetBits16(GPIO_RESET_IRQ_REG ,RESET_KBRD_IRQ,1);

 

4、使用示例

 

4.1中断线IRQ0中断:

实现功能:1个按键、1个LED,按键按一次LED取反。

 

1)在user_periph_setup.h中定义要用到的管脚

#define KEY_PORT        GPIO_PORT_2
#define KEY_PIN         GPIO_PIN_4
#define LED_PORT        GPIO_PORT_2
#define LED_PIN         GPIO_PIN_3

2)在GPIO_reservations函数里面添加预留管脚。

void GPIO_reservations(void)
{
    RESERVE_GPIO(LED, LED_PORT,LED_PIN, PID_GPIO);
    RESERVE_GPIO(KEY, KEY_PORT,KEY_PIN, PID_GPIO);
}

3)在set_pad_functions函数里配置管脚工作模式

void set_pad_functions(void)       
{
	//配置LED管脚为输出,初始化为低电平
	GPIO_ConfigurePin(LED_PORT,LED_PIN,OUTPUT,PID_GPIO,false);
	
	//配置KEY管脚为上拉输入,初始化为高电平
	GPIO_ConfigurePin(KEY_PORT,KEY_PIN,INPUT_PULLUP,PID_GPIO,true);

	//使能按键中断,中断类型为GPIO0_IRQn,下降沿中断,消抖20ms
	GPIO_EnableIRQ(KEY_PORT,KEY_PIN,GPIO0_IRQn,true,true,20);   
        //注册GPIO0_IRQn中断回调函数
        GPIO_RegisterCallback(GPIO0_IRQn,GPIO_IRQ_Handle);	
} 

 

4)定义中断回调函数

 

void GPIO_IRQ_Handle(void)
{
	
	if(GPIO_GetPinStatus(LED_PORT,LED_PIN) == false)
	{
		GPIO_SetActive(LED_PORT,LED_PIN);
	}
	else
	{
		GPIO_SetInactive(LED_PORT,LED_PIN);
	}			
}
整个代码到这里就完成了,如果把GPIO_EnableIRQ改为
        GPIO_EnableIRQ(KEY_PORT,KEY_PIN,GPIO0_IRQn,true, false,20);
那么就变为低电平中断了,按键按下时,就会不停的进入中断,而且中断间隔为20ms。

 

 

 

4.2、键盘中断(KEYBRD)

实现功能:1个按键、1个LED,按键按一次LED取反。

 

1)在user_periph_setup.h中定义要用到的管脚

#define KEY_PORT        GPIO_PORT_2
#define KEY_PIN         GPIO_PIN_4

2)在GPIO_reservations函数里面添加预留管脚。

void GPIO_reservations(void)
{
    RESERVE_GPIO(LED, LED_PORT,LED_PIN, PID_GPIO);
    RESERVE_GPIO(KEY, KEY_PORT,KEY_PIN, PID_GPIO);
}

3)由于键盘中断官方并没有给出相关的函数,所以我们要自己实现

a、在gpio.c里面添加2个变量,KBRD_GPIO、KBRD_status,用来标志需要使能键盘中断的管脚。

int KBRD_GPIO[NO_OF_PORTS][NO_OF_MAX_PINS_PER_PORT];
volatile uint64_t KBRD_status;

b、编写KBRD_SELECT_GPIO函数,用来设置需要使能键盘中断的管脚。(设置KBRD_status 的值)

void KBRD_SELECT_GPIO(GPIO_PORT port, GPIO_PIN pin)   
{ 
	KBRD_GPIO[port][pin] = (KBRD_GPIO[port][pin] != 0) ? (-1) : 1; 
	KBRD_status |= ((uint64_t)KBRD_GPIO[port][pin] << pin) << (port * 16);
}

c、编写键盘中断使能函数

/**
 ****************************************************************************************
 * @brief 使能键盘中断
 *
 * @param[in] low_input     true:低电平中断   	false:高电平中断
 * @param[in] release_wait  true:按下和松开都中断	false:按下中断、松开不中断
 * @param[in] debounce_ms   消抖时间(看DEB_VALUE位)
 * @param[in] repeat_ms	    重复时间(看KEY_REPEAT位)
 *
 * @return void
 ****************************************************************************************
 */
void KBRD_Enable_IRQ(bool low_input,bool release_wait, uint8_t debounce_ms,uint8_t repeat_ms )
{	
	//是否使能键盘消抖
	GPIOSetBits16(GPIO_DEBOUNCE_REG, DEB_ENABLE_KBRD, (debounce_ms > 0) );
	//给出消抖时间最大63ms
	GPIOSetBits16(GPIO_DEBOUNCE_REG, DEB_VALUE, debounce_ms);
    
	GPIOSetBits16(KBRD_IRQ_IN_SEL0_REG, KBRD_REL, release_wait);
	GPIOSetBits16(KBRD_IRQ_IN_SEL0_REG, KBRD_LEVEL , low_input);
 	
	GPIOSetBits16(KBRD_IRQ_IN_SEL0_REG, KEY_REPEAT , repeat_ms);	
	
	//配置P0端口
	GPIOSetBits16(KBRD_IRQ_IN_SEL0_REG, 0xff   , KBRD_status&0xff);	
	//配置P1端口
	GPIOSetBits16(KBRD_IRQ_IN_SEL1_REG, 0xfc00 , ((KBRD_status>>16)&0x3f));	
	//配置P2端口
	GPIOSetBits16(KBRD_IRQ_IN_SEL1_REG, 0x3ff , ((KBRD_status>>32)&0x3ff));	
	//配置P3端口
	GPIOSetBits16(KBRD_IRQ_IN_SEL1_REG+2, 0xff , ((KBRD_status>>48)&0xff));	

	//中断优先级
	NVIC_SetPriority(KEYBRD_IRQn, 2);
	//使能中断
	NVIC_EnableIRQ(KEYBRD_IRQn);
}

d、编写中断处理函数

void KEYBRD_Handler(void)
{
	GPIOSetBits16(GPIO_RESET_IRQ_REG ,RESET_KBRD_IRQ,1);        
		
	if(GPIO_GetPinStatus(LED_PORT,LED_PIN) == false)
	{
		GPIO_SetActive(LED_PORT,LED_PIN);
	}
	else
	{
		GPIO_SetInactive(LED_PORT,LED_PIN);
	}
} 

 

3)在set_pad_functions函数里配置管脚工作模式

 

void set_pad_functions(void)       
{
	//配置LED管脚为输出,初始化为低电平
	GPIO_ConfigurePin(LED_PORT,LED_PIN,OUTPUT,PID_GPIO,false);
	
	//配置KEY管脚为上拉输入,初始化为高电平
	GPIO_ConfigurePin(KEY_PORT,KEY_PIN,INPUT_PULLUP,PID_GPIO,true);

	KBRD_SELECT_GPIO(KEY_PORT,KEY_PIN);             //需要使能键盘中断的管脚
	KBRD_Enable_IRQ(true,false,20,0);	        //使能键盘中断
} 

 

到这里,键盘中断相关的代码就编写完成了,可以运行程序看结果。

 

把KBRD_Enable_IRQ的参数改为下面这样

KBRD_Enable_IRQ(true,false,20,30);

一直按下按键时,每30ms就会进入1次中断。

 

 

 

 

 

 

 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dear_Wally

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值