線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:6058
推到 Plurk!
推到 Facebook!

rs232的相關資料

答題得分者是:axsoft
kimi
一般會員


發表:37
回覆:76
積分:22
註冊:2003-07-17

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-08-26 09:37:39 IP:140.134.xxx.xxx 未訂閱
大大可不可以提供我,有關rs232的相關資料.因為我想更了解rs232的各種狀況,拜託大大的幫忙
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#2 引用回覆 回覆 發表時間:2003-08-26 12:07:27 IP:61.218.xxx.xxx 未訂閱
kimi您好:    參考這篇文章看看 Interfacing the Serial / RS232 Port  http://www.beyondlogic.org/serial/serial.htm    
/*開心的事情別隱藏在心裡,分享給別人知道會更快樂的*/
/*得到新知識別隱藏在心裡,分享給別人了解會更清楚的*/
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#3 引用回覆 回覆 發表時間:2003-08-26 12:09:28 IP:61.218.xxx.xxx 未訂閱
資料來源:中山大學 West BBS-西子灣站 http://bbs3.nsysu.edu.tw/txtVersion/boards/math-asm/M.867852899.A.html

PC的通訊方面知識。

〔傳送資料〕 PC通訊時需要一個PC通訊界面卡﹐也就是一般所謂的RS232 卡﹐卡的上面有一顆8250 UART的晶片﹐PC上的一些通訊細節﹐ 就全交由8250 UART處理。程式設計者只要等UART放置輸出資料 的暫存器空了﹐這時CPU將資料寫入UART的資料輸出暫存器內就可 以。 如果用ISR的方式來設計程式﹐透過ISR程式的幫忙﹐CPU只 需將資料輸出到BUFFER中即可。當UART的輸出暫存器空了﹐便會 引發中斷產生﹐而由ISR實際負責將資料送到UART的輸出暫存器。 這樣會使CPU減少不少工作負擔。 〔通訊埠位址〕 PC的通訊資料是經由通訊埠(COM1、COM2)進出的。因此處理通 訊程式時﹐就需知道這些通訊埠的I/O埠位在那裡?要知道通訊埠的 I/O埠在那裡可以由記憶體0X400的位址上取得COM1的I/O埠位址 ﹐由0X402的位址取得COM2的I/O埠位址。這些位址都是在開機時 由BIOS所設定的。 〔資料格式〕 非同步串列式資料傳輸﹐就表示在資料傳輸當中﹐傳送方與接 收方作業時間上並不一致﹐在這種情形下﹐當傳送方傳出資料後﹐ 接收方在資料傳輸過程中並沒有規律的情形時﹐是要如何知道資料 何時會傳到。因此在傳送資料過程中﹐為了能有傳送字元與字元的 間隔﹐就需要在一個字元傳送時﹐加上起始位元及結束位元﹐來組 成字元傳送。 一個ASCII字元是1Byte長﹐在非同步通訊資料傳輸過程﹐每 個字的傳送都是以比一個Byte多兩個bit﹐也就是十個bit的格式 傳送。而ASCII用到的只需七個bit﹐多出來的一個bit就用為偵 錯用。 〔BIOS通訊功能〕 PC BIOS提供了四個Function Call給程式設計者使用﹐而 這四個Function Call是透過INT 14H來執行的。 AH 功能 00H 設定通訊資料傳輸協定 01H 對通訊埠寫入一個字元 02H 從通訊埠讀取一個字元 03H 查詢通訊埠狀態 〔UART的結構〕 8250 UART本身擁有10個可程式化的暫存器﹐每一個暫存器 都是一個Byte長﹐CPU將不同的UART視為I/O埠﹐假如想對UART 作存取動作﹐可以透過對UART的I/O埠讀寫資料。 每一個I/O埠位對UART而言﹐都是它的起始位址。UART內的 暫存器I/O埠位正是依此起始位址排列下去。UART內的10個暫存 器﹐由於有幾個暫存器共用同樣的I/O埠位﹐所以UART的10個暫 存器﹐可以利用7個I/O埠位址對它的暫存器作資料存取。以COM1 的UART基本位址0x03F8來算這10個暫存器的實際位址。 位址 OFFSET 暫存器名稱 0X03F8 0 THR & RDR BRDL 0X03F9 1 IER BRDH 0X03FA 2 IIR 0X03FB 3 LCR 0X03FC 4 MCR 0X03FD 5 LSR 0X03FE 6 MSR 當LCR的Bit 7=0時﹐0x03F8的位址為THR及RDR共用 0X03F9的位址為IER 當LCR的Bit 7=1時﹐0x03F8的位址為 BRDL 0X03F9的位址為 BRDH THR(Transmitter Holding Register) THR用來保留即將被送出的一個位元組資料。當LSR Bit5=1 時﹐表示THR目前已經空了﹐可以在這時後將資料送入THR。 RDR(Receiver Data Register) RDR用來放置剛由通訊線上接收的一個位元組資料。當LSR Bit0=1時﹐表示RDR內已經有資料進來﹐這時可以從RDR讀取資 料。 BRD(Baud Rate Divisor﹐Low byte) BRD鮑率除法器是用來設定資料的傳輸率(bps)﹐可以分為 低位元組的BRDL及高位元組的BRDH。此位址於LCR的Bit7=1時 ﹐才是BRDL暫存器使用﹐而下一個暫存器的位址才是BRDH使用 的。 Bps BRDH BRDL 19200 00H 06H 9600 00H 0CH 4800 00H 18H 2400 00H 30H 1200 00H 60H 300 01H 80H IER(Interrupt Enable Register) IER用來設定UART將可以在何種情形下產生中斷。而於中 斷產生後﹐在設計的ISR程式必須有一個相對應的處理動作。 位元 中斷狀況 處理動作 0 資料已接收 讀取RDR資料 1 THR已經空了 將資料寫入THR 2 LSR有變動 讀取LSR 3 MSR有變動 讀取MSR IIR(Interrupt Identification Register) IIR是用在有中斷產生時﹐我們於中斷服務常式中﹐藉由讀 取IIR的Bit 1及Bit 2﹐兩個位元的值﹐得知是何種中斷發生。 UART允許四種情行下產生中斷﹐而且又有優先順序性。 優先順序 Bit 2 Bit 1 中斷原因 0 1 1 LSR有狀況 1 1 0 資料接收到 2 0 1 THR空了 3 0 0 MSR有變動 LCR(Line Control Register) LCR的Bit 0至Bit 5﹐存放資料格式的設定值。而Bit 6 為1時﹐將產生Break﹐為0時恢復原狀。至於Bit 7為0﹐表 示目前用的是THR/RDR及IER暫存器﹐反之則是BRDL及BRDH暫 存器。 MCR(Modem Control Register) MCR控制兩個RS232輸出'狀態:DTR、RTS。 位元 內容 0 可設定UART的DTR輸出 1 可設定UART的RTS輸出 2 使用者可設定的輸出 3 使用者可設定的輸出﹐設為1時才允許8250有中斷功能 4 UART迴路 其它三個Bit則保持0。 LSR(Line Status Register) LSR可以讓我們偵測一般通訊線的問題。而當IER的Bit 2 為1時﹐LSR的Bit 1到Bit 4所代表的錯誤情形會促使中斷產 生。 位元 內容 處理 0 收到的位元組已組合好﹐ 讀入另一資料時設為0 而且放入RDR 1 Overrun:代表接收器內的位 讀取LSR後設為0 元組被新到的位元組蓋掉 2 Parity Error:收到的位元組 讀取LSR後設為0 Parity與ICR內的Parity 不同 3 Framing Error:收到的位元 讀取LSR後設為0 組於組合後發現不正確的結 束位元 4 Break產生 讀取LSR後設為0 MSR(Modem Status Register) MSR的Bit 0到Bit 3對應到RS232接腳狀態的變化﹐只要 其中一個Bit為1﹐表示上次狀態已經有變化﹐而在我們讀取這 暫存器後﹐Bit 0到Bit 3都會清為0。MSR的Bit 4至Bit 7則 指示RS232的實際狀況。 位元 訊號 內容 4 CTS(Clear To Send) Modem已經準備從電腦接收字元 5 DSR(Data Set Ready) Modem電源已開﹐準備作業 6 RI(Ring Indicator) 電話在響﹐當電話響時﹐RI維 持在HIGH狀態﹐因此電腦可以 偵測到。 7 DCD(Data Carrier Detect) Modem與另一Modem連通了 〔資料傳送〕 UART在資料傳送階段﹐主要是將資料由並列轉換為串列。而其 傳輸速率可以由軟體程式設定。當資料由PC的DATA BUS接收到﹐ 就放在THR﹐然後再移送到TSR(Transmiffer Shift Register)﹐而 於此處加上起使位元、偵錯位元及結束位元﹐最後將資料一個位元 一個位元送出﹐經由RS232的第2支腳﹐送至Modem。而TSR是UART 的內部使用暫存器﹐程式設計師無法自行控制的。 〔資料接收〕 UART在資料接收階段﹐正好相反﹐即是將資料由串列轉為並列。其 過程是UART不斷監視RS232的第3支腳﹐等待由Modem送來的起始 位元﹐當UART接收到起始位元時﹐便將第一個位元一個位元一個位 元的放入RSR(Receiver Shift Register)中﹐並且檢查諸如Overrun Error、Parity Error、Framing Error等錯誤狀況。若有錯誤發生 ﹐UART會通知終端機作應變措施。最後將資料放入RDR﹐再送入PC 的DATA BUS中﹐完成資料的接收過程。RSR就如同TSR一樣﹐是僅 供UART內部使用﹐同樣不允許程式設計者自行控制的。 〔RS232〕 傳送資料時﹐對於RS232C來說﹐表示將資料由電腦(DTE)送到 數據機(DCE)。過程是將資料由電腦主機的RS232C的第2接腳送出 ﹐通過纜線﹐進入數據機的第2支接腳。而接收資料的情形﹐則是 資料由數據機的第3接腳送出﹐再進入電腦的RS232C第3支接腳。 所以對於RS232C的接腳訊號就必須了解。 DTR(Data Terminal Ready) DTR﹐第20支接腳﹐是RS232C的一個控制訊號﹐主要用來 通知MODEM﹐說PC電源已經打開﹐而且準備好要通訊了。DTR訊 號對於MODEM是一個很重要的訊號﹐沒有這個訊好MODEM就不會 作業。 CTS(Clear To Send) CTS﹐第5支腳﹐是RS232C的一個控制訊號。這個訊號是由 MODEM送到PC﹐代表目前PC可以傳送資料給MODEM了。 RTS(Request To Send) RTS﹐第4接腳﹐是RS232C的一個控制訊號。這個訊號是由 PC發出給MODEM的﹐它要求MODEM開始傳送資料到PC來﹐一般 都是使用在半雙工的MODEM。 DCD(Data Carrier Detect) DCD﹐第8接腳﹐也是一個控制訊號。常常是MODEM送到PC 的第二個訊號。一般電話號碼打完﹐而且收到對方的回音之後﹐ 這兩個MODEM之間就建立了載波(CARRIER)﹐MODEM便將DCD設為 ON﹐這樣雙方就已經構成所謂的連線。 〔RS232 HANDSHAKE〕 PC與MODEM之間是利用RS232C來連通﹐而它們之間存在著一 個協定﹐用來管制彼此之間的資料流量。這個協定就叫做「交握」 協定(Handshake)。它會利用到DTR、DSR、DCD、CTS這四個控制訊 號。 〔AT指令組〕 一般市面上所見到的數據機都是所謂的「智慧型數據機」 (Intelligent Modem)。這種數據機可以接受PC下達的指令﹐並加 以分析執行﹐只要下達的指令符合所謂的「AT指令組」的要求。這 套指令是由Hays Microcomputer公司所發展出來的。為何叫它為「AT 指令組」呢?因為下達指令給MODEM時﹐所有命令的前面都須加上"AT" 兩個字元。指令長度不得超過40個字。 〔Response〕 當PC對MODEM下達指令時﹐MODEM會對指令加以分析﹐假使指 令語法正確無誤便執行指令。執行完後﹐MODEM會傳給PC一組字串 ﹐主要是告訴PC執行的結果。實際上MODEM提供兩種型式的Response ﹐一種是直接傳回代碼﹐一種是傳回字串。如"OK"的代碼為0﹐"ERROR" 的代碼為4。但是由MODEM傳回PC的資料如何判別是遠端電腦傳回 的﹐還是MODEM傳回的呢?所以Response的格式就必須加以規定。 如果說傳回的是字串﹐則格式應為"\r\n OK \r\n"與"\r\n ERROR \r\n"﹐如果傳回的是代碼的話格式則為"\r 0 \r"與"\r 4 \r" 。另外還有一點就是在撥完電話之後﹐可能收到的還有其他幾個代 碼跟字串。 代碼 字串 意義 0 OK "非撥號"指令執行成功 1 Connect 接通了 2 Ring 有電話進來 3 No Carrier 兩部MODEM間的載波沒有建立成功 4 Error 送來的指令﹐語法上有錯誤 ============================================================================= 這學期的期末作業寫的很不滿意,這些資料post上來希望對 有興趣寫PC通訊程式的同學或學弟妹能有點幫助! -- An expert is a man who has made all mistakes which can be made in a very narrow field! --Niels Bohr-- E-mail:b8424033@student.nsysu.edu.tw
/*開心的事情別隱藏在心裡,分享給別人知道會更快樂的*/
/*得到新知識別隱藏在心裡,分享給別人了解會更清楚的*/
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#4 引用回覆 回覆 發表時間:2003-08-26 12:14:53 IP:61.218.xxx.xxx 未訂閱
--------------------------------------------------------- PROGRAMMING THE 8250 UART or, "how to do some fun things with the serial port" by Jered Wierzbicki
資料來源:http://www.whisqu.se/per/docs/general25.htm
 Warning: You'll stay a lot more sane than I am for a lot longer if you
 have two PCs and a null modem cable so that you can put some of this
 material into application. If you don't, then this is going to be a very,
 very bland piece of reading for you, because it's strictly a technical
 specification on the 8250 UART.    The UART (Universal Asynchronous Receiver/Transmitter) chip is responsible
