串口中断实验
我们之前做过串口的实验,使用的是启用FIFO功能,以轮询的形式发送和接收数据。采用一位起始位,八位数据位,零位校验位,一位停止位的数据帧格式。
现在我们要添加中断功能,通过中断来接收数据。需要说明的一点是,我们之所以不使用中断来发送数据,是因为我们的串口一直在打印东西,所以如果开启了发送中断,那么会一直进IRQ中断。
设置FIFO中断触发条件
这个功能比较简单,我们首先需要设置FIFO中断触发条件,如下图所示:
我们将中断设置为发送FIFO剩余48字节、接收FIFO多于8字节时产生中断。因为我们后面没有清除掉发送中断掩码,所以不会产生发送中断。
UFCON0 &= (~(0xF0));
UFCON0 |= ((0x3 << 6) | (0x1 << 4));
中断控制器设置
我们需要在中断控制器中取消串口UART0相对应的接收和发送中断屏蔽。
通过上图我们可知,UART0对应的中断还细分了三个子中断,所以我们既要设置INTMSK,也要设置INTSUBMSK。
我们将UART0的接收中断 和 错误中断打开。
INTMSK = (~(0x1 << 28));
INTSUBMSK = (~(0x5));
至此,我们开启了UART0的接收、发送和错误中断。
串口0中断处理函数
由中断偏移寄存器INTOFFSET寄存器可知:UART0对应的硬件中断号是28。
所以当中断号是28的时候,我们就需要进行串口中断处理了。
void uart0_handle_irq(int num) {
unsigned int dataCount = 0;
unsigned int status = 0;
switch(num){
case UART0_TX_IRQ:
dataCount = ((UFSTAT0 >> 8) & 0x3F);
printf("%d bytes data in Tx FIFO.\n\r", dataCount);
break;
case UART0_RX_IRQ:
//将收到的数据打印出来
dataCount = UFSTAT0 & (0x3F);
while(dataCount) {
uart0_putc(URXH0);
dataCount = UFSTAT0 & (0x3F);
}
printf("\n\r");
break;
case UART0_ERR_IRQ:
status = UERSTAT0;
if(status & 0x1) {
printf("Overrun Error is occured.\n\r");
}
if(status & 0x2) {
printf("Parity Error is occured.\n\r");
}
if(status & 0x4) {
printf("Frame Error is occured.\n\r");
}
if(status & 0x8) {
printf("Break is received.\n\r");
}
break;
default:
printf("UART0 Unknown is interrupted.\n\r");
break;
}
}
void irqExpHandler(void) {
//现在处于SVC模式
//我们先获取硬件中断号
unsigned int interruptNum = INTOFFSET;
int subInterruptNum = 0;
printf("\n\rIRQ Interrupt Number: %d\n\r", interruptNum);
//按键 按下后为低电平
unsigned int isKeyUp = 0;
int ledNum = -1;
switch(interruptNum){
case 0:
//EINT0中断 s2按键
isKeyUp = (GPFDAT & 0x1);
ledNum = LED1;
break;
case 2:
//EINT2 s3按键
isKeyUp = (GPFDAT & (0x1 << 2));
ledNum = LED2;
break;
case 5:
//EINT8_23 s4按键
isKeyUp = (GPGDAT & (0x1 << 3));
ledNum = LED4;
break;
case 28:
subInterruptNum = SUBSRCPND & 0x7;
if(SUBSRCPND & 0x1) {
//INT_RXD0
uart0_handle_irq(UART0_RX_IRQ);
}
if(SUBSRCPND & 0x2) {
//INT_RXD0
uart0_handle_irq(UART0_TX_IRQ);
}
if(SUBSRCPND & 0x4) {
//INT_RXD0
uart0_handle_irq(UART0_ERR_IRQ);
}
break;
default:
break;
}
if(ledNum > 0) {
if(isKeyUp) {
//熄灭LED1
led_off(ledNum);
printf("Key is Up.LED%d is turn off.\n\r", ledNum);
}else {
led_on(ledNum);
printf("Key is Down.LED%d is turn on.\n\r", ledNum);
}
}
//处理完毕,从源头开始清理中断标志
//注意是写1清零
if(interruptNum == 5) {
EINTPEND = (0x1 << 11);
}
SUBSRCPND = subInterruptNum;
SRCPND = (0x1 << interruptNum);
INTPND = (0x1 << interruptNum);
printf("IRQ Interrupt is Handled\n\r");
}
实验主函数
我们的实验主函数一直在死循环打印字符,别的什么也不做。
char gCh = 'A';
int main(void) {
leds_init();
keys_init_irq();
printf("%s\n\r", "IRQ Test.");
dump_norFlash(80);
while(1) {
printf("%c(0x%02x) ", gCh, gCh);
gCh++;
wait(888888);
}
return 0;
}
实验结果
只要我们往串口助手内写入的字符达到8个,就会产生IRQ中断,并将我们输入的内容打印出来。