s5pv210的外部中断
2015-09-02 12:17 1784717631 阅读(379) 评论(0) 收藏 举报中断,在学单片机的时候就没有学好,这次接触到210的中断体系,直接蒙圈了。。前天下午老师简单的讲了一下,他的每句话拆开都可以听得懂,联系起来就傻了,,而且懂了与会写差距还远着呢。当天下午所有人都是萎靡的状态(不懂,不会写极其郁闷),以为参照裸机开发指南可以边写会慢慢理解,结果越写越是打击。晚上没有回去,一直想体验下在教室通宵的感觉,除了蚊子比较多、床不好睡、网速依旧渣、睡得太累,好吧,好像并没有什么优点。
虽然说是通宵了,但是几乎什么都没有学到,反而把自己搞得劳累。得不偿失!早上去领了免费包子,吃完回教室,大家在吐槽寝室那边“习俗”的事和程序的事,得到老师的承诺说下午会带着写程序,整个早上也没有怎么瞎折腾了,随便看看。
前几天写好的makefile今天打开居然无法使用,编译到最后连接的时候有段错误!!(致命一击),重新把程序审视了一遍,什么都没有发现。请教老师也没有找出来,可能是ld程序出错了,后来重启了几次依旧如此,不想再纠结了,直接做中断了。
6410和210的中断体系增加了向量中断的概念,相比2440,复杂程度乘法增加的。部分理解如下:
四个向量中断:每个分别存放32个中断源,注意是中断”源“,不是单个中断,理解这点很重要,因为每个中断“源”里面包含了若干中断
其中外部中断全部在第一个中断向量中,中断“源”是16,,,16中断“源”包含了EXT_INT[16] ~ [31]号中断,这里主要讨论16--19和24--28号的外部按键中断
由于存在中断“源”和具体中断的区别,所以分别有两套寄存器控制着,这一点也是非常重要的,操作“源”就可以操作里面的中断,里面具体的哪一号中断还要 另外控制。呵呵,现在只能理解部分,以后要好好加深。
中断处理函数和中断服务程序:(起这样两个名字的人有没有考虑过初学者的感受。。。)处理一个中断需要两级跳转,首先是跳转到中断处理函数(irq_handle和irq_handler 这两个函数真心不晓得是哪个),中断处理函数负责入栈、出栈等操作外,还负责跳转到中断服务程序(isr_key),在中断服务函数判断产生了具体哪个中断 (不是哪个中断“源”),然后执行相应的操作。
关于注册地址:中断处理函数需要注册到异常向量表的中断异常地址上,实现中断异常的跳转。
中断服务程序需要注册到相应的中断“源”地址上,
因为两者都是通过注册地址来调用的,所以都不需要直接动手调用函数
/******************************************************************************************************************************************************************************************************************/ 具体程序如下:
#include "stdio.h"
// 1.设置按键
#define GPH2CON       *((volatile unsigned int *)0xE0200C40)
#define GPH3CON       *((volatile unsigned int *)0xE0200C60)
//中断状态寄存器,可以通过该寄存器知道中断是否发生
#define VIC0IRQSTATUS        *((volatile unsigned int *)0xF2000000)
//中断选择
#define VIC0INTSELECT        *((volatile unsigned int *)0xF200000C)
//中断使能寄存器
#define VIC0INTENABLE         *((volatile unsigned int *)0xF2000010)
//禁止所有中断
#define VIC0INTENCLEAR      *((volatile unsigned int *)0xF2000014)
//存放中断处理函数的地址
//VICAddress:向量地址寄存器.当IRQ中断产生时,
//此寄存器保存当前激活的中断向量的地址.
#define VIC0ADDR          *((volatile unsigned int *)0xF2000F00)
//存放中断服务程序的地址
#define VIC0VECTADDR16      *((volatile unsigned int *)0xF2000140)
//#define VIC0_BASE					(0xF2000000)
//#define  VIC0EINT16ADDR    ( *((volatile unsigned long *)(VIC0_BASE + 0x100 + 64)) )
//设置中断为下降沿触发
#define EXT_INT_2_CON    *((volatile unsigned int *)0xE0200E08)
#define EXT_INT_3_CON    *((volatile unsigned int *)0xE0200E0C)
//不屏蔽中断
#define EXT_INT_2_MASK      *((volatile unsigned int *)0xE0200F08)
#define EXT_INT_3_MASK      *((volatile unsigned int *)0xE0200F0C)
//记录中断,有中断发生相应位就会置1,初始化时相应位清零
//可以用来检测具体哪一个中断是否发生
//VIC0IRQSTATUS是检测是否有中断产生(总体与个体的关系)
#define EXT_INT_2_PEND      *((volatile unsigned int *)0xE0200F48)
#define EXT_INT_3_PEND      *((volatile unsigned int *)0xE0200F4C)
//中断向量表
#define		_Exception_Vector			0xD0037400
#define		pExceptionRESET	    		( *((volatile unsigned long *)(_Exception_Vector + 0x0)) )
#define		pExceptionUNDEF    			( *((volatile unsigned long *)(_Exception_Vector + 0x4)) )
#define		pExceptionSWI	  	     	( *((volatile unsigned long *)(_Exception_Vector + 0x8)) )
#define 		pExceptionPABORT	     	( *((volatile unsigned long *)(_Exception_Vector + 0xc)) )
#define 		pExceptionDABORT	     	( *((volatile unsigned long *)(_Exception_Vector + 0x10)) )
#define		pExceptionRESERVED       ( *((volatile unsigned long *)(_Exception_Vector + 0x14)) )
#define 		pExceptionIRQ         			( *((volatile unsigned long *)(_Exception_Vector + 0x18)) )
#define 		pExceptionFIQ      			( *((volatile unsigned long *)(_Exception_Vector + 0x1c)) )
void IRQ_handle(void);  //用来现场保护和恢复,并且跳转到中断处理函数,不用调用
void enable_irq(void);  //使能cpsr的总中断
void disable_irq(void);  //关闭cpsr的总中断
void key_isq(void);
void delay(void);
/************************************************************************************************/
int init_interrupt_reg()
{
               //printf("here1\r\n");
	  //禁止所有中断
	  VIC0INTENCLEAR = 0xffffffff;
	   //设置成普通中断模式
	  VIC0INTSELECT = 0x0;
	  //清除中断地址
	  VIC0ADDR = 0x0;
	  return 0;
}
int init_gpio(void)
{
           //printf("here3\r\n");
	//设置GPH2 0~3为中断方式
	//GPH2CON &= 0xffff0000;
	GPH2CON |= 0x0000ffff;
	GPH3CON |= 0x0000ffff;
	//设置外部中断为下降沿触发
	EXT_INT_2_CON &= 0xffff8888;  //保留位不清零
	EXT_INT_2_CON |= 0x00002222;
	
	EXT_INT_3_CON &= 0xffff8888;  //保留位不清零
	EXT_INT_3_CON |= 0x00002222;
	//打开外部中断16--19
	EXT_INT_2_MASK &= 0xfffffff0;
	//打开外部中断24--27
	EXT_INT_3_MASK &= 0xfffffff0;
	//通过清除中断记录,清除外部中断,写1清零
	EXT_INT_2_PEND = 0xff;
	EXT_INT_3_PEND = 0xff;
//使能16号外部中断源
 VIC0INTENABLE |= (0x1<<16);
	return 0;
}
 
