PC16550串口中断接收与异常处理程序
1.标准中断服务程序的处理流程(最佳实践)
void UART_ISR(void) {// 1. 读取IIR来判断中断源(注意:读IIR不会清除任何中断)unsigned char iir = inportb(UART_BASE + IIR_OFFSET);// 2. 循环处理,直到所有pending的中断都被处理完毕(IIR.0 = 1)while ((iir & 0x01) == 0) { // IIR.0 = 0 表示有中断待处理switch (iir & 0x0E) { // 屏蔽低位的0,检查中断ID位case 0x06: // 110: 最高优先级 - 线路状态错误handle_line_status_error();break;case 0x04: // 100: 接收数据可用handle_receive_data();break;case 0x0C: // 1100: 注意,IIR是3位,但超时中断用了高位// 实际上,在16550中,超时中断的IIR值通常也是 0x0C (1100)handle_receive_timeout();break;case 0x02: // 010: 发送保持寄存器空handle_transmit_empty();break;case 0x00: // 000: 最低优先级 - MODEM状态改变handle_modem_status_change();break;default:// 未知中断类型,可能是硬件问题break;}// 再次读取IIR,检查是否还有其他pending的中断iir = inportb(UART_BASE + IIR_OFFSET);}
}
2.线路状态错误中断处理
/*** 处理UART线路状态错误中断* 这是最高优先级的中断,必须首先处理*/
void handle_line_status_error(void) {// 读取线路状态寄存器(LSR) - 这个操作会清除线路状态中断标志unsigned char lsr = inportb(UART_BASE + LSR_OFFSET);// 检查各种错误标志位if (lsr & LSR_OE) { // 位1: 溢错误handle_overrun_error();}if (lsr & LSR_PE) { // 位2: 奇偶校验错误handle_parity_error();}if (lsr & LSR_FE) { // 位3: 帧错误handle_framing_error();}if (lsr & LSR_BI) { // 位4: 中止中断handle_break_interrupt();}// 注意:位0 (DR) 是数据就绪标志,不是错误,不需要在这里处理// 位5 (THRE) 和 位6 (TEMT) 是发送状态,也不是错误
}
3.具体错误处理函数实现
/*** 处理溢错误* 原因:CPU没有及时读取接收缓冲器,新数据覆盖了旧数据*/
void handle_overrun_error(void) {// 记录错误日志uart_log_error("UART: Overrun Error - Data lost due to slow reading");// 溢错误发生时,最新的数据可能已经丢失// 建议清空接收FIFO,重新开始outportb(UART_BASE + FCR_OFFSET, 0x07); // 设置FCR: 启用FIFO,清空RX FIFO,清空TX FIFO// 在严重情况下,可能需要重新初始化UARTif (++overrun_error_count > MAX_OVERRUN_ERRORS) {uart_log_error("UART: Too many overrun errors, reinitializing");initialize_uart();overrun_error_count = 0;}
}/*** 处理奇偶校验错误* 原因:数据传输过程中受到干扰,奇偶校验不匹配*/
void handle_parity_error(void) {// 记录错误日志uart_log_error("UART: Parity Error - Data corruption detected");// 对于奇偶校验错误,通常只是记录,不采取激进措施// 因为可能是暂时的线路干扰// 如果使用流量控制,可以临时暂停数据传输if (uart_flow_control_enabled) {// 发送XOFF字符,请求对方暂停发送outportb(UART_BASE + THR_OFFSET, XOFF_CHAR);}parity_error_count++;
}/*** 处理帧错误* 原因:缺少有效的停止位,通常表示波特率不匹配或线路断开*/
void handle_framing_error(void) {// 记录错误日志uart_log_error("UART: Framing Error - Invalid stop bit or baud rate mismatch");// 帧错误通常比较严重,可能表示配置问题// 尝试从接收缓冲器读取一个字节(尽管有错误)// 这样可以清除错误状态,但数据不可靠unsigned char bad_data = inportb(UART_BASE + RBR_OFFSET);// 记录错误数据(用于调试)uart_log_debug("UART: Framing error byte: 0x%02X", bad_data);framing_error_count++;// 如果帧错误持续发生,可能需要检查波特率设置if (framing_error_count > MAX_FRAMING_ERRORS) {uart_log_error("UART: Excessive framing errors, check baud rate configuration");// 可以在这里触发重新配置流程}
}
/*** 处理中止中断* 原因:接收线路上检测到长时间的逻辑0(Break信号)*/
void handle_break_interrupt(void) {// 记录事件uart_log_info("UART: Break Signal detected");// Break信号通常用于通信协议的重置或特殊命令// 清空接收FIFO,因为Break期间接收的数据无效outportb(UART_BASE + FCR_OFFSET, 0x06); // 清空RX FIFO,不清TX FIFO// 通知上层应用Break信号发生if (uart_break_callback != NULL) {uart_break_callback();}break_detected_count++;
}