访问电脑版页面

导航:老古开发网手机版其他

TMS320VC5416与TLC16C554的接口函数(转帖)

导读:
关键字:

#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,

来源:   作者:  2006/9/25 16:50:53
栏目: [ ]

相关阅读

安森美推出新的高功率图腾柱PFC控制器,满足具挑战的能效标准

动态功耗低至60μA/MHz!助力设备超长续航,首选国民技术低功耗MCU!