#include "N1S16DSP.H" ////////////////////// // 串口访问参数设置 // ////////////////////// ////////////////////////////// // 串口信息的流向设计思想 // ////////////////////////////// // 1、临时发送和接收缓冲、实际发送和接收缓冲均为缓冲缓冲; // // 2、串口接收的信息,首先存放到临时接收缓冲*uiLowComRxd中,当接收的实际字节数uiComTempRecvBytePtr大于等于 // 2*cnComTmpRecvBufWordSize时,将*uiLowComRxd的数据转存到扩展RAM中的uiExtComRxd;然后根据转发到网络 // 的需要转移到低端RAM中的uTxdNet,即组织网络报文;当扩展RAM中没有数据时,也可以从uiLowComRxd中直接 // 组织网络报文,具体如下: // // 中断 当接收的字节数大于等于临时缓冲的大小时, 发送时 // COM ------> 临时接收缓冲*uiLowComRxd -----------------------------------------> 扩展RAM中的uiExtComRxd --------> 低端RAM的uTxdNet // 查询 | 每次转移cnComTmpRecvBufWordSize个字 | // | | // ------------------------------------扩展RAM中没有数据或数据不足时--------------------->>- // // 3、网络接收的信息,即串口将要发送的信息,首先存放到临时发送缓冲*uiLowComTxd中,多余的数据存放到扩展RAM // 中的uiExtComTxd,然后根据发送情况转移到临时发送缓冲*uiLowComTxd中,以便发送到串口;具体如下: // // 中断 发送时 // 网络 ------> 低端RAM的uRxdNet --> 扩展RAM中的uiExtComTxd --------> 临时发送缓冲*uiLowComTxd // 查询 | | // | | // -----------临时发送缓冲为空时----------->>- // UINT uiComTempRecvBytePtr[cnMaxComThisType]; // 串口临时接收字节指针(以字节为单位),单向缓冲,满时转入扩展RAM UINT uiComTempRecvByteUse[cnMaxComThisType]; // 串口临时接收使用字节指针(以字节为单位),单向缓冲,满时转入扩展RAM UINT uiComTempSendBytePtr[cnMaxComThisType]; // 串口临时发送字节指针(以字节为单位),单向缓冲,空时由扩展RAM转入 UINT uiComTempSendByteUse[cnMaxComThisType]; // 串口临时发送使用字节指针(以字节为单位),单向缓冲,空时由扩展RAM转入 UINT uiComRealRecvWordPtr[cnMaxComThisType]; // 串口实际接收字节指针(以字为单位),环形缓冲 UINT uiComRealRecvWordUse[cnMaxComThisType]; // 串口实际接收使用字节指针(以字为单位),环形缓冲 UINT uiComRealSendWordPtr[cnMaxComThisType]; // 串口实际发送字节指针(以字为单位),环形缓冲 UINT uiComRealSendWordUse[cnMaxComThisType]; // 串口实际发送使用字节指针(以字为单位),环形缓冲 // 网络数据的按帧接收,或帧数据流的识别: // ===================================== // 串口发向网络的条件具体为: // ⑴ 待发送的字节数满足一个以太网帧最大字节数时; // ⑵ 未满足以太网帧最大字节数,串口接收空闲时间超过10倍单字节发送时间(由波特率折算); UINT uiM10Sec10CharsTime[cnMaxComThisType]; // 按波特率计算,接收(发送)一个字节所需要的时间(以10ms为单位) UINT uiM10SecCountCharDelay[cnMaxComThisType]; // 该串口自接收完上一个字节到现在的时间间隔 UINT *uiLowComRxd[cnMaxComThisType]; // 串口临时接收缓冲区指针 UINT *uiLowComTxd[cnMaxComThisType]; // 串口临时发送缓冲区指针 ////////////////////////////////////////////////////////////////////////////////////// // Three types of information are stored in the internal registers used in the ACE: // control, status, and data. Mnemonic abbreviations for the registers are shown in // Table 1. Table 2 defines the address location of each register and whether it is // read only, write only, or read writable. // // Table 1. Internal Register Mnemonic Abbreviations // ================================================================================================================ // CONTROL MNEMONIC | STATUS MNEMONIC | DATA MNEMONIC // ------------------------- -------- | --------------------- -------- | ---------------------------- -------- // Line control register LCR | Line status register LSR | Receiver buffer register RBR // FIFO control register FCR | Modem status register MSR | Transmitter holding register THR // Modem control register MCR | | // Divisor latch LSB DLL | | // Divisor latch MSB DLM | | // Interrupt enable register IER | | // ----------------------------------------------------------------------------------------------------------------- // // Table 2. Register Selection // =========================== // DLAB A2 A1 A0 READ MODE WRITE MODE // ---- -- -- -- ------------------------ ---------------------------- // 0 0 0 0 Receiver buffer register Transmitter holding register // 0 0 0 1 Interrupt enable register // X 0 1 0 Interrupt identification register FIFO control register // X 0 1 1 Line control register // X 1 0 0 Modem control register // X 1 0 1 Line status register // X 1 1 0 Modem status register // X 1 1 1 Scratchpad register Scratchpad register // 1 0 0 0 LSB divisor latch // 1 0 0 1 MSB divisor latch // ------------------------------------------------------------------------ // X = irrelevant, 0 = low level, 1 = high level // The serial channel is accessed when either /CSA or /CSD is low. // DLAB is the divisor latch access bit and bit 7 in the LCR. // A2-A0 are device terminals. // // Individual bits within the registers are referred to by the register mnemonic // and the bit number in parentheses. For example, LCR7 refers to line control // register bit 7. The transmitter buffer register and receiver buffer register // are data registers that hold from five to eight bits of data. If less than eight // data bits are transmitted, data is right justified to the LSB. Bit 0 of a data // word is always the first serial data bit received and transmitted. The ACE data // registers are double buffered (TL16450 mode) or FIFO buffered (FIFO mode) so // that read and write operations can be performed when the ACE is performing the // parallel-to-serial or serial-to-parallel conversion. // // The scratch register is an 8-bit read/write register that has no affect on either // channel in the ACE. It is intended to be used by the programmer to hold data // temporarily. // // /RXRDY operation 选择 mode 1 // ================ // In mode 0, /RXRDY is asserted (low) when the receive FIFO is not empty; it is // released (high) when the FIFO is empty. In this way, the receiver FIFO is read // when /RXRDY is asserted (low). // In mode 1, /RXRDY is asserted (low) when the receive FIFO has filled to the // trigger level or a character time-out has occurred (four character times with // no transmission of characters); it is released (high) when the FIFO is empty. In // this mode, multiple received characters are read by the DMA device, reducing the // number of times it is interrupted. // /RXRDY and /TXRDY outputs from each of the four internal ACEs of the TL16C554 are // ANDed together internally. This combined signal is brought out externally to // /RXRDY and /TXRDY. Following the removal of the reset condition (RESET low), the // ACE remains in the idle mode until programmed. // A hardware reset of the ACE sets the THRE and TEMT status bits in the LSR. When // interrupts are subsequently enabled, an interrupt occurs due to THRE. A summary // of the effect of a reset on the ACE is given in Table 12. // // /TXRDY operation 选择 mode 1 // ================ // In mode 0, /TXRDY is asserted (low) when the transmit FIFO is empty; it is released // (high) when the FIFO contains at least one byte. In this way, the FIFO is written // with 16 bytes when /TXRDY is asserted (low). // In mode 1, /TXRDY is asserted (low) when the transmit FIFO is not full; in this mode, // the transmit FIFO is written with another UINT when /TXRDY is asserted (low). // // scratchpad register // =================== // The scratch register is an 8-bit read/write register that has no affect on either // channel in the ACE. It is intended to be used by the programmer to hold data // temporarily. //////////////////////////////////////////////////////////////////////////////////////// #define cnMaxBaudRate 691200 // 对应主振频率为11.0592MHz = 691200 * 16 //////////////////////////////////////////////////////////////////////////////////////// // // ============================= // TL16C554访问基地址:读/写100H // ============================= // // ================================== // 分选片选控制地址如下表:低电平有效 // ================================== // 端口地址 D0 D1 D2 D3 D4 D5 D6 D7 // -------- ---- ---- ---- ---- ---- ---- ---- ---- // INT0: 200H CSA1 CSB1 CSC1 CSD1 CSA3 CSB3 CSC3 CSD3 // INT1: 300H CSA5 CSB5 CSC5 CSD5 CSA7 CSB7 CSC7 CSD7 // INT2: 700H CSA2 CSB2 CSC2 CSD2 CSA4 CSB4 CSC4 CSD4 // Nmi: 900H CSA6 CSB6 CSC6 CSD6 CSA8 CSB8 CSC8 CSD8 // // 用通道号表示 // ------------ // INT0: 200H 1 2 3 4 9 10 11 12 // INT1: 300H 17 18 19 20 25 26 27 28 // INT2: 700H 5 6 7 8 13 14 15 16 // Nmi: 900H 21 22 23 24 29 39 31 32 // // 如要选择第 1路port900 = 0xff, port700 = 0xff, port300 = 0xff, port200 = 0xfe; // 如要选择第 5路port900 = 0xff, port700 = 0xfe, port300 = 0xff, port200 = 0xff; // 如要选择第 9路port900 = 0xff, port700 = 0xff, port300 = 0xff, port200 = 0xef; // 如要选择第13路port900 = 0xff, port700 = 0xef, port300 = 0xff, port200 = 0xff; // 如要选择第17路port900 = 0xff, port700 = 0xff, port300 = 0xfe, port200 = 0xff; // 如要选择第21路port900 = 0xfe, port700 = 0xff, port300 = 0xff, port200 = 0xff; // 如要选择第25路port900 = 0xff, port700 = 0xff, port300 = 0xef, port200 = 0xff; // 如要选择第29路port900 = 0xef, port700 = 0xff, port300 = 0xff, port200 = 0xff; // // ================ // 串口芯片复位地址 // ================ // 写400H;D0 = 1,复位第一片串口芯片,D0 = 0,使第一片串口芯片工作; // 写400H;D1 = 1,复位第二片串口芯片,D1 = 0,使第二片串口芯片工作; // 写400H;D2 = 1,复位第三片串口芯片,D2 = 0,使第三片串口芯片工作; // 写400H;D3 = 1,复位第四片串口芯片,D3 = 0,使第四片串口芯片工作; // 写400H;D4 = 1,复位第五片串口芯片,D4 = 0,使第五片串口芯片工作; // 写400H;D5 = 1,复位第六片串口芯片,D5 = 0,使第六片串口芯片工作; // 写400H;D6 = 1,复位第七片串口芯片,D6 = 0,使第七片串口芯片工作; // 写400H;D7 = 1,复位第八片串口芯片,D7 = 0,使第八片串口芯片工作; // // ========================== // 串口芯片中断标识位读取地址 // ========================== // INT0: 写500H,D1D0 = 00,同时读取600H,D0-D8分别对应INTA1、INTB1、INTC1、INTD1、INTA3、INTB3、INTC3、INTD3; // INT2: 写500H,D1D0 = 01,同时读取A00H,D0-D8分别对应INTA2、INTB2、INTC2、INTD2、INTA4、INTB4、INTC4、INTD4; // INT1: 写500H,D1D0 = 10,同时读取600H,D0-D8分别对应INTA5、INTB5、INTC5、INTD5、INTA7、INTB7、INTC7、INTD7; // Nmi: 写500H,D1D0 = 11,同时读取A00H,D0-D8分别对应INTA6、INTB6、INTC6、INTD6、INTA8、INTB8、INTC8、INTD8; // // 用通道号表示 // ------------ // INT0:写500H,D1D0 = 00,同时读取600H,D0-D8分别对应 1、 2、 3、 4、 9、10、11、12; // INT2:写500H,D1D0 = 01,同时读取A00H,D0-D8分别对应 5、 6、 7、 8、13、14、15、16; // INT1:写500H,D1D0 = 10,同时读取600H,D0-D8分别对应17、18、19、20、25、26、27、28; // Nmi: 写500H,D1D0 = 11,同时读取A00H,D0-D8分别对应21、22、23、24、29、30、31、32; // // ======== // 中断处理 // ======== // INT0:第一、三片串口芯片中断使用DSP的INT0, 1、 2、 3、 4、 9、10、11、12; // INT1:第五、七片串口芯片中断使用DSP的INT1,17、18、19、20、25、26、27、28; // INT2:第二、四片串口芯片中断使用DSP的INT2, 5、 6、 7、 8、13、14、15、16; // Nmi: 第六、八片串口芯片中断使用DSP的NMI, 21、22、23、24、29、30、31、32; // ///////////////////////////////////////////////////////////////////////////////////////// // TL16c554访问I/O地址 // =================== // 0,cnRBR_16c554,Receiver buffer register(READ) // 0,cnTHR_16c554,Transmitter holding register(WRITE) // 0,cnDLL_16c554,Divisor latch LSB(When LCR.7=1)(WRITE) // 1,cnDLM_16c554,Divisor latch MSB(When LCR.7=1)(WRITE) // 1,cnIER_16c554,Interrupt enable register(WRITE) // 2,cnIIR_16c554,Interrupt identification(READ) // 2,cnFCR_16c554,FIFO control register(WRITE) // 3,cnLCR_16c554,Line control register(WRITE) // 4,cnMCR_16c554,Modem control register(WRITE) // 5,cnLSR_16c554,Line status register(READ) // 6,cnMSR_16c554,Modem status register(READ) // 7,cnSCR_16c554,Scratchpad register(READ & WRITE) ioport UINT port100; // 0,cnRBR_16c554,Receiver buffer register(READ) // 0,cnTHR_16c554,Transmitter holding register(WRITE) // 0,cnDLL_16c554,Divisor latch LSB(When LCR.7=1)(WRITE) ioport UINT port101; // 1,cnDLM_16c554,Divisor latch MSB(When LCR.7=1)(WRITE) // 1,cnIER_16c554,Interrupt enable register(WRITE) ioport UINT port102; // 2,cnIIR_16c554,Interrupt identification(READ) // 2,cnFCR_16c554,FIFO control register(WRITE) ioport UINT port103; // 3,cnLCR_16c554,Line control register(WRITE) ioport UINT port104; // 4,cnMCR_16c554,Modem control register(WRITE) ioport UINT port105; // 5,cnLSR_16c554,Line status register(READ) ioport UINT port106; // 6,cnMSR_16c554,Modem status register(READ) ioport UINT port107; // 7,cnSCR_16c554,Scratchpad register(READ & WRITE) // TL16c554路选方法 // ================ // 端口地址 D0 D1 D2 D3 D4 D5 D6 D7 // -------- ---- ---- ---- ---- ---- ---- ---- ---- // INT0: 200H CSA1 CSB1 CSC1 CSD1 CSA3 CSB3 CSC3 CSD3 // INT1: 300H CSA5 CSB5 CSC5 CSD5 CSA7 CSB7 CSC7 CSD7 // INT2: 700H CSA2 CSB2 CSC2 CSD2 CSA4 CSB4 CSC4 CSD4 // Nmi: 900H CSA6 CSB6 CSC6 CSD6 CSA8 CSB8 CSC8 CSD8 // // 用通道号表示 // ------------ // INT0: 200H 1 2 3 4 9 10 11 12 // INT1: 300H 17 18 19 20 25 26 27 28 // INT2: 700H 5 6 7 8 13 14 15 16 // Nmi: 900H 21 22 23 24 29 39 31 32 // // 如要选择第 1路port900 = 0xff, port700 = 0xff, port300 = 0xff, port200 = 0xfe; // 如要选择第 5路port900 = 0xff, port700 = 0xfe, port300 = 0xff, port200 = 0xff; // 如要选择第 9路port900 = 0xff, port700 = 0xff, port300 = 0xff, port200 = 0xef; // 如要选择第13路port900 = 0xff, port700 = 0xef, port300 = 0xff, port200 = 0xff; // 如要选择第17路port900 = 0xff, port700 = 0xff, port300 = 0xfe, port200 = 0xff; // 如要选择第21路port900 = 0xfe, port700 = 0xff, port300 = 0xff, port200 = 0xff; // 如要选择第25路port900 = 0xff, port700 = 0xff, port300 = 0xef, port200 = 0xff; // 如要选择第29路port900 = 0xef, port700 = 0xff, port300 = 0xff, port200 = 0xff; ioport UINT port200; // 通道选择 ioport UINT port300; ioport UINT port700; ioport UINT port900; // 串口芯片中断标识位读取地址 // -------------------------- // INT0:写500H,D1D0 = 00,同时读取600H,D0-D8分别对应INTA1、INTB1、INTC1、INTD1、INTA3、INTB3、INTC3、INTD3; // INT2:写500H,D1D0 = 01,同时读取A00H,D0-D8分别对应INTA2、INTB2、INTC2、INTD2、INTA4、INTB4、INTC4、INTD4; // INT1:写500H,D1D0 = 10,同时读取600H,D0-D8分别对应INTA5、INTB5、INTC5、INTD5、INTA7、INTB7、INTC7、INTD7; // Nmi: 写500H,D1D0 = 11,同时读取A00H,D0-D8分别对应INTA6、INTB6、INTC6、INTD6、INTA8、INTB8、INTC8、INTD8; // // 用通道号表示 // ------------ // INT0:写500H,D1D0 = 00,同时读取600H,D0-D8分别对应 1、 2、 3、 4、 9、10、11、12; // INT2:写500H,D1D0 = 01,同时读取A00H,D0-D8分别对应 5、 6、 7、 8、13、14、15、16; // INT1:写500H,D1D0 = 10,同时读取600H,D0-D8分别对应17、18、19、20、25、26、27、28; // NMI: 写500H,D1D0 = 11,同时读取A00H,D0-D8分别对应21、22、23、24、29、30、31、32; ioport UINT port500; // 中断标识 ioport UINT port600; // 读出8位中断状态,从而判断是那路发生了中断 ioport UINT portA00; // 中断处理 // -------- // INT0:第一、三片串口芯片中断使用DSP的INT0, 1、 2、 3、 4、 9、10、11、12; // INT1:第五、七片串口芯片中断使用DSP的INT1,17、18、19、20、25、26、27、28; // INT2:第二、四片串口芯片中断使用DSP的INT2, 5、 6、 7、 8、13、14、15、16; // Nmi: 第六、八片串口芯片中断使用DSP的NMI, 21、22、23、24、29、30、31、32; BOOL blIntr0NeedToBeActive; // 主程序有必要启动一次INTR0;每次收到网络数据,均应置此标志,以便启动串口发送 BOOL blIntr1NeedToBeActive; // 主程序有必要启动一次INTR1;每次收到网络数据,均应置此标志,以便启动串口发送 BOOL blIntr2NeedToBeActive; // 主程序有必要启动一次INTR2;每次收到网络数据,均应置此标志,以便启动串口发送 BOOL blNmiNeedToBeActive; // 主程序有必要启动一次NMI;每次收到网络数据,均应置此标志,以便启动串口发送 // 用于INT0、INT1和INT2公用 UINT uiComNo0_1_2, uiComNoINT0_1_2, uiInterruptFlagINT0_1_2, uiMaskINT0_1_2; // 用于NMI UINT uiComNoNmi, uiComNoIntNmi, uiInterruptFlagNmi, uiMaskNmi; // 由于NMI可能中断INT0、INT1和INT2,因此需要保护现场 UINT uiInINT0_1_2; // 0x0000:未在INT0、INT1或INT2服务中;0xff00、0xff01和0xff02分别标识在INT0、INT1和INT2服务中 UINT uiPort900Val; // 不选中任何串口 UINT uiPort700Val; UINT uiPort300Val; UINT uiPort200Val; // 由INT0、INT1和INT2调用的串口信息接收函数 void vRecvComInforByInt0_1_2() // 因为INT0、INT1和INT2的中断级别相同,因此可以使用同一函数,而不会造成重入问题 { UINT uiTemp, *uipRxdPtr, uiBytesCount; ////////////// // 读取数据 // ////////////// if (uiInterruptFlagINT0_1_2 & uiMaskINT0_1_2) // 接收或发送中断有效 { uipRxdPtr = uiLowComRxd[uiComNoINT0_1_2] + (uiComTempRecvBytePtr[uiComNoINT0_1_2] >> 1); // 临时接收缓冲指针,以提高速度 // 检查线状态寄存器 0 D6 D5 D4 D3 D2 D1 D0 // --------------------------------------- // D0--接收数据准备好 // D1--数据被冲出错 // D2--校验出错 // D3--数据格式出错 // D4--检出间断 // D5--发送保持寄存器空 // D6--发送移位寄存器空 uiBytesCount = 0; uiTemp = port105; // 线路状态寄存器 while (uiTemp & 0x01) // 数据准备好否 D0 { if (uiBytesCount ++ >= 16) break; // FIFO最大16字节,防止硬件错误导致死机! // D1--数据被冲出错 // D2--校验出错 // D3--数据格式出错 if (uiTemp & 0x6) // D3.D2--校验出错 { uiTemp = port100; // 接收当前字符(必须读取,否则可能导致该字符一直留在FIFO中) uiTemp = "?"; } else // 中断接收缓存中, 用于放下一字节的位置 uiTemp = port100 & 0xff; // 接收当前字符 if (uiComTempRecvBytePtr[uiComNoINT0_1_2] & 0x01) // 第1、3、5、7、...字节在低字节位置 { *uipRxdPtr = (*uipRxdPtr) + uiTemp; uipRxdPtr ++; // 整字指针加1 } else // 第0、2、4、6、...字节在高字节位置 *uipRxdPtr = uiTemp << 8; // 若指针位于末尾, 则指针回零,并转移数据 uiComTempRecvBytePtr[uiComNoINT0_1_2] ++; if (uiComTempRecvBytePtr[uiComNoINT0_1_2] >= cnComTmpRecvBufByteSize) // 串口临时接收缓冲区大小 { // 将低端RAM缓冲中的数据写入实际串口接收缓冲; uiWriteDataExtComRxd(uiComNoINT0_1_2, uiLowComRxd[uiComNoINT0_1_2], cnComTmpRecvBufWordSize); // 准备发给网络的数据 uiComTempRecvBytePtr[uiComNoINT0_1_2] = 0; uiComTempRecvByteUse[uiComNoINT0_1_2] = 0; uipRxdPtr = uiLowComRxd[uiComNoINT0_1_2]; // 临时接收缓冲指针,以提高速度 } uiTemp = port105; // 线路状态寄存器 } // 数据准备好 /* // 中断有效,但数据未准备好;属于错误状态 if (uiBytesCount == 0) uiTemp = port100; // 防止错误?????????????????? */ } // 接收或发送中断有效 ////////////// // 发送数据 // 因为可能由软件启动中断发送数据,因此每次中断必须检查,而不管是否有硬件中断标志 ////////////// uiBytesCount = 0; do { if (uiBytesCount ++ >= 16) break; // FIFO最大16字节,防止硬件错误导致死机! // 是否有数据需要发送 if (uiComTempSendByteUse[uiComNoINT0_1_2] == uiComTempSendBytePtr[uiComNoINT0_1_2]) break; uiTemp = port105; // 线路状态寄存器 if (uiTemp & 0x60) // 移位寄存器或发送寄存器空否 D6 D5 { if (uiComTempSendByteUse[uiComNoINT0_1_2] & 0x01) // 第0、2、4、6、...字节在低字节位置 port100 = (*(uiLowComTxd[uiComNoINT0_1_2] + (uiComTempSendByteUse[uiComNoINT0_1_2] >> 1))) & 0xff; // 发送当前字节 else // 第1、3、5、7、...字节在高字节位置 port100 = (*(uiLowComTxd[uiComNoINT0_1_2] + (uiComTempSendByteUse[uiComNoINT0_1_2] >> 1))) >> 8; // 发送当前字节 // 若临时发送缓冲内容发送完毕, 则指针回零,并准备转移数据 uiComTempSendByteUse[uiComNoINT0_1_2] ++; if (uiComTempSendByteUse[uiComNoINT0_1_2] >= uiComTempSendBytePtr[uiComNoINT0_1_2]) // 临时缓冲信息发送完毕 { uiComTempSendBytePtr[uiComNoINT0_1_2] = 0; break; // 每次中断仅发送临时发送缓冲中的内容 } } // if ((uiTemp & 0x60)) // 移位寄存器或发送寄存器空否 D6 D5 else break; // 发送寄存器不空,无法继续发送 } while(TRUE); // 若还有数据等待发送,在上一级函数启动串口中断,以提高代码效率 if (uiComTempSendBytePtr[uiComNoINT0_1_2]) return; else // 串口临时发送缓冲内容发送完毕,检查扩展RAM中是否有数据 { // 从实际串口发送缓冲中读取数据到指定的低端RAM缓冲; if (uiComRealSendWordUse[uiComNoINT0_1_2] != uiComRealSendWordPtr[uiComNoINT0_1_2]) // 实际缓冲中数据有效 { // 从实际串口发送缓冲中读取数据到指定的低端RAM缓冲; uiComTempSendBytePtr[uiComNoINT0_1_2] = uiReadDataExtComTxd(uiComNoINT0_1_2, uiLowComTxd[uiComNoINT0_1_2], cnComTmpSendBufWordSize); // 需要发给串口的数据 uiComTempSendBytePtr[uiComNoINT0_1_2] = uiComTempSendBytePtr[uiComNoINT0_1_2] << 1; // 字 = 2字节 } uiComTempSendByteUse[uiComNoINT0_1_2] = 0; } } // 由NMI调用的串口信息接收函数 void vRecvComInforByNMI() { UINT uiTemp, *uipRxdPtr, uiBytesCount; ////////////// // 读取数据 // ////////////// if (uiInterruptFlagNmi & uiMaskNmi) // 接收或发送中断有效 { uipRxdPtr = uiLowComRxd[uiComNoIntNmi] + (uiComTempRecvBytePtr[uiComNoIntNmi] >> 1); // 临时接收缓冲指针,以提高速度 // 检查线状态寄存器 0 D6 D5 D4 D3 D2 D1 D0 // --------------------------------------- // D0--接收数据准备好 // D1--数据被冲出错 // D2--校验出错 // D3--数据格式出错 // D4--检出间断 // D5--发送保持寄存器空 // D6--发送移位寄存器空 uiBytesCount = 0; uiTemp = port105; // 线路状态寄存器 while (uiTemp & 0x01) // 数据准备好否 D0 { if (uiBytesCount ++ >= 16) break; // FIFO最大16字节,防止硬件错误导致死机! // D1--数据被冲出错 // D2--校验出错 // D3--数据格式出错 if (uiTemp & 0x6) // D3.D2--校验出错 { uiTemp = port100; // 接收当前字符(必须读取,否则可能导致该字符一直留在FIFO中) uiTemp = "?"; } else // 中断接收缓存中, 用于放下一字节的位置 uiTemp = port100 & 0xff; // 接收当前字符 if (uiComTempRecvBytePtr[uiComNoIntNmi] & 0x01) // 第1、3、5、7、...字节在低字节位置 { *uipRxdPtr = (*uipRxdPtr) + uiTemp; uipRxdPtr ++; // 整字指针加1 } else // 第0、2、4、6、...字节在高字节位置 *uipRxdPtr = uiTemp << 8; // 若指针位于末尾, 则指针回零,并转移数据 uiComTempRecvBytePtr[uiComNoIntNmi] ++; if (uiComTempRecvBytePtr[uiComNoIntNmi] >= cnComTmpRecvBufByteSize) // 串口临时接收缓冲区大小 { // 将低端RAM缓冲中的数据写入实际串口接收缓冲; uiWriteDataExtComRxd(uiComNoIntNmi, uiLowComRxd[uiComNoIntNmi], cnComTmpRecvBufWordSize); // 准备发给网络的数据 uiComTempRecvBytePtr[uiComNoIntNmi] = 0; uiComTempRecvByteUse[uiComNoIntNmi] = 0; uipRxdPtr = uiLowComRxd[uiComNoIntNmi]; // 临时接收缓冲指针,以提高速度 } uiTemp = port105; // 线路状态寄存器 } // 数据准备好 /* // 中断有效,但数据未准备好;属于错误状态 if (uiBytesCount == 0) uiTemp = port100; // 防止错误?????????????????? */ } // 接收或发送中断有效 ////////////// // 发送数据 // 因为可能由软件启动中断发送数据,因此每次中断必须检查,而不管是否有硬件中断标志 ////////////// uiBytesCount = 0; do { if (uiBytesCount ++ >= 16) break; // FIFO最大16字节,防止硬件错误导致死机! // 是否有数据需要发送 if (uiComTempSendByteUse[uiComNoIntNmi] == uiComTempSendBytePtr[uiComNoIntNmi]) break; uiTemp = port105; // 线路状态寄存器 if (uiTemp & 0x60) // 移位寄存器或发送寄存器空否 D6 D5 { if (uiComTempSendByteUse[uiComNoIntNmi] & 0x01) // 第0、2、4、6、...字节在低字节位置 port100 = (*(uiLowComTxd[uiComNoIntNmi] + (uiComTempSendByteUse[uiComNoIntNmi] >> 1))) & 0xff; // 发送当前字节 else // 第1、3、5、7、...字节在高字节位置 port100 = (*(uiLowComTxd[uiComNoIntNmi] + (uiComTempSendByteUse[uiComNoIntNmi] >> 1))) >> 8; // 发送当前字节 // 若临时发送缓冲内容发送完毕, 则指针回零,并准备转移数据 uiComTempSendByteUse[uiComNoIntNmi] ++; if (uiComTempSendByteUse[uiComNoIntNmi] >= uiComTempSendBytePtr[uiComNoIntNmi]) // 临时缓冲信息发送完毕 { uiComTempSendBytePtr[uiComNoIntNmi] = 0; break; // 每次中断仅发送临时发送缓冲中的内容 } } // if ((uiTemp & 0x60)) // 移位寄存器或发送寄存器空否 D6 D5 else break; // 发送寄存器不空,无法继续发送 } while(TRUE); // 若还有数据等待发送,在上一级函数启动串口中断,以提高代码效率 if (uiComTempSendBytePtr[uiComNoIntNmi]) return; else // 串口临时发送缓冲内容发送完毕,检查扩展RAM中是否有数据 { // 从实际串口发送缓冲中读取数据到指定的低端RAM缓冲; if (uiComRealSendWordUse[uiComNoIntNmi] != uiComRealSendWordPtr[uiComNoIntNmi]) // 实际缓冲中数据有效 { // 从实际串口发送缓冲中读取数据到指定的低端RAM缓冲; uiComTempSendBytePtr[uiComNoIntNmi] = uiReadDataExtComTxd(uiComNoIntNmi, uiLowComTxd[uiComNoIntNmi], cnComTmpSendBufWordSize); // 需要发给串口的数据 uiComTempSendBytePtr[uiComNoIntNmi] = uiComTempSendBytePtr[uiComNoIntNmi] << 1; // 字 = 2字节 } uiComTempSendByteUse[uiComNoIntNmi] = 0; } } // INT0:第一、三片串口芯片中断使用DSP的INT0, 1、 2、 3、 4、 9、10、11、12; interrupt void ivInt0Function() { UINT uiTotalComThisTime; // 用于防止串口数不同,错误的中断可能导致程序运行错误 ////////////////// // 中断函数主体 // ////////////////// blIntr0NeedToBeActive = FALSE; // 主程序有必要启动一次INTR0;每次收到网络数据,均应置此标志, // INT0:第一、三片串口芯片中断使用DSP的INT0, 1、 2、 3、 4、 9、10、11、12; // if (cnMaxComThisType < 1) return; // 本类型的最大串口数 // 装置最少为8路 uiInINT0_1_2 = 0xff00; // 在INT0服务中 // 串口芯片中断标识位读取地址: // INT0:写500H,D1D0 = 00,同时读取600H,D0-D8分别对应INTA1、INTB1、INTC1、INTD1、INTA3、INTB3、INTC3、INTD3; // INT2:写500H,D1D0 = 01,同时读取A00H,D0-D8分别对应INTA2、INTB2、INTC2、INTD2、INTA4、INTB4、INTC4、INTD4; // INT1:写500H,D1D0 = 10,同时读取600H,D0-D8分别对应INTA5、INTB5、INTC5、INTD5、INTA7、INTB7、INTC7、INTD7; // Nmi: 写500H,D1D0 = 11,同时读取A00H,D0-D8分别对应INTA6、INTB6、INTC6、INTD6、INTA8、INTB8、INTC8、INTD8; // // 用通道号表示 // INT0:写500H,D1D0 = 00,同时读取600H,D0-D8分别对应 1、 2、 3、 4、 9、10、11、12; // INT2:写500H,D1D0 = 01,同时读取A00H,D0-D8分别对应 5、 6、 7、 8、13、14、15、16; // INT1:写500H,D1D0 = 10,同时读取600H,D0-D8分别对应17、18、19、20、25、26、27、28; // Nmi: 写500H,D1D0 = 11,同时读取A00H,D0-D8分别对应21、22、23、24、29、30、31、32; // 具体查询是那路串口有中断发生 // ---------------------------- // INT0:写500H,D1D0 = 00,同时读取600H,D0-D8分别对应 1、 2、 3、 4、 9、10、11、12; port500 = 0x00; uiInterruptFlagINT0_1_2 = port600; // 读取8位串口中断位标志 // TL16c554路选方法 // ================ // 端口地址 D0 D1 D2 D3 D4 D5 D6 D7 // -------- ---- ---- ---- ---- ---- ---- ---- ---- // INT0: 200H CSA1 CSB1 CSC1 CSD1 CSA3 CSB3 CSC3 CSD3 // INT1: 300H CSA5 CSB5 CSC5 CSD5 CSA7 CSB7 CSC7 CSD7 // INT2: 700H CSA2 CSB2 CSC2 CSD2 CSA4 CSB4 CSC4 CSD4 // Nmi: 900H CSA6 CSB6 CSC6 CSD6 CSA8 CSB8 CSC8 CSD8 // // 用通道号表示 // INT0: 200H 1 2 3 4 9 10 11 12 // INT1: 300H 17 18 19 20 25 26 27 28 // INT2: 700H 5 6 7 8 13 14 15 16 // Nmi: 900H 21 22 23 24 29 30 31 32 // // INT0:1 2 3 4 9 10 11 12 // -------------------------------------------------- // 如要选择第 1路port900 = 0xff, port700 = 0xff, port300 = 0xff, port200 = 0xfe; // 如要选择第 9路port900 = 0xff, port700 = 0xff, port300 = 0xff, port200 = 0xef; // // INT1:17 18 19 20 25 26 27 28 // --------------------------------------------------- // 如要选择第17路port900 = 0xff, port700 = 0xff, port300 = 0xfe, port200 = 0xff; // 如要选择第25路port900 = 0xff, port700 = 0xff, port300 = 0xef, port200 = 0xff; // // INT2:5 6 7 8 13 14 15 16 // -------------------------------------------------- // 如要选择第 5路port900 = 0xff, port700 = 0xfe, port300 = 0xff, port200 = 0xff; // 如要选择第13路port900 = 0xff, port700 = 0xef, port300 = 0xff, port200 = 0xff; // // Nmi:21 22 23 24 29 30 31 32 // -------------------------------------------------- // 如要选择第21路port900 = 0xfe, port700 = 0xff, port300 = 0xff, port200 = 0xff; // 如要选择第29路port900 = 0xef, port700 = 0xff, port300 = 0xff, port200 = 0xff; uiPort900Val = 0xffff; uiPort700Val = 0xffff; uiPort300Val = 0xffff; port900 = uiPort900Val; port700 = uiPort700Val; port300 = uiPort300Val; // 以下只操作port200即可 // 用于防止串口数不同,错误的中断可能导致程序运行错误 // --------------------------------------------------- // INT0:第一、三片串口芯片中断使用DSP的INT0, 1、 2、 3、 4、 9、10、11、12; uiTotalComThisTime = cnMaxComThisType > 8 ? 8:4; // 本类型的最大串口数 for (uiComNo0_1_2 = 0; uiComNo0_1_2 < uiTotalComThisTime; uiComNo0_1_2 ++) { uiMaskINT0_1_2 = 1 << uiComNo0_1_2; // INT0:第一、三片串口芯片中断使用DSP的INT0, 1、 2、 3、 4、 9、10、11、12; if (uiComNo0_1_2 < 4) uiComNoINT0_1_2 = uiComNo0_1_2; // 1、 2、 3、 4 else uiComNoINT0_1_2 = uiComNo0_1_2 + 4; // 9、10、11、12 if (uiComNo0_1_2 >= cnMaxComThisType) break; // 本类型的最大串口数 uiPort200Val = ~uiMaskINT0_1_2; port200 = uiPort200Val; // TL16c554路选方法 // 由INT0、INT1和INT2调用的串口信息接收函数 vRecvComInforByInt0_1_2(); // 因为INT0、INT1和INT2的中断级别相同,因此可以使用同一函数,而不会造成重入问题 // 若还有数据等待发送,启动串口中断 if (uiComTempSendBytePtr[uiComNoINT0_1_2]) blIntr0NeedToBeActive = TRUE; // 主程序有必要启动一次INTR0;每次收到网络数据,均应置此标志,以便启动串口发送 } // for (uiComNo0_1_2 = 0; uiComNo0_1_2 < 8; uiComNo0_1_2 ++) uiPort200Val = 0xffff; // 放弃所有串口选择 port200 = uiPort200Val; // TL16c554路选方法 uiInINT0_1_2 = 0x0000; // 未在INT0、INT1或INT2服务中 } // INT1:第五、七片串口芯片中断使用DSP的INT1,17、18、19、20、25、26、27、28; interrupt void ivInt1Function() { UINT uiTotalComThisTime; // 用于防止串口数不同,错误的中断可能导致程序运行错误 ////////////////// // 中断函数主体 // ////////////////// blIntr1NeedToBeActive = FALSE; // 主程序有必要启动一次INTR1;每次收到网络数据,均应置此标志, // INT1:第五、七片串口芯片中断使用DSP的INT1,17、18、19、20、25、26、27、28; if (cnMaxComThisType < 17) return; // 本类型的最大串口数 uiInINT0_1_2 = 0xff01; // 在INT1服务中 // 串口芯片中断标识位读取地址: // INT0:写500H,D1D0 = 00,同时读取600H,D0-D8分别对应INTA1、INTB1、INTC1、INTD1、INTA3、INTB3、INTC3、INTD3; // INT2:写500H,D1D0 = 01,同时读取A00H,D0-D8分别对应INTA2、INTB2、INTC2、INTD2、INTA4、INTB4、INTC4、INTD4; // INT1:写500H,D1D0 = 10,同时读取600H,D0-D8分别对应INTA5、INTB5、INTC5、INTD5、INTA7、INTB7、INTC7、INTD7; // Nmi: 写500H,D1D0 = 11,同时读取A00H,D0-D8分别对应INTA6、INTB6、INTC6、INTD6、INTA8、INTB8、INTC8、INTD8; // // 用通道号表示 // INT0:写500H,D1D0 = 00,同时读取600H,D0-D8分别对应 1、 2、 3、 4、 9、10、11、12; // INT2:写500H,D1D0 = 01,同时读取A00H,D0-D8分别对应 5、 6、 7、 8、13、14、15、16; // INT1:写500H,D1D0 = 10,同时读取600H,D0-D8分别对应17、18、19、20、25、26、27、28; // Nmi: 写500H,D1D0 = 11,同时读取A00H,D0-D8分别对应21、22、23、24、29、30、31、32; // 具体查询是那路串口有中断发生 // ---------------------------- // INT1:写500H,D1D0 = 10,同时读取600H,D0-D8分别对应17、18、19、20、25、26、27、28; port500 = 0x10; uiInterruptFlagINT0_1_2 = port600; // 读取8位串口中断位标志 // TL16c554路选方法 // ================ // 端口地址 D0 D1 D2 D3 D4 D5 D6 D7 // -------- ---- ---- ---- ---- ---- ---- ---- ---- // INT0: 200H CSA1 CSB1 CSC1 CSD1 CSA3 CSB3 CSC3 CSD3 // INT1: 300H CSA5 CSB5 CSC5 CSD5 CSA7 CSB7 CSC7 CSD7 // INT2: 700H CSA2 CSB2 CSC2 CSD2 CSA4 CSB4 CSC4 CSD4 // Nmi: 900H CSA6 CSB6 CSC6 CSD6 CSA8 CSB8 CSC8 CSD8 // // 用通道号表示 // INT0: 200H 1 2 3 4 9 10 11 12 // INT1: 300H 17 18 19 20 25 26 27 28 // INT2: 700H 5 6 7 8 13 14 15 16 // Nmi: 900H 21 22 23 24 29 30 31 32 // // INT0:1 2 3 4 9 10 11 12 // -------------------------------------------------- // 如要选择第 1路port900 = 0xff, port700 = 0xff, port300 = 0xff, port200 = 0xfe; // 如要选择第 9路port900 = 0xff, port700 = 0xff, port300 = 0xff, port200 = 0xef; // // INT1:17 18 19 20 25 26 27 28 // --------------------------------------------------- // 如要选择第17路port900 = 0xff, port700 = 0xff, port300 = 0xfe, port200 = 0xff; // 如要选择第25路port900 = 0xff, port700 = 0xff, port300 = 0xef, port200 = 0xff; // // INT2:5 6 7 8 13 14 15 16 // -------------------------------------------------- // 如要选择第 5路port900 = 0xff, port700 = 0xfe, port300 = 0xff, port200 = 0xff; // 如要选择第13路port900 = 0xff, port700 = 0xef, port300 = 0xff, port200 = 0xff; // // Nmi:21 22 23 24 29 30 31 32 // -------------------------------------------------- // 如要选择第21路port900 = 0xfe, port700 = 0xff, port300 = 0xff, port200 = 0xff; // 如要选择第29路port900 = 0xef, port700 = 0xff, port300 = 0xff, port200 = 0xff; uiPort900Val = 0xffff; uiPort700Val = 0xffff; uiPort200Val = 0xffff; port900 = uiPort900Val; port700 = uiPort700Val; port200 = uiPort200Val; // 以下只操作port300即可 // 用于防止串口数不同,错误的中断可能导致程序运行错误 // --------------------------------------------------- // INT1:第五、七片串口芯片中断使用DSP的INT1,17、18、19、20、25、26、27、28; uiTotalComThisTime = cnMaxComThisType > 24 ? 8:4; // 本类型的最大串口数 for (uiComNo0_1_2 = 0; uiComNo0_1_2 < uiTotalComThisTime; uiComNo0_1_2 ++) { uiMaskINT0_1_2 = 1 << uiComNo0_1_2; // INT1:第五、七片串口芯片中断使用DSP的INT1,17、18、19、20、25、26、27、28; if (uiComNo0_1_2 < 4) uiComNoINT0_1_2 = uiComNo0_1_2 + 16; // 17、18、19、20 else uiComNoINT0_1_2 = uiComNo0_1_2 + 20; // 25、26、27、28 if (uiComNo0_1_2 >= cnMaxComThisType) break; // 本类型的最大串口数 uiPort300Val = ~uiMaskINT0_1_2; port300 = uiPort300Val; // TL16c554路选方法 // 由INT0、INT1和INT2调用的串口信息接收函数 vRecvComInforByInt0_1_2(); // 因为INT0、INT1和INT2的中断级别相同,因此可以使用同一函数,而不会造成重入问题 // 若还有数据等待发送,启动串口中断 if (uiComTempSendBytePtr[uiComNoINT0_1_2]) blIntr1NeedToBeActive = TRUE; // 主程序有必要启动一次INTR1;每次收到网络数据,均应置此标志,以便启动串口发送 } // for (uiComNo0_1_2 = 0; uiComNo0_1_2 < 8; uiComNo0_1_2 ++) uiPort300Val = 0xffff; // 放弃所有串口选择 port300 = uiPort300Val; // TL16c554路选方法 uiInINT0_1_2 = 0x0000; // 未在INT0、INT1或INT2服务中 } // INT2:第二、四片串口芯片中断使用DSP的INT2, 5、 6、 7、 8、13、14, 、15、16; interrupt void ivInt2Function() { UINT uiTotalComThisTime; // 用于防止串口数不同,错误的中断可能导致程序运行错误 ////////////////// // 中断函数主体 // ////////////////// blIntr2NeedToBeActive = FALSE; // 主程序有必要启动一次INTR2;每次收到网络数据,均应置此标志, // INT2:第二、四片串口芯片中断使用DSP的INT2, 5、 6、 7、 8、13、14、15、16; // if (cnMaxComThisType < 5) return; // 本类型的最大串口数 // 装置最少为8路 uiInINT0_1_2 = 0xff02; // 在INT2服务中 // 串口芯片中断标识位读取地址: // INT0:写500H,D1D0 = 00,同时读取600H,D0-D8分别对应INTA1、INTB1、INTC1、INTD1、INTA3、INTB3、INTC3、INTD3; // INT2:写500H,D1D0 = 01,同时读取A00H,D0-D8分别对应INTA2、INTB2、INTC2、INTD2、INTA4、INTB4、INTC4、INTD4; // INT1:写500H,D1D0 = 10,同时读取600H,D0-D8分别对应INTA5、INTB5、INTC5、INTD5、INTA7、INTB7、INTC7、INTD7; // Nmi: 写500H,D1D0 = 11,同时读取A00H,D0-D8分别对应INTA6、INTB6、INTC6、INTD6、INTA8、INTB8、INTC8、INTD8; // // 用通道号表示 // INT0:写500H,D1D0 = 00,同时读取600H,D0-D8分别对应 1、 2、 3、 4、 9、10、11、12; // INT2:写500H,D1D0 = 01,同时读取A00H,D0-D8分别对应 5、 6、 7、 8、13、14、15、16; // INT1:写500H,D1D0 = 10,同时读取600H,D0-D8分别对应17、18、19、20、25、26、27、28; // Nmi: 写500H,D1D0 = 11,同时读取A00H,D0