简介:
本文主要介绍完成作业时在触摸屏中断,ADC中断以及IIC中断中碰到的一些问题。
中断简介:
在没有做这个作业之前我一直没有写过子中断的程序,直到这个作业我使用了ADC中断和触摸屏子中断。而这两个中断的结合使用也让我学到了很多。知道了如何对子中断进行操作,如果判断一个中断是触摸屏中断还是ADC中断。这些都是我在这个作业中学到了。所以也要感谢这次的作业让我认识了更多,了解了更多。
下面我们来讲解这两个中断,我们先看下面的两幅图:
从上面的中断处理框图和SRCPND映射图中,我们可以看出不管是触摸屏子中断还是ADC中断,他们在触发时都会使SRCPND位中对应的ADC位(bit[31])设置为高电平。同时在中断触发函数中我们只能注册一个中断处理函数。因为在中断偏移寄存器(INFOFFSET)中只有ADC位(bit[31]),而并无触摸屏的位。
这里我们遇到了第一个问题:如何来确定我们是触摸屏触发中断还是ADC触发中断?
这就要通过SUBSRCPND来判断了。不管是触摸屏触发中断还是ADC触发中断,SRCPND位都会被设为高电平。但是SUBSRCPND就不一样了,只有当触摸屏触发时,SUBSRCPND中INT_TC位(bit[9])被设为高电平。而当ADC触发时该位没有变化。所以我们使用该位来确定是触摸屏触发还是ADC触发。这样我们关于ADC和触摸屏的中断程序就可以写出来了。
触摸屏与ADC中断程序为:
void ADCIntHandle(void)
{
static int cnt;
static int x[4],y[4];
int i;
if(SUBSRCPND & (BIT_SUB_TC)){ //用于判断是否是触摸屏中断,如果不是触摸中断,那么就是ADC中断了
SRCPND |= (1<<31);
INTPND |= (1<<31);
SUBSRCPND |= (1<<9);
if(ADCDAT0 & (1<<15)){
printf("TC up!!!!!!!!!!!\n");
enter_wait_pen_down_mode();
}else{
/* 4.4 在中断中启动ADC,转化XY坐标 */
printf("TC down!!!!!!!!!!\n");
while(!ADCDAT0 & (1<<15));
enter_measure_xy_mode();
start_adc();
}
}else{ //此时为ADC中断
SRCPND |= (1<<31);
INTPND |= (1<<31);
x[cnt] = ((ADCDAT0)&0x3ff);
y[cnt] = ((ADCDAT1)&0x3ff);
draw_x = ((ADCDAT0)&0x3ff);
draw_y = ((ADCDAT1)&0x3ff);
cnt++;
if(ADCDAT0 & (1<<15)){
printf("ADC up!!!!!!!!!!!!\n");
enter_wait_pen_down_mode();
if(cnt >= 4){ //注意这里一定要写为大于等于4
ADC_x = x[2];
ADC_y = y[2];
for(i=0;i<4;i++){
x[i]=0;
y[i]=0;
}
printf("adc_irq x= %d, y=%d \n",ADC_x,ADC_y);
flag_up = 1;
cnt = 0;
}
}else{
printf("ADC down!!!!!!!!!!!!\n");
enter_wait_pen_up_mode();
}
}
}
我觉得这里有一个很值得注意的地方是:if(cnt >= 4) 。为什么会对这个地方这么重视?是因为我在这里吃了很大的亏。所以希望日后的自己和看这篇文章的同学以后不要犯同样的错误。我以前的判断是:if(cnt == 4),但是我有时候发现程序会在跑着跑着的时候就没有反应了。我都不知道是什么原因,后来我慢慢看程序,才发现是这里的错误。如果这里用等于4来判断是否进行值确认操作。但是有时候由于一些中断原因cnt的值会超过4,这样cnt的值会越来越大,而我们的程序却回不到我们当初的设想。而当改为>=4后这个问题就迎刃而解了。所以希望大家以后不要和我一样犯这样的错误。
IIC中断:
触摸屏和ADC中断写好之后我们就要写另一个中断IIC中断了。由于IIC中断相对于上面的中断就简单一些了,因为他不用对子中断进行判断。所以他只要在中断初始化函数中将自己的处理函数注册进去,然后在中断处理中调用自己的处理函数就好了。程序为:
void init_irq(void)
{
int i = 0;
for (i = 0; i < sizeof(isr_handle_array) / sizeof(isr_handle_array[0]); i++)
{
isr_handle_array[i] = Dummy_isr;
}
INTMOD = 0x0; // 所有中断都设为IRQ模式
INTMSK = BIT_ALLMSK; // 先屏蔽所有中断
isr_handle_array[ISR_ADC_OFT] = ADCIntHandle;
isr_handle_array[ISR_IIC_OFT] = I2CIntHandle;
}
void IRQ_Handle(void)
{
unsigned long oft = INTOFFSET;
/* 调用中断服务程序 */
isr_handle_array[oft]();
}
而关于IIC裸机操作OLED的介绍我在文章:
嵌入式Linux——IIC总线驱动(1):2440裸板驱动OLED中已经做了详细的介绍。