zoukankan      html  css  js  c++  java
  • TQ210裸机编程(4)——按键(中断法)

    S5PV210有4个向量中断控制器(VIC),每个向量中断控制器包含32个中断源。

    当某个中断源产生中断时,CPU会自动的将VICxVECTADDRy(x=0,1,2,3,y=0-31)寄存器的值赋给VICxADDRESS(x=0,1,2,3),因此我们可以把我们的中断处理函数的地址赋给VICxVECTADDRy寄存器,

    比如我们有个函数

    void key_handle()
    {    
    ……
    }

    我们把key_handle 函数的值赋给VIC0VECTADDR0(外部中断0)

    VIC0VECTADDR0 =key_handle


    外部中断0触发中断时,CPU会自动的将VIC0VECTADDR0的值赋给VIC0ADDRESS,并跳转到这个地址去执行,即执行函数key_handle


    代码如下:

    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 */


    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)		/* key1 */
    		GPC0DAT ^= 1 << 3;	/* toggle LED1 */
    	else if (key_code == 2)	/* key2 */
    		GPC0DAT ^= 1 << 4;	/* toggle LED2 */
    }
    
    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] */
    	
    	VIC0VECTADDR0 = (int)key_isr;			/* 当EXT_INT[0]触发中断,即用户按下key1时,
    											 CPU就会自动的将VIC0VECTADDR0的值赋给VIC0ADDRESS并跳转到这个地址去执 */
    	VIC0VECTADDR1 = (int)key_isr;
    	
    	while (1);
    	
    	return 0;
    }


    Makefile

    key.bin: start.o key.o
    	arm-linux-ld -Ttext 0x20000000 -o key.elf $^
    	arm-linux-objcopy -O binary key.elf $@
    	arm-linux-objdump -D key.elf > key.dis
    	
    key.o : key.c
    	arm-linux-gcc -c $< -o $@
    start.o : start.S
    	arm-linux-gcc -c $< -o $@
    	
    clean:
    	rm *.o *.elf *.bin *.dis
    


    将程序下载到内存运行

    按下key1,LED1点亮,再次按下key1,LED1熄灭

    按下key2,LED2点亮,再次按下key2,LED2熄灭

  • 相关阅读:
    利用正则表达式,完成参数的替换
    使用python读取yaml文件
    python+unittet在linux与windows使用的区别
    python发送requests请求时,使用登录的token值,作为下一个接口的请求头信息
    jmeter线程组之间传参
    requests:json请求中中文乱码处理
    ddt源码修改:HtmlTestRunner报告依据接口名显示用例名字
    使用openpyxl的styles,实现写入值时加背景色
    批量数据请求接口
    locust参数化
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3367735.html
Copyright © 2011-2022 走看看