先说一下环境: lpc2220,模板是zlg网站上的最新版本。
概述: 我自己写了一个串口驱动,现在UART0自收自发,UART1自收自发都正常,UART0,UART1“接力”的时候会出现问题。 所谓的接力是指同时启用Uart0,Uart1,Uart0将自己收到的数据通过Uart1发送出去,同时,Uart1将自己收到的数据通过Uart0发送出去。
现象: 在我调试的时候发现,两个串口会正常工作一段时间,然后R14不知道什么样的原因被莫名其妙的修改,在下文所述的UART1_EnableTX(),以及于此类似的UART0_EnableTX(),函数返回时R14存储的值指向自身函数的入口,出现死循环的情况。
问题: 不知道各位有没有遇到过类似的情况?如果有,是什么样的原因造成的? 另外,有一个概念我一直没弄明白,假设当前程序正在Uart1的中断服务程序(低优先)中,然后这个时候产生了Uart0中断(高优先),程序会跳转到Uart0的中断服务程序中么?
供参考的资料: void UART1_DisableTX() { U1IER = U1IER & (~0x02); }
void UART1_EnableTX() { U1IER = U1IER | 0x02; }
UART1_EnableTX的汇编代码如下: 80005a48 [0xe59f0114] ldr r0,0x80005b64 ; = #0xe000c000 80005a4c [0xe5d00004] ldrb r0,[r0,#4] 80005a50 [0xe3800002] orr r0,r0,#2 80005a54 [0xe59f1108] ldr r1,0x80005b64 ; = #0xe000c000 80005a58 [0xe5c10004] strb r0,[r1,#4] 80005a5c [0xe1a0f00e] mov pc,r14 <== 此处R14=0x80005a48,为函数的入口
以下为串口驱动的代码: 其中队列部分参考了zlg的队列中间件,我的改动主要使其适合于前后台系统。
#define UART1_TXD_SEL (1 << 16) //P0.8 #define UART1_RXD_SEL (1 << 18) //P0.9 void UART1_InitTxdRxd(void) { PINSEL0 |= UART1_TXD_SEL | UART1_RXD_SEL;}
#define UART1_MODEMSEL (1 << 20) | (1 << 22) | (1 << 24) | (1 << 26) | (1 << 28) | (1 << 30) void UART1_InitModem(void) { PINSEL0 |= UART1_MODEMSEL; }
volatile uint8 acUart1RxBuff[UART1_RX_QUEUE_SIZE]; volatile uint8 acUart1TxBuff[UART1_TX_QUEUE_SIZE]; volatile struct _tag_Queue stUart1RxQueue; volatile struct _tag_Queue stUart1TxQueue;
void /* __irq*/ IRQ_UART1(void) { uint8 nState; nState = (U1IIR & 0x0E) >> 1; switch(nState) { case 0x06://字符超时 case 0x02://接收 { QueuePushOneChar(&stUart1RxQueue, U1RBR); break; } case 0x01://发送 { if(QueuePullOneChar(&stUart1TxQueue, &nState) == 1) U1THR = nState; break; } case 0x00://MODEM中断 { nState = U1MSR; break; } case 0x03://接受线状态 { nState = U0LSR; nState = U0RBR; break; } } nEnterTimes1--; VICVectAddr = 0x00; // 中断处理结束 }
void UART1_Init(void) { UART1_InitTxdRxd(); QueueInit(acUart1RxBuff, UART1_RX_QUEUE_SIZE, &stUart1RxQueue); QueueInit(acUart1TxBuff, UART1_TX_QUEUE_SIZE, &stUart1TxQueue);
VICIntEnClr = 1 << 7; //禁能中断 }
uint32 UART1_SetMode(const UARTMODE *pMode) { extern void IRQ_Def(void); extern void UART1_Handler(void); uint32 i; uint8 nTemp; if(UartEx_IsModeValid(pMode) == 0) return 0; U1LCR = 0x80; // DLAB位置1
i = (Fpclk>>4) / pMode->nBaudRate; // 设置串口波特率 U1DLM = i >> 8; U1DLL = i & 0xFF;
nTemp = 0; nTemp |= (pMode->nDataLen - 5); //数据长度 nTemp |= (pMode->nStopBitLen - 1) << 2; //停止位 if(pMode->nParity != 0) //是否校验 nTemp |= (pMode->nParity - 1) << 4; //校验方式 U1LCR = nTemp;
if(pMode->nFullSignal != 0) UART1_InitModem();
U1FCR = 0x01; // 使能FIFO,并设置触发点为1字节 U1IER = 0x03; // 接收中断,发送中断
VICIntEnClr = 1 << 7; //禁能中断
VICIntSelect &= (~(1 << 7)); //设置UART1中断分配为IRQ中断 VICVectCntl2 = 0x20 | 7; //UART1中断 VICVectAddr2 = (int)UART1_Handler; //设置UART1中断服务程序地址
VICDefVectAddr = (int)IRQ_Def;
VICIntEnable = 1 << 7; //使能中断 return 1; } void UART1_DisableRX() { U1IER = U1IER & (~0x01); } void UART1_EnableRX() { U1IER = U1IER | 0x01; } void UART1_DisableTX() { U1IER = U1IER & (~0x02); } void UART1_EnableTX() { U1IER = U1IER | 0x02; }
uint8 UART1_Send(const uint8 *pnData, uint8 nDataLen) { volatile struct _tag_Queue *pstQueue = &stUart1TxQueue; uint8 nLen; uint8 temp; UART1_DisableTX(); nLen = QueuePushIn(pstQueue, pnData, nDataLen); if ((U1LSR & 0x00000020) != 0) { /* UART0发送保持寄存器空 */ QueuePullOut(pstQueue, 1, &temp); /* 发送最初入队的数据 */ U1THR = temp; } UART1_EnableTX(); return nLen; }
uint8 UART1_Receive(uint8 *pnData, uint8 nDataLen) { volatile struct _tag_Queue *pstQueue = &stUart1RxQueue; uint8 nLen = 0; if(QueueGetSize(pstQueue) >= nDataLen) { UART1_DisableRX(); QueuePullOut(pstQueue, nDataLen, pnData); UART1_EnableRX(); nLen = nDataLen; } return nLen; } |