ARM进阶 003 中断

预备实验:如何检测是否按下了K1按键?

/*预备实验:如何检测是否按下了K1按键?*/
/*按下k1即点亮LED1*/

/*配置LED灯*/
#define rGPBCON  (*(unsigned int *)0x56000010)
#define rGPBDAT	 (*(unsigned int *)0x56000014)

/*配置K1*/
#define rGPGCON  (*(unsigned int *)0x56000060)
#define rGPGDAT  (*(unsigned int *)0x56000064)


// led初始化
void ledInit(void)
{
	// LED IO设置为输出
	rGPBCON |= (1<<10) ;
	// 灭灯
	rGPBDAT |= (1<<5);
	
}

// 点亮led
void ledon(void)
{
	rGPBDAT &= (~(1<<5));
}


// 熄灭led
void ledoff(void)
{
	rGPBDAT |= (1<<5);
}

// 按键初始化
void keyInit(void)
{
	// io设置为输入
	rGPGCON &= ~(3<<0);
}


void KeyScanMain(void)
{
	// 初始化led
	ledInit();
	
	while(1)
	{
		// 循环检测按键是否按下---- 效率低
		if ((rGPGDAT & (1<<0)) == 0)
		{
			ledon();
		}
	}
}	area Init , code , readonly
	code32
	entry
start
	b resetHandler  ;中断向量表
	nop
	nop
	nop
	nop
	nop
	nop
	
resetHandler
	    ; 初始化堆栈(FD)
		ldr sp, =0x34000000
		
		;混合编程--汇编调用C(impoort和b)
		import KeyScanMain
		b   KeyScanMain

stop
	b stop
	end


此种方法的弊端:陷入“检测是否按下K1”的死循环,无法做其他事。
如何让程序既能判断是否按下K1,又能执行其他功能呢?



预备知识一:中断
1、中断基本概念
中断的定义:在程序运行中,出现了某种紧急事件,CPU必须中止现行程序,转去处理此紧急事件(执行中断服务程序),并在处理完毕后再返回运行程序的过程。
ARM进阶 003 中断_第1张图片

2、中断源
   引起CPU中断的事件——中断源。 中断源包括:
1)来自处理器外部的中断。如I/O设备请求、实时时钟等。
2)故障源。如电源掉电,校验出错等。
3)软件中断。如在调试程序时设置的断点等。


3、中断的作用 
   为何计算机中要引入中断?——提高计算机工作效率。
   CPU与外设之间的数据传送控制方式(即I/O控制方式),通常有以下三种:1)程序控制方式    2)中断方式     3)DMA方式(Direct Memory Access)
  中断的作用: 
1)并行操作:指CPU和多个外设并行操作。
2)分时操作:指CPU可分时执行多个用户程序和多道作业。
3)实现实时处理、 故障处理。
4)基本功能调用:通过软件中断可实现DOS功能调用和基本BIOS调用。
5)提高了CPU的利用效率。

4、中断优先级与中断嵌套
中断优先级:
CPU响应并处理中断请求的先后次序。
同时有多个中断请求时优先级高的先得到响应。
中断嵌套:
CPU在执行某个中断服务程序过程中对更高级别的中断请求的响应。


5、中断的分类
ARM进阶 003 中断_第2张图片
说明:高性能微机中软中断称为异常。


6、可屏蔽中断和不可屏蔽中断
可屏蔽中断:可由用户指令来确定是否允许CPU响应的中断为可屏蔽中断
屏蔽中断:不能由用户用软
件屏蔽 的中断为非屏蔽中断。CPU必须响应非屏蔽中断请求。非屏蔽中断可由CPU外部产生,也可由CPU内部产生。外部产生的非屏蔽中断请求一般由NMI线引入。


7、中断过程
1)中断请求
       中断系统需要解决的问题:
1>将随机出现的中断请求信号保持到被CPU发现。(锁存)
2>CPU响应中断请求后及时清除该请求信号。        措施:设置中断请求触发器
3>对于多个中断源增加控制的灵活性。                    措施:设置中断屏蔽触发器
4>多个中断源的识别与判优

2)中断判优(有时还要进行中断源识别)
     
3)中断响应
1>CPU在每条指令执行的最后一个总线周期(机器周期)的最后一个T状态检测中断请求输入端有无有效请求信号。
2>响应的先决条件:
(路是通的,不同中断控制器会有差别)
     ①中断请求屏蔽触发器置1。(中断源使能)
     ②中断屏蔽触发器置0。(中断使能)
     ③CPU内部开中断。(中断总使能)
     ④没有更高优先级别的中断请求正在被响应或正在发出。
3>先决条件有关的说明:(不同中断控制器会有一些差别)
      ①CPU内部中断允许触发器的状态可由指令来设定。
      ②有三种情况可使CPU关中断:     CPU复位时, CPU自动关中断;     中断请求被响应后, CPU自动关中断;     CPU执行关中断指令。
      ③中断关闭后要通过开中断指令才能开放中断。
4>CPU响应中断会自动完成:(不同微处理器会完成的内容会有一些差别)
      ①关闭中断;
      ②保护断点;(方便返回)
      ③特殊寄存器(CS、IP及FR内容)入栈;
     ④寻找中断源,确定入口,转向中断服务程序。

4)中断服务

5)中断返回
   ARM进阶 003 中断_第3张图片





预备知识二:

ARM进阶 003 中断_第4张图片

既然需要使用中断,则需要中断控制器

ARM进阶 003 中断_第5张图片





1.如果IRQ信号成功的传递到了arm920t内核,内核认为发生了一个irq异常:
内核检测CPSR的I位,看是否为I=0,如果是,就会处理这个异常。
内核如何处理这个异常呢?
1)cpsr -> spsr_irq
2)修改cpsr的值:
I = 1
MOD = 0x12
lr = pc-4
T = 0
PC = 0x18

