TQ210——按键
底板上有8个独立按键,可分别使用查询法和中断法控制按键。通过原理图可知:按键按下,GPIO检测到低电平,松开时高电平。
直接查询法程序的实现简单,但是效率很低,CPU一直在查询,啥事也干不了。中断查询法程序的实现较为复杂,但是效率高。
GPIO寄存器(GPH0CON,GPH0DAT),外部中断寄存器(EXT_INT_0_CON,EXT_INT_0_MASK),中断通道选择(VIC0INTSELECT),中断使能(VIC0INTENABLE),中断向量地址(VIC0VECTADDR0,VIC0VECTADDR1),清除中断向量(EXT_INT_0_PEND)
.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 */
#define GPC0CON *((volatileunsigned int *)0xE0200060)
#define GPC0DAT *((volatileunsigned int *)0xE0200064)
#define GPH0CON *((volatileunsigned int *)0xE0200C00)
#define GPH0DAT *((volatileunsigned int *)0xE0200C04)
#define EXT_INT_0_CON *((volatileunsigned int *)0xE0200E00)
#define EXT_INT_0_MASK *((volatileunsigned int *)0xE0200F00)
#define VIC0INTSELECT *((volatileunsigned int *)0xF200000C)
#define VIC0INTENABLE *((volatileunsigned int *)0xF2000010)
#define VIC0VECTADDR0 *((volatileunsigned int *)0xF2000100)
#define VIC0VECTADDR1 *((volatileunsigned int *)0xF2000104)
#define VIC0ADDRESS *((volatile unsigned int*)0xF2000F00)
#define EXT_INT_0_PEND *((volatileunsigned int *)0xE0200F40)
extern void key_isr(void);
void key_handle()
{
volatileunsigned char key_code = EXT_INT_0_PEND & 0x03;
VIC0ADDRESS= 0; /* 清中断向量寄存器 */
EXT_INT_0_PEND&= ~0x03; /* 清中断挂起寄存器 */
if(key_code == 1) /* key1 */
{
GPC0DAT&= ~(0x01 << 3); /* toggleLED1 */
GPC0DAT|= 1 << 3; /* toggle LED1 */
}
else if(key_code == 2) /* key2 */
{
GPC0DAT&= ~(0x01 << 4); /* toggleLED1 */
GPC0DAT|= 1 << 4; /* toggle LED1 */
}
}
int main()
{
GPC0CON&= ~(0xFF << 12);
GPC0CON |=0x11 << 12; /*配置GPC0_3和GPC0_4为输出:LED1和LED2 */
GPH0CON |=0xFF << 0; /*配置GPH0_0和GPH0_1为外部中断:key1和key2 */
EXT_INT_0_CON&= ~(0xFF << 0);
EXT_INT_0_CON|= 2 | (2 << 4); /*配置EXT_INT[0]和EXT_INT[1]为下降沿触发 */
EXT_INT_0_MASK&= ~3; /* 取消屏蔽外部中断EXT_INT[0]和EXT_INT[1] */
VIC0INTSELECT&= ~3; /*选择外部中断EXT_INT[0]和外部中断EXT_INT[1]为IRQ类型的中断 */
VIC0INTENABLE|= 3; /*使能外部中断EXT_INT[0]和EXT_INT[1] */
/* 当EXT_INT[0]触发中断,即用户按下key1时,
** CPU就会自动的将VIC0VECTADDR0的值赋给VIC0ADDRESS并跳转到这个地址去执 */
VIC0VECTADDR0= (unsigned int)key_isr;
VIC0VECTADDR1= (unsigned int)key_isr;
while (1);
return 0;
}
裸机编程编译的时候一定要加16字节的头信息,编译生成的bin文件通过SD卡或者TFTP的方法下载到开发板。