for just what its name implies; transfering data, to and from the serial
port. The 8250 is quite old, and has been almost entirely replaced (the
8250 UART was shipped WITH the original IBM PC--and I mean the original.)
Its first replacement was the 16540 UART, which had the same general
architecture, but was somewhat faster and supported higher baud rates for
data transfer. The 16540 was replaced by the 16550, a UART which featured a
16-bit wide receive buffer for characters and a built-in FIFO buffer. A
close cousin to the 16550 is the 16560, a chip which sports a 32-bit wide
receive buffer.    Nevertheless, modern serial controllers are backward compatible, so what
you learn about the 8250 can still be applied on today's machines. With
that bit of background covered, we can begin studying the 8250.    Where to start? For software engineers, a register listing is the most
direct and intimate way to get to know a piece of hardware. I've provided
you with one for the 8250 below.     If you haven't worked with hardware much, you're probably not used to
 register listings. Register listings give the addresses of registers that
 are used to program a chip and list the manner in which the register
 affects the behavior of the chip. You can use this information to program
 the chip to perform tasks.    [note: I didn't piece this together entirely from memory. A lot of the
details came from http://www.byterunner.com/16550.html.]                               8250 REGISTER LISTING
 To write to an 8250 register, you write to the base address of the chip
 plus an offset. The base address is 2e8h for COM1 and 3e8h for COM2.
 Register 0:     RHR (Receive Holding Register; Receive Buffer
                 Register in some literature).  Doubles as the THR
                 (Transmitter Holding Register).  Is also the LSB
                 of the DLR (Divisor Latch Register) occasionally;
                 don't worry about that yet, but remember it.     Purpose:        This register is where you both read and write data
                 for the serial port.     Bits:           Bits 0-4 contain data bits 0-4.
                 Bits 5-7 may or may not be defined, depending upon
                 whether the UART has been instructed to use 5, 6, 7,
                 or 8 bit words.
 Register 1:     IER (Interrupt Enable Register).  Also the MSB of
                 the DLR (Divisor Latch Register) occasionally; don't
                 worry about that yet, but remember it.     Purpose:        Tells the UART to generate an interrupt when different
                 things occur.     Bits:           Bit 0: RHRI (Receive Holding Register Interrupt; RxRDY
                 in some literature).  The UART will generate an
                 interrupt when a character is received in the RHR if
                 this bit is set.
                 Bit 1: THRI (Transmit Holding Register Interrupt; TxRDY).
                 If set, the UART generates an interrupt when a
                 character is moved from the THR to the Internal Shift
                 Register.
                 Bit 2: RLSI (Receive Line Status Interrupt; ERROR).
                 If set, the UART interrupts when a parity or overrun
                 error occurs, or when a break condition is encountered.
                 Bit 3: MSI (Modem Status Interrupt; DELTA).  If set,
                 the UART interrupts whenever an RS-232 line changes
                 state.
                 Bits 4-7: Unused     Register 2:     ISR (Interrupt Status Register; also refered to as
                 the Interrupt Identification Register).     Purpose:        Tells what event caused a UART interrupt.     Bits:           Bit 0: Flags if an interrupt has occurred
                 Bits 1-2: Indicates what caused interrupt:
                           00 -> RS-232 line change
                           01 -> THR emptied
                           10 -> RHR contains character
                           11 -> Error condition
                 Bits 3-7: Unused     Register 3:     LCR (Line Control Register).     Purpose:        Configures the UART.  Also  flags the use of
                 registers 0 and 1 for the DLR (Divisor Latch
                 Register).  More about that shortly.     Bits:           Bits 0-1: Sets the number of data bits in a
                 serial word:
                           00 -> 5-bit data
                           01 -> 6-bit data
                           10 -> 7-bit data
                           11 -> 8-bit data
                 Bit 2: Stop bits; 0 flags 1 stop bit per word,
                 1 flags 2 stop bits per word.
                 Bits 3-5: Sets the parity
                          000 -> No parity
                          001 -> Odd
                          011 -> Even
                          101 -> Mark
                          111 -> Space
                 Bit 6: Break control; sends the receiver a break
                 condition.
                 Bit 7: DLR access enable; if set, registers 0
                 and 1 become one big word register (the DLR)
                 that stores the baud rate divisor for calculating
                 the baud rate of the UART.     Register 4:     MCR (Modem Control Register).     Purpose:        Controls the lines on the RS-232 interface.     Bits:           Bit 0: Is reflected on RS-232 DTR (Data
                 Terminal Ready) line.
                 Bit 1: Reflected on RS-232 RTS (Request to
                 Send) line.
                 Bit 2: GPO1 (General Purpose Output 1).
                 Bit 3: GPO2 (General Purpose Output 2).
                 Enables interrupts to be sent from the UART
                 to the PIC.
                 Bit 4: Echo (loop back) test.  All characters
                 sent will be echoed if set.
                 Bits 5-7: Unused.     Register 5:     LSR (Line Status Register).     Purpose:        Stores general status information about the UART.     Bits:           Bit 0: Set if RHR contains a character (called
                 RxRDY or RDR, depending on literature).
                 Bit 1: Overrun error (character overwrote the last
                 in the RHR)
                 Bit 2: Parity error
                 Bit 3: Framing error (stop bit was set to 0 instead
                 of 1).
                 Bit 4: Break condition
                 Bit 5: THE (or TBE).  Transmit Buffer Empty.  If
                 set, the UART sent data from the THR to the OSR
                 (Output Shift Register) and data can be safely
                 written without overwriting anything.
                 Bit 6: Transmitter empty; both the THR and shift
                 register are empty if this is set.
                 Bit 7: Unused on the 8250.     Register 6:     MSR (Modem Status Register).     Purpose:        Displays the status of the modem control lines.
                 After bits 0-3 are read they are reset.     Bits:           Bit 0: CTS (Clear To Send) line has changed
                 (since last read of MSR).
                 Bit 1: DSR (Data Set Ready) has changed.
                 Bit 2: RI (Ring Indicator) has been set since
                 the last time the MSR was read.
                 Bit 3: CD (Carrier Detect) has changed.
                 Bit 4: Value of CTS
                 Bit 5: Value of DSR
                 Bit 6: Value of RI
                 Bit 7: Value of CD     Register 7:     SPR (Scratch Pad Register)     Purpose:        Just what the name implies; a scratch pad, for
                 nothing.     Bits:           Bit 0-7: As you will    The registers listed above are pretty much all that there is to programming
the 8250; you access them by doing an out to the base address of the UART
for a given COM port (it's got a set of registers for every COM port) plus
the offset of the register that you want to work with. The base addresses
of the COM ports are as follows:    #define PORT_COM1       0x3f8
#define PORT_COM2       0x2f8
#define PORT_COM3       0x3e8
#define PORT_COM4       0x2e8    In C, that means    void Write_UART (int COM_port, int reg, int data) {
     outp((COM_port   reg), data);
}    int Read_UART (int COM_port, int reg) {
    return(_inp(COM_port   reg));
}    Easy enough. These functions will allow you to program the UART registers,
and they're all you need to construct a full serial communications library.
Most things that you can program the UART to do are self-explanatory. As a
for-instance, let's try to figure out how to send and receive characters
from the serial port. To do this, first we have to figure out how to set it
up.    Setting up the UART:    Refering to the table above, you'll see that the LCR (register 3) allows us
to establish essential aspects of a serial communications session via the
UART. We need to set up the format of the characters to be sent or
received, namely how many bits each character is to have (5-8), the parity
of the connection (something like a method of error checking), the number
of stop-bits (don't worry about them), and the baud rate at which the
connection is to take place (the number of bits per second to transfer).    Let's go with 8-bit serial words, because that comes to exactly a byte, the
size of the type unsigned char in ANSI C. This makes things a lot easier.
It takes care of the parity issue--there's no room for it with 8-bit serial
words, so forget it (parity=NONE). As for stop bits, we'll just set the
UART to send one of them. That leaves us the issue of setting the baud
rate. Be sure you're sitting down for this next one.    To set the baud rate:    You set bit 7 of register 3, which makes registers 0 and 1 one big
word-sized register that is used to hold the baud-rate divisor. This
divisor is calculated as 0x1C200 / baud_rate and stored in a word-sized
(two-byte) variable, like int in a 16-bit compiler or short in a 32-bit
compiler. Then to set the baud rate for the UART, you do a word out (I
think the ANSI C standard library has a word-out function--like, say,
outpw()--for your convenience) to register 0 on the UART, which fills
registers 0 and 1 with the divisor.     Don't ask me why it's designed like that, I'm not a hardware engineer.
 Let's just say that some Roman god decreed it two thousand years ago and
 your PC will get hit by lightning if you contradict it--some things are
 just plain wierd.    So let's throw together a function that sets up the serial port. Skip the
box if you know about bit flags.     Bit flags for the beginner: It's often desirable to cram a lot of
 information about something into a small space. One way to achieve this
 is by using bit flags, by which each bit of a byte represents the state
 of something. Bit-flags work by using the logical operators & and |, AND
 and OR. OR on a bit level compares two bits and produces one output bit:
 If either one of the input bits is set (=1), then the resulting bit is 1,
 else it isn't. AND on a bit level also compares two bits and produces one
 output bit: If both input bits are set to 1, then the resulting bit is 1,
 else it isn't. When used on a byte level, AND and OR work the same way as
 they do on the bit-level, only on every bit of a byte.     Bit "flags" are defined as numbers that have only one bit set in them,
 such as 128, 64, 32, etc. Individual flags can then be combined to form a
 flag that records the information stored in both of them, such as (128 |
 4) = (01000000 | 00000100) = 01000100. Then you check the state of each
 bit in the byte using & to "mask" all bits in the byte except the one
 that you're interested in. If the bit that you're interested in is set,
 the result of & will be non-zero.    typedef short word
//typedef int word    //SOME CONSTANTS FOR PROGRAMMING THE UART    #define REG_RHR         0
#define REG_THR         0
#define REG_IER         1
#define REG_IIR         2
#define REG_LCR         3
#define REG_MCR         4
#define REG_LSR         5
#define REG_MSR         6
#define REG_SCRATCH     7    //LCR-related constants
#define PARITY_NONE     0
#define PARITY_ODD      8
#define PARITY_EVEN     24
#define PARITY_MARK     20
#define PARITY_SPACE    28    #define STOP_ONE        0
#define STOP_TWO        4    #define BITS_5          0
#define BITS_6          1
#define BITS_7          2
#define BITS_8          3    #define DLR_ON          128    int port_in_use=0;    int Setup_Serial (int COM_port, int baud, unsigned char misc) {
    word divisor;        if(port_in_use)
      return(port_in_use);        port_in_use = COM_port;        Write_UART(COM_port, REG_LCR, (int)DLR_ON);
    divisor = 0x1c200 / baud;
    outpw(COM_port, divisor);        Write_UART(COM_port, REG_LCR, (int)misc);
    return 1;
}    Here's a demonstration:    Setup_Serial(PORT_COM1, 2400, BITS_8 | PARITY_NONE | STOP_ONE);    Now we'd like it if we could actually use the serial port. Let's send and
receive characters.    Sending characters:    To send a character out the serial port, you write it to the THR (register
0). What if there's another character in the THR waiting to be sent? On the
8250, it'll be overwritten. However, you can wait for it to be sent. Test
bit 3 of the LSR to determine if the last character in the THR was shifted
out of the buffer before writing a character. Like this:    void Serial_Write (unsigned char ch) {
     while (!((unsigned char)Read_UART(port_in_use, REG_LSR) & 0x20)) {}         //clear interrupts
     _asm cli         Write_UART(port_in_use, REG_THR, (int)ch);         //set interrupts
     _asm sti
}    Note that software interrupts are turned off using _asm cli. This makes
sure that interrupts using the COM port set up by other programs don't
interfere with the operation of our application. Always be sure to turn
interrupts back on.    Receiving characters:    To determine if a character is in the THR, you read bit 0 of the LSR. When
this bit is set, a character is in the THR, and you can retrieve it by
reading register 0 of the UART.    unsigned char Simple_Serial_Read (void) {
              while (!((unsigned char)Read_UART(port_in_use, REG_LSR) << 7)) {}
              return(Read_UART(port_in_use, REG_RHR));
}    Programming the UART to generate interrupts:    It is often desirable to have the UART tell you when an event occurs,
rather than having to poll its registers to find out. You can do this by
programming it to generate interrupts on certain events.    Before setting up any interrupts, you must set bit 3 of the MCR (UART
register 4) to 1. This toggles the GPO2, which puts the UART out of
tri-state, and allows it to service interrupts. [don't ask; I didn't design
the thing] Then, set the bits of the IER (register 1) that represent the
interrupts you want the UART to generate.    Next, you set up the PIC (Programmable Interrupt Controller) to allow
interrupts from the COM ports. Many of you aren't familiar with this chip
[the PIC], but there's not enough space to give a tutorial on it, so you'll
just have to believe me. COM1 and COM3 are on IRQ4 and COM2 and COM4 are on
IRQ3, so you enable the interrupt by zeroing the 3rd (IRQ3) or 4th (IRQ4)
bit of the PIC's Interrupt Mask Register (be sure to keep the other bits
intact!).    The serial interrupt vector is 0Bh (for COM1/COM3) or 0Ch (for COM2/COM4).
Write an ISR that latches onto the appropriate one. Your ISR should check
the LSR (register 5) to determine what caused the interrupt, then handle
it. Was that fun or what? Some sample code follows, hopefully you can
follow it (DJGPP). [warning: not tested, compiled, or warranted in any way;
uses functions developed earlier in this article.]    #include 
#include 
#include     #define ON_RHRI 1
#define ON_THRI 2
#define ON_RLSI 4
#define ON_MSI  8    _go32_segment_info old_ISR, new_ISR;    void my_ISR(void) {
     //does nothing, and does it well
     asm("cli;pusha");
     asm("popa;sti");
}
void end_my_ISR(void) {}    int serial_interrupt(int COM_port, unsigned char conditions) {
     unsigned char data;         Write_UART(COM_port, REG_MCR, 0x08);
     Write_UART(COM_port, REG_IER, (int)conditions);         _go3d_dpmi_lock_code(my_ISR,(unsigned long)(end_my_ISR-my_ISR));         //WARNING:  You should also lock any data accessed from within
     //an interrupt handler using _go32_dpmi_lock_data();         new_ISR.pm_offset = (int)my_ISR;
     new_ISR.pm_selector = _go32_my_cs();         switch(COM_port) {
           case PORT_COM1:
                _go32_dpmi_get_protected_mode_interrupt_vector(0x0B, &old_ISR);
                _go32_dpmi_allocate_iret_wrapper(&new_ISR);
                _go32_dpmi_set_protected_mode_interrupt_vector(0x0B, &new_ISR);                    data= inportb(0x21); //get PIC IMR
                data&=0xF7;       //zero bit 4
                outportb(0x21,data); //write PIC IMR
                break;
           case PORT_COM2:
                _go32_dpmi_get_protected_mode_interrupt_vector(0x0C, &old_ISR);
                _go32_dpmi_allocate_iret_wrapper(&new_ISR);
                _go32_dpmi_set_protected_mode_interrupt_vector(0x0C, &new_ISR);                    data= inportb(0x21); //get PIC IMR
                data&=0xFB;       //zero bit 3
                outportb(0x21,data); //write PIC IMR
                break;
           default:
                return 0;
     }         return 1;
}    void set_irpt_conditions (int COM_port, unsigned char conditions) {
     Write_UART(COM_port, REG_IER, (int)conditions);
}    int stop_serial_irpt (int COM_port) {
    unsigned char data;        //toggle GPO2
    data = Read_UART(COM_port, REG_MCR);
    data&=0x08;
    Write_UART(COM_port, REG_MCR, (int)data);        //disable interrupts
    Write_UART(COM_port, REG_IER, 0x00);        if (COM_port==PORT_COM1) {
       _go32_dpmi_set_protected_mode_interrupt_vector(0x0B, &old_ISR);
       _go32_dpmi_free_iret_wrapper(&new_ISR);
       return 1;
    }
    if (COM_port==PORT_COM2) {
       _go32_dpmi_set_protected_mode_interrupt_vector(0x0C, &old_ISR);
       _go32_dpmi_free_iret_wrapper(&new_ISR);
       return 1;
    }        return 0;
}    That pretty much covers it for UART/serial port basics. Other tasks that
you might want to perform with the UART are fairly explanatory from the
register information just given. For the purposes of game programming, you
shouldn't have to worry about doing much more than reading, sending, and
checking status. As for the interrupt routine issues, I will leave it up to
you to write an interrupt that processes serial events, because you and you
alone know how you're going to process them in your particular application.
Hopefully this article has made some sense out of the jumbled internals of
the beast called the 8250.    Happy coding...finish that game! :)    If there are any problems or inaccuracies in this article, please post
something on the message board or figure out my address and flame me until
I fix it. ;-)
------------------------------------------------------------    
/*開心的事情別隱藏在心裡,分享給別人知道會更快樂的*/
/*得到新知識別隱藏在心裡,分享給別人了解會更清楚的*/
發表人 - axsoft 於 2003/08/26 12:35:45
kimi
一般會員


發表:37
回覆:76
積分:22
註冊:2003-07-17

發送簡訊給我
#5 引用回覆 回覆 發表時間:2003-08-26 19:36:14 IP:61.227.xxx.xxx 未訂閱
謝謝大大的大力提供
系統時間:2024-04-18 23:48:26
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!