int  set_isr_addr(void)
 {
             //printf("here2\r\n");	
 
 	//注册中断服务子函数到相应的中断响应地址
 	//每个源都有一个特有的地址,16号中断源
 	VIC0VECTADDR16 = (unsigned long)key_isq;
 	
 	//注册中断处理函数到中断异常
 	pExceptionIRQ = (unsigned long)IRQ_handle;
 	return 0;
 }
//编写中断服务子函数
void key_isq(void)
{
           //printf("here6\r\n");
           delay();//消抖
           
	unsigned int reg = 0;
	unsigned int reg1 = 0;
	reg = EXT_INT_2_PEND;//有中断产生时相应位就会有记录为1
	reg1 = EXT_INT_3_PEND;  // 25--28的中断记录
	//判断16--19号外部中断产生 了哪一个
	if((reg & 0x01)==0x01)
	{
		//记录位为1,有中断,为EINT16
		printf("key1(EINT16) down\r\n");
	}
	else if(reg & (0x01<<1))
	{
		//记录位为1,有中断,为EINT17
		printf("key2(EINT17) down\r\n");
	}
	else if(reg & (0x01<<2))
	{
		//记录位为1,有中断,为EINT18
		printf("key3(EINT18) down\r\n");
	}
	else if(reg & (0x01<<3))
 {
		//记录位为1,有中断,为EINT19
		printf("key4(EINT19) down\r\n");
	}
	//判断25--28号外部中断产生 了哪一个
	 if((reg1 & 0x01)==0x01)
	{
		//记录位为1,有中断,为EINT19
		printf("key5(EINT24) down\r\n");
	}
	else if(reg1 & (0x01<<1))
	{
		//记录位为1,有中断,为EINT19
		printf("key6(EINT25) down\r\n");
	}
	else if(reg1 & (0x01<<2))
	{
		//记录位为1,有中断,为EINT19
		printf("key7(EINT26) down\r\n");
	}
	else if(reg1 & (0x01<<3))
	{
		//记录位为1,有中断,为EINT19
		printf("key8(EINT27) down\r\n");
	}
	
	VIC0ADDR =0x0;       //随便写入一个值表示中断服务子函数结束
	EXT_INT_2_PEND = 0xf; //通过写1去清零16--19相应的记录位
	EXT_INT_3_PEND = 0xf; //通过写1去清零25--28相应的记录位
}
typedef void  funp(void);//定义了funp的函数类型,记得加;号
//中断处理函数
void  irq_handler(void)
{
           //printf("here5\r\n");	
	unsigned int reg = 0;
	
	void (*isr)(void);
	
	reg = VIC0IRQSTATUS;
	if(reg !=0)
	{
		//有中断产生
		isr = (funp*)VIC0ADDR;//类型强转,读取中断向量的地址执行中断服务子程序
	}
	(*isr)();
}
/**************************************************************************************/
void init_exint(void)
{			
	disable_irq();
	init_interrupt_reg();
		
	set_isr_addr();
		
	//irq_handler(void);由IRQ_handle()函数调用到
	
	//中断处理函数和中断服务程序不用注册,
	//key_isq(void);由于已经安装了地址,有中断产生时自然会调用
	
	init_gpio();
		
	enable_irq(); 
}
、*********************************************************************************************************************************************************************/
吐槽下博客园的程序文本格式。。。
虽然说程序写完了,准确的说是抄完了,现在让我一个写还是没有把握写出来,毕竟那么多寄存器不是那么好找的,更别说用了。在老师程序的基础上,完成了全部八个外部按键中断,
还有一点是要注意的是,由于裸机是没有标准库的,所以要想很好的调试程序,在裸机上面移植了网上的printf函数,只要把自己写的程序最后组装成一个函数,然后直接把组装好的函数扔进printf的主函数即可。
记得要把源代码赋值到printf的目录,直接加到项目工程是不能编译的,,,加进去之后还有把目录里面的加载到工程里面,否则修改不到。。。(这种错误,智商捉急啊。。)
                    
                
                
            
        
浙公网安备 33010602011771号