2.软件如果想要检测IRQ中断:
中断发生前:
初始化arm920t相关寄存器:
· 1)使能IRQ I=0
2) 切换到各个模式下,初始化相应模式的sp

初始化:保证中断请求信号能够成功的传递到arm920t中。
1)GPIO功能选择寄存器,选择外部中断功能
2)触发信号初始化(低电平,上升沿,下降沿等)
3)使能EINTMASK相应的位
4)使能INTMSK相应的位。


准备Irq异常处理的代码:
1)中断向量表0x18的位置写 b irqHandler
2) irqHandler标号位置,处理IRQ的业务
3)处理完后需要异常返回。




实验:检测是否按下了K1按键?

实现按下K1,LED灯全亮,再按下时LED灯全灭的功能。







工程所需文件:


工程文件夹中应包含的其他文件:

ARM进阶 003 中断_第6张图片


更改环境:

ARM进阶 003 中断_第7张图片





附(核心代码):

/*预备实验:如何检测是否按下了K1按键?*/
/*按下k1即点亮LED1*/

/*配置LED灯*/
#define rGPBCON  (*(unsigned int *)0x56000010)
#define rGPBDAT	 (*(unsigned int *)0x56000014)

/*配置K1*/
#define rGPGCON  (*(unsigned int *)0x56000060)
#define rGPGDAT  (*(unsigned int *)0x56000064)


// led初始化
void ledInit(void)
{
	// LED IO设置为输出
	rGPBCON |= (1<<10) ;
	// 灭灯
	rGPBDAT |= (1<<5);
	
}

// 点亮led
void ledon(void)
{
	rGPBDAT &= (~(1<<5));
}


// 熄灭led
void ledoff(void)
{
	rGPBDAT |= (1<<5);
}

// 按键初始化
void keyInit(void)
{
	// io设置为输入
	rGPGCON &= ~(3<<0);
}


void KeyScanMain(void)
{
	// 初始化led
	ledInit();
	
	while(1)
	{
		// 循环检测按键是否按下---- 效率低
		if ((rGPGDAT & (1<<0)) == 0)
		{
			ledon();
		}
	}
}	area Init , code , readonly
	code32
	entry
start
	b resetHandler  ;中断向量表
	nop
	nop
	nop
	nop
	nop
	nop
	
resetHandler
	    ; 初始化堆栈(FD)
		ldr sp, =0x34000000
		
		;混合编程--汇编调用C(impoort和b)
		import KeyScanMain
		b   KeyScanMain

stop
	b stop
	end
		area	resetsec, code, readonly
		code32
		entry
		import	Main
		
		b		start
		nop
		nop
		nop
		nop
		nop
		nop
		nop

start	
		ldr		sp, =0x34000000

		ldr		r2, =0x015550
		ldr		r1, =0x56000010
		str		r2, [r1]
    
		ldr		r2, =0x7ff
		ldr		r1, =0x56000018
		str		r2, [r1]
    
		ldr		r1, =0x56000014

    
led_loop    
		ldr		r2, =0x1e0
	    str		r2, [r1]
	    
	    bl		asmdelay
	    
	    ldr		r2, =0
	    str		r2, [r1]
	    
	    bl		asmdelay

	 	;b		led_loop
	 	
	 	b		Main
	 	
	 	export	asmdelay
asmdelay
		ldr		r7, =0x1000000
del_loop
		sub		r7, r7, #1
		cmp		r7, #0
		bne		del_loop
		mov		pc, lr
	
		end#include "uart0.h"


int Main(void)
{
	unsigned char buf[] = "hello neusoft#\n";
	int aa = 120;
	
	rGPBCON = 0x015550;
	rGPBDAT = 0x1e0;
	
	uart0_init();
	
	
	Uart0_Printf("aa = %d\n", aa);
	
	uart0_sendstring(buf);
	
	while(1)
	{
		//uart0_sendstring(buf);
		uart0_sendchar(uart0_recv());
	}

	/*
	//exchangeab();
	while(1)
	{
		rGPBDAT = 0x1e0;
		asmdelay();
		rGPBDAT = 0;
		asmdelay();
	}*/
	return 0;
}#include "uart0.h"
#include 
#include 
#include 
#include 
#include 

void uart0_init(void)
{
	//初始化引脚,选择串口0功能
	rGPHCON = (rGPHCON &(~(0xf << 4))) | (0x2 << 4) | (0x2 << 6);
	rULCON0 = (0x3 << 0);
	
	rUFCON0 = 0;
	rUBRDIV0 = 26;
	
	rUCON0 = 0;
	rUCON0 = (1<<2) | (1<<0);
	
	return;	
}

void uart0_sendchar(unsigned char ch)
{
	while( (rUTRSTAT0 & (1<<1)) == 0)
	{
		;
	}
	rUTXH0 = ch;
	return;
}

void uart0_sendstring(unsigned char *str)
{
	while(*str != '\0')
	{
		uart0_sendchar(*str);
		str++;
	}
	return;
} 

unsigned char uart0_recv(void)
{
	while((rUTRSTAT0 & (1 << 0)) == 0)
	{
		;
	}

	return rURXH0;
}


void Uart0_Printf(char *fmt,...)
{
    va_list ap;
    char string[256];

    va_start(ap,fmt);
    vsprintf(string,fmt,ap);
    uart0_sendstring((unsigned char*)string);
    va_end(ap);
} 




PS:其余文件直接引用即可(文件见网盘)














你可能感兴趣的:(ARM_ARM进阶)