TQ210_裸机编程(二)——按键控制LED灯

来源:互联网 发布:免费发信息的软件 编辑:程序博客网 时间:2024/05/17 03:55

TQ210_裸机编程——按键key控制LED灯

 

首先我们可以在开发板配套材料中找到按键的电路图,E:\TQ210_CD\开发板配套电路图\Bottom\pdf格式\TQ210_BOARD_V4_20121023。

可以看到按键key1~key6对应的地址线为XEINT0~XEINT5,我们暂时就只用前面几个按键。

然后我们再找地址线在板子中相应的引脚号。

 

可以看到 按键地址线XEINT0~XEINT5对应的管脚号为GPH0_1~GPH0_5。

现在在S5PV210_UM_REV1.1文档中就能找到GPH0的控制寄存器,对应的控制6个按键。

 

将按键控制寄存器都设置为外部中断处理。然后去设定外部中断的处理相应参数。

外部中断要设置2个中断寄存器,EXT_INT_CON,EXT_INT_MASK。

由于按键按下时为低电平,所以全部设置为Falling edge triggered。

设置完EXT_INT_CON,还要设置EXT_INT_MASK,(外部中断控制寄存器)。

将需要使用的按键对应的外部中断处理 设置为允许中断。

再设置中断选择寄存器VIC0INTSELECT,选择中断模式(一般为IRQ模式)。

 

之后再设置VICINTENABLE寄存器,中断使能寄存器。

 

当中断发生时,需要一个存放中断处理的寄存器VICVECTADDR,中断发生后,就跳转到该寄存器里的函数开始执行。

例如:

VIC0VECTADDR0 = (unsigned int)key_isr;

中断发生后就跳转到key_isr处去执行了。

但是涉及到跳转执行的时候,就需要考虑保护现场的操作了。

例如:在key_isr中

key_isr:
 /* 计算返回地址:PC的值等于当前执行的地址+8,
 ** 当CPU正要执行某条指令时(还未执行),被中断,
 ** 这是这条刚要执行的指令的地址刚好=PC-4(可查三级流水线工作原理) */
 sub lr, lr, #4
 stmfd sp!, {r0-r12, lr}   /* 保护现场 ,由于不知道使用的具体哪个通用寄存器,所以讲0~12全部压栈*/
 bl key_handle
 /* 恢复现场 */
 ldmfd sp!, {r0-r12, pc}^   /* ^表示把spsr恢复到cpsr */

 

由于用到中断处理,所以对cpsr(当前程序状态寄存器)要进行参数设置,

要使用IRQ中断,就要使i位为0,

/* 开总中断 */
 mrs r0, cpsr  /*传送cpsr的内容到r0*/
 bic r0, r0, #0x00000080  /* 清楚第7位,IRQ中断禁止位,写0使能IRQ */
 msr cpsr, r0  /*传送r0的内容到cpsr*/

BIC―――――位清除指令指令格式:BIC{cond}{S} Rd,Rn,operand2 BIC指令将Rn 的值与操作数operand2 的反码按位逻辑”与”,结果存放到目的寄存器Rd 中。指令示例:BIC R0,R0,#0x0F ;将R0最低4位清零,其余位不变。

 

在上面保护现场的时,程序跳转到key_handle执行。

void key_handle()

 volatile unsigned char key_code = EXT_INT_0_PEND & 0x3;
 
 VIC0ADDRESS = 0;  
 EXT_INT_0_PEND |= 3;
 
 if (key_code == 1)  
 /* GPC0DAT ^= 1 << 3;*/
  GPC0DAT |= 0x00000008;
 else if (key_code == 2) 
 /* GPC0DAT ^= 1 << 4;*/ 
  GPC0DAT |= 0x00000010;
}

 


程序中EXT_INT_0_PEND寄存器为发生中断后的数据变化。1就是发生了中断。

 

整体源代码如下:

/*key.c*/

#define GPC0CON *((volatile unsigned int *)0xE0200060)
#define GPC0DAT *((volatile unsigned int *)0xE0200064)

#define GPH0CON *((volatile unsigned int *)0xE0200C00)
#define GPH0DAT *((volatile unsigned int *)0xE0200C04)

#define EXT_INT_0_CON   *((volatile unsigned int *)0xE0200E00)
#define EXT_INT_0_MASK  *((volatile unsigned int *)0xE0200F00)

#define VIC0INTSELECT  *((volatile unsigned int *)0xF200000C)
#define VIC0INTENABLE   *((volatile unsigned int *)0xF2000010)

#define VIC0VECTADDR0  *((volatile unsigned int *)0xF2000100)
#define VIC0VECTADDR1  *((volatile unsigned int *)0xF2000104)

#define VIC0ADDRESS    *((volatile unsigned int *)0xF2000F00)

#define EXT_INT_0_PEND  *((volatile unsigned int *)0xE0200F40)

extern void key_isr(void);
void key_handle()

 volatile unsigned char key_code = EXT_INT_0_PEND & 0x3;
 
 VIC0ADDRESS = 0;  
 EXT_INT_0_PEND |= 3;
 
 if (key_code == 1)  
 /* GPC0DAT ^= 1 << 3;*/
  GPC0DAT |= 0x00000008;
 else if (key_code == 2) 
 /* GPC0DAT ^= 1 << 4;*/ 
  GPC0DAT |= 0x00000010;
}

int main()
{
 GPC0CON &= ~(0xFF << 12);
 GPC0CON |= 0x11 << 12;     
 GPH0CON |= 0xFF << 0;     
 
 EXT_INT_0_CON &= ~(0xFF << 0);
 EXT_INT_0_CON |= 2 | (2 << 4);   
 EXT_INT_0_MASK &= ~3;     
 
 VIC0INTSELECT &= ~3;     
 
 VIC0INTENABLE |=3;       
 
 
 VIC0VECTADDR0 = (unsigned int)key_isr;
 VIC0VECTADDR1 = (unsigned int)key_isr;
 
 while (1);
 
 return 0;
}

/*start.S*/

.global _start     /* 声明一个全局的标号 */
.global key_isr
_start:
 /* 设置栈,以调用c函数 */
 ldr sp, =0x40000000  

 /* 开总中断 */
 mrs r0, cpsr
 bic r0, r0, #0x00000080  /* 清楚第7位,IRQ中断禁止位,写0使能IRQ */
 msr cpsr, r0

 bl main      /* 跳转到C函数去执行 */

halt:
 b halt

key_isr:
 /* 计算返回地址:PC的值等于当前执行的地址+8,
 ** 当CPU正要执行某条指令时(还未执行),被中断,
 ** 这是这条刚要执行的指令的地址刚好=PC-4 */
 sub lr, lr, #4
 stmfd sp!, {r0-r12, lr}   /* 保护现场 */
 bl key_handle
 /* 恢复现场 */
 ldmfd sp!, {r0-r12, pc}^   /* ^表示把spsr恢复到cpsr */

 

 

0 0
原创粉丝点击