#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
文章评论(0条评论)
登录后参与讨论