TQ210——按键(中断查询法)

TQ210——按键


       底板上有8个独立按键,可分别使用查询法和中断法控制按键。通过原理图可知:按键按下,GPIO检测到低电平,松开时高电平。

       直接查询法程序的实现简单,但是效率很低,CPU一直在查询,啥事也干不了。中断查询法程序的实现较为复杂,但是效率高。

GPIO寄存器(GPH0CONGPH0DAT),外部中断寄存器(EXT_INT_0_CONEXT_INT_0_MASK),中断通道选择(VIC0INTSELECT),中断使能(VIC0INTENABLE),中断向量地址(VIC0VECTADDR0VIC0VECTADDR1),清除中断向量(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的方法下载到开发板。

你可能感兴趣的:(ARM,TQ210——裸机编程)