doc sever
中國(guó)DOS 聯(lián)盟聯(lián)盟域名:www.cn-dos.net 論壇域名:bbs.cn-dos.net DOS ,代表著自由開(kāi)放與發(fā)展,我們努力起來(lái),學(xué)習(xí)FreeDOS 和Linux 的自由開(kāi)放與GN
中國(guó)DOS 聯(lián)盟

聯(lián)盟域名:www.cn-dos.net 論壇域名:bbs.cn-dos.net DOS ,代表著自由開(kāi)放與發(fā)展,我們努力起來(lái),學(xué)習(xí)FreeDOS 和Linux 的自由開(kāi)放與GNU
精神,共同創(chuàng)造和發(fā)展美好的自由與GNU GPL世界吧!
? 游客: 注冊(cè) | 登錄 | 命令行 | 會(huì)員 | 搜索 | 上傳 | 幫助
中國(guó)DOS 聯(lián)盟論壇 ? DOS 開(kāi)發(fā)編程 & 發(fā)展交流 (開(kāi)發(fā)室) ? MS-DOS下如何編程控制RS232串口詳細(xì)資料及源程序
<< >> >


上一主題 | 下一主題 作者: 標(biāo)題: MS-DOS下如何編程控制RS232串口詳
細(xì)資料及源程序
BA_WANG_
MAO
初級(jí)用戶
『樓 主』: MS-DOS下如何編程控制RS232串口詳細(xì)資料及源程序 PC 機(jī)與單片機(jī)的通訊 大多數(shù)的電腦設(shè)備都具有RS-232C 接口,盡管它的性能指標(biāo)并非很好。在廣泛的市場(chǎng)支
持下依然常勝不衰。就使用而言,RS-232也確實(shí)有其優(yōu)勢(shì):僅需3根線便可在兩個(gè)數(shù)字設(shè)備之間全雙工的傳送數(shù)據(jù)。不過(guò),RS-232C 的控制要比使用并行通訊的打印機(jī)接口更 難于控制。RS-232C 使用了遠(yuǎn)較并行口更多的寄存器。這些寄存器用來(lái)實(shí)現(xiàn)串行數(shù)據(jù)的傳送及RS-232C 設(shè)備之間的握手與流量控制。本文將分別描述PC 機(jī)及單片機(jī)MCS-51的串行通訊的原理及具體的軟件設(shè)計(jì)。
(1)RS-232C 介紹與PC 硬件
RS-232C 使用-3到-25V 表示數(shù)字“1”,使用3V 到25V 表示數(shù)字“0”,RS-232C 在空閑時(shí)處于邏輯“1”狀態(tài),在開(kāi)始傳送時(shí),首先產(chǎn)生一起始位,起始位為一個(gè)寬度的邏輯“0”,緊隨其后為所要傳送的數(shù)據(jù),所要傳送的數(shù)據(jù)有最低位開(kāi)始依此送出,并以一個(gè)結(jié)束位標(biāo)志該字節(jié)傳送結(jié)束,結(jié)束位為一個(gè)寬度的邏輯“1”狀態(tài)。
PC 機(jī)一般使用8250或16550作為串行通訊的控制器,使用9針或25針的接插件將串 積分 147 發(fā)帖 13 注冊(cè) 2005-3-25 狀態(tài) 離線
,行口的信號(hào)送出。該插座的信號(hào)定義如下:
DB-25 DB-9 信號(hào)名稱 方向 含義
2 3 TXD 輸出 數(shù)據(jù)發(fā)送端
3 2 RXD 輸入 數(shù)據(jù)接收端
4 7 RTS 輸出 請(qǐng)求發(fā)送(計(jì)算機(jī)要求發(fā)送數(shù)據(jù))
5 8 CTS 輸入 清除發(fā)送(MODEM 準(zhǔn)備接收數(shù)據(jù)) 6 6 DSR 輸入 數(shù)據(jù)設(shè)備準(zhǔn)備就緒
7 5 SG - 信號(hào)地
8 1 DCD 輸入 數(shù)據(jù)載波檢測(cè)
20 4 DTR 輸出 數(shù)據(jù)終端準(zhǔn)備就緒(計(jì)算機(jī))
22 9 RI 輸入 響鈴指示
以上信號(hào)在通訊過(guò)程之中可能會(huì)被全部或部分使用,最簡(jiǎn)單的通訊僅需TXD 及RXD 及SG 即可完成,其他的握手信號(hào)可以做適當(dāng)處理或直接懸空,至于是否可以懸空這視乎你的通訊軟件。比如說(shuō),如果使用DOS 所提供的BIOS 通訊驅(qū)動(dòng)程序,那么,這些握手信號(hào)則需要做如下處理,因?yàn)锽IOS 的通訊驅(qū)動(dòng)使用了這些信號(hào)。如果使用自己編寫(xiě)的串行驅(qū)動(dòng)程序則可以完全不使用這些握手信號(hào)(詳見(jiàn)下面有關(guān)章節(jié))。
PC 機(jī)一般使用8250或16550的作為串行通訊控制器,8250及16550的管腳排列如下:
8250(16550)的寄存器如下表所示:
基地址 讀/寫(xiě) 寄存器縮寫(xiě) 注釋
0 Write - 發(fā)送保持寄存器(DLAB=0)
0 Read - 接收數(shù)據(jù)寄存器(DLAB=0)
0 Read/Write - 波特率低八位(DLAB=1)
1 Read/Write IER 中斷允許寄存器
1 Read/Write - 波特率高八位(DLAB=1)
2 Read IIR 中斷標(biāo)識(shí)寄存器
2 Write FCR FIFO 控制寄存器
3 Read/Write LCR 線路控制寄存器
4 Read/Write MCR MODEM 控制寄存器
5 Read LSR 線路狀態(tài)寄存器
6 Read MSR MODEM 狀態(tài)寄存器
7 Read/Write - Scratch Register
PC 機(jī)支持1-4個(gè)串行口,即COM1-COM4,其基地址在BIOS 數(shù)據(jù)區(qū)0000:0400-0000:0406中描述,對(duì)應(yīng)地址分別為3F8/2F8/3E8/2E8,COM1及COM3使用PC 機(jī)中斷4,COM2及COM4使用中斷3。
在上表中,8250共有12個(gè)寄存器,使用了8個(gè)地址,其中部分寄存器共用一個(gè)地址,由DLAB=0/1來(lái)區(qū)分,在DLAB=1用于設(shè)定通訊所需的波特率。常用的波特率參數(shù)見(jiàn)下表:
速率(BPS ) 波特率高八位 波特率低八位
50 09h 00h
300 01h 80h
,600 00h C0h
2400 00h 30h
4800 00h 18h
9600 00h 0Ch
19200 00h 06h
38400 00h 03h
57600 00h 02h
115200 00h 01h
以下幾個(gè)表格為8250的寄存器的功能描述:
中斷允許寄存器(IER ):
位 注釋
7 未使用
6 未使用
5 進(jìn)入低功耗模式(16750)
4 進(jìn)入睡眠模式(16750)
3 允許MODEM 狀態(tài)中斷
2 允許接收線路狀態(tài)中斷
1 允許發(fā)送保持器空中斷
0 允許接收數(shù)據(jù)就緒中斷
Bit0置1將允許接收到數(shù)據(jù)時(shí)產(chǎn)生中斷,Bit1置1時(shí)允許發(fā)送保持寄存器空時(shí)產(chǎn)生中斷,Bit2置1將在LSR 變化時(shí)產(chǎn)生中斷,相應(yīng)的Bit3置位將在MSR 變化時(shí)產(chǎn)生中斷。 中斷識(shí)別寄存器(IIR ):
位 注釋
Bit6:7=00 無(wú)FIFO
Bit6:7=01 允許FIFO ,但不可用
Bit6:7=11 允許FIFO
Bit5 允許64字節(jié)FIFO (16750)
Bit4 未使用
Bit3 16550超時(shí)中斷
Bit2:1=00 MODEM 狀態(tài)中斷(CTS/RI/DTR/DCD)
Bit2:1=01 發(fā)送保持寄存器空中斷
Bit2:1=10 接收數(shù)據(jù)就緒中斷
Bit2:1=11 接收線路狀態(tài)中斷
Bit0=0 有中斷產(chǎn)生
Bit0=1 無(wú)中斷產(chǎn)生
IIR 為只讀寄存器,Bit6:7用來(lái)指示FIFO 的狀態(tài),均為0時(shí)則無(wú)FIFO ,此時(shí)為8250或16450芯片,為01時(shí)有FIFO 但不可以使用,為11時(shí)FIFO 有效并可以正常工作。Bit3用來(lái)指示超時(shí)中斷(16550/16750)。
Bit0用來(lái)指示是否有中斷發(fā)生,Bit1:2標(biāo)識(shí)具體的中斷類型,這些中斷具有不同的優(yōu)先級(jí)別,其中LSR 中斷級(jí)別最高,其次是數(shù)據(jù)就緒中斷,然后是發(fā)送寄存器空中斷,而MSR 中斷級(jí)別最低。
FIFO 控制寄存器(FCR ):
位 注釋
,Bit7:6=00 1Byte 產(chǎn)生中斷
Bit7:6=01 4Byte 產(chǎn)生中斷
Bit7:6=10 8Byte 產(chǎn)生中斷
Bit7:6=11 14Byte 產(chǎn)生中斷
Bit5 允許64字節(jié)FIFO
Bit4 未使用
Bit3 DMA 模式選擇
Bit2 清除發(fā)送FIFO
Bit1 清除接收FIFO
Bit0 允許FIFO
FCR 可寫(xiě)但不可以讀,該寄存器用來(lái)控制16550或16750的FIFO 寄存器。Bit0置1將允許發(fā)送/接收的FIFO 工作,Bit1和Bit2置1分別用來(lái)清除接收及發(fā)送FIFO 。清除接收及發(fā)送FIFO 并不影響移位寄存器。Bit1:2可自行復(fù)位,因此無(wú)需使用軟件對(duì)其清零。Bit6:7用來(lái)設(shè)定產(chǎn)生中斷的級(jí)別,發(fā)送/接收中斷將在發(fā)送/接收到對(duì)應(yīng)字節(jié)數(shù)時(shí)產(chǎn)生。 線路控制寄存器(LCR ):
位 注釋
Bit7=1 允許訪問(wèn)波特率因子寄存器
Bit7=0 允許訪問(wèn)接收/發(fā)送及中斷允許寄存器
Bit6 設(shè)置間斷,0-禁止,1-設(shè)置
Bit5:3=XX0 無(wú)校驗(yàn)
Bit5:3=001 奇校驗(yàn)
Bit5:3=011 偶校驗(yàn)
Bit5:3=101 奇偶保持為1
Bit5:3=111 奇偶保持為0
Bit2=0 1位停止位
Bit2=1 2位停止位(數(shù)據(jù)位6-8位),1.5位停止位(5位數(shù)據(jù)位)
Bit1:0=00 5位數(shù)據(jù)位
Bit1:0=01 6位數(shù)據(jù)位
Bit1:0=10 7位數(shù)據(jù)位
Bit1:0=11 8位數(shù)據(jù)位
LCR 用來(lái)設(shè)定通訊所需的一些基本參數(shù)。Bit7為1指定波特率因子寄存器有效,為0則指定發(fā)送/接收及IER 有效。Bit6置1會(huì)將發(fā)送端置為0,這將會(huì)使接收端產(chǎn)生一個(gè)“間斷”。Bit3-5用來(lái)設(shè)定是否使用奇偶校驗(yàn)以及奇偶校驗(yàn)的類型,Bit3=1時(shí)使用校驗(yàn),Bit4為0則為奇校驗(yàn),1為偶校驗(yàn),而B(niǎo)it5則強(qiáng)制校驗(yàn)為1或0,并由Bit4決定具體為0或
1。Bit2用來(lái)設(shè)定停止位的長(zhǎng)度,0表示1位停止位,為1則根據(jù)數(shù)據(jù)長(zhǎng)度的不同使用
1.5-2位停止位。Bit0:1用來(lái)設(shè)定數(shù)據(jù)長(zhǎng)度。
MODEM 控制寄存器(MCR ):
位 注釋
Bit7 未使用
Bit6 未使用
Bit5 自動(dòng)流量控制(僅16750)
Bit4 環(huán)路測(cè)試
Bit3 輔助輸出2
Bit2 輔助輸出1
,Bit1 設(shè)置RTS
Bit0 設(shè)置DSR
MCR 寄存器可讀可寫(xiě),Bit4=1進(jìn)入環(huán)路測(cè)試模式。Bit3-0用來(lái)控制對(duì)應(yīng)的管腳。 線路狀態(tài)寄存器(LSR ):
位 注釋
Bit7 FIFO 中接收數(shù)據(jù)錯(cuò)誤
Bit6 發(fā)送移位寄存器空
Bit5 發(fā)送保持寄存器空
Bit4 間斷
Bit3 幀格式錯(cuò)
Bit2 奇偶錯(cuò)
Bit1 超越錯(cuò)
Bit0 接收數(shù)據(jù)就緒
LSR 為只讀寄存器,當(dāng)發(fā)生錯(cuò)誤時(shí)Bit7為1,Bit6為1時(shí)標(biāo)示發(fā)送保持及發(fā)送移位寄存器均空,Bit5為1時(shí)標(biāo)示僅發(fā)送保持寄存器空,此時(shí),可以由軟件發(fā)送下一數(shù)據(jù)。當(dāng)線路狀態(tài)為0時(shí)Bit4置位為1,幀格式錯(cuò)時(shí)Bit3置位為1,奇偶錯(cuò)和超越錯(cuò)分別將Bit2及Bit1置位為1。Bit0置位為1表示接收數(shù)據(jù)就緒。
MODEM 狀態(tài)寄存器(MSR ):
位 注釋
Bit7 載波檢測(cè)
Bit6 響鈴指示
Bit5 DSR 準(zhǔn)備就緒
Bit4 CTS 有效
Bit3 DCD 已改變
Bit2 RI 已改變
Bit1 DSR 已改變
Bit0 CTS 已改變
MSR 寄存器的高4位分別對(duì)應(yīng)MODEM 的狀態(tài)線,低4位表示MODEM 的狀態(tài)線是否發(fā)生了變化。
以上我們?cè)敿?xì)介紹了PC 機(jī)的串行通訊硬件環(huán)境,以下將分別給出使用查詢及中斷驅(qū)動(dòng)的方法編寫(xiě)的串行口驅(qū)動(dòng)程序。這些程序僅使用RXD/TXD,無(wú)需硬件握手信號(hào)。
(2)使用查詢方法的串行通訊程序設(shè)計(jì)
CODE: [Copy to clipboard]
polling.c
#include
#include
#include
#define PortBase 0x2F8
void com_putch(unsigned char);
int com_chkch(void);
main()
,{
int c;
unsigned char ch;
outportb(PortBase 1 , 0); /* Turn off interrupts - Port1 *//* Set COM1: 9600,8,N,1*/
outportb(PortBase 3 , 0x80);
outportb(PortBase 0 , 0x0C);
outportb(PortBase 1 , 0x00);
outportb(PortBase 3 , 0x03);
clrscr();
while(1) {
c = com_chkch();
if(c!=-1) {
c &= 0xff; putch(c);
if(c=='n') putch('r');
}
if(kbhit()) {
ch = getch(); com_putch(ch);
}
}
}
void com_putch(unsigned char ch) {
unsigned char status;
while(1) {
status = inportb(PortBase 5);
if(status&0x01) inportb(PortBase 0); else break;
}
outportb(PortBase,ch);
}
int com_chkch(void) {
unsigned char status;
status = inportb(PortBase 5);
status &= 0x01;
if(status) return((int)inportb(PortBase 0)); else return(-1);
}
使用查詢方式的通訊程序適合9600bps 以下的應(yīng)用。
,(3)使用中斷的串行通訊程序設(shè)計(jì)
該程序由兩部分組成,serial.c 及sercom.c ,sercom.c 為通訊的底層驅(qū)動(dòng),使用中斷的串行通訊程序可以工作到115.2Kbps.
CODE: [Copy to clipboard]
serial.c
#include
#include
#include
#include
#include
#include "sercom.c"
COM *c;
main()
{
unsigned char ch;
c =
ser_init( PORT_B,BAUD_9600,_COM_CHR8,_COM_NOPARITY,4096,4096 ); while(1) {
if( serhit(c)) {
ch = getser(c);
putchar(ch);
}
if(kbhit()) {
ch = getch();
putser(ch,c);
}
}
}
llio.c
#include
#include
#include
#include
#define CR 0x0d
#define TRUE 0xff
#define FALSE 0
#define PORT_A 0 /* COM1 */
#define PORT_B 1 /* COM2 */
,#define BAUD_9600 _COM_9600
#define BAUD_4800 _COM_4800
#define BAUD_2400 _COM_2400
#define BAUD_1200 _COM_1200
#define BAUD_600 _COM_600
#define BAUD_300 _COM_300
#define BAUD_110 _COM_110
typedef struct {
char ready; /* TRUE when ready */
unsigned com_base; /* 8250 Base Address */
char irq_mask; /* IRQ Enable Mask */
char irq_eoi; /* EOI reply for this port */ char int_number; /* Interrupt # used */
void (_interrupt _far *old)( void ); /* Old Interrupt */
/* Buffers for I/O */
char *in_buf; /* Input buffer */
int in_tail; /* Input buffer TAIL ptr */ int in_head; /* Input buffer HEAD ptr */ int in_size; /* Input buffer size */
int in_crcnt; /* Input
char in_mt; /* Input buffer FLAG */
char *out_buf; /* Output buffer */
int out_tail; /* Output buffer TAIL ptr */ int out_head; /* Output buffer HEAD ptr */ int out_size; /* Output buffer size */
char out_full; /* Output buffer FLAG */
char out_mt; /* Output buffer MT */
} COM;
COM *ser_init( int port,int baud,int bit,int parity,int isize,int osize );
void ser_close( COM *c );
int getsers( COM *c,int len,char *str );
int putsers( char *str, COM *c );
char serline( COM *c );
int getser( COM *c );
,char serhit(COM *c);
char putser(char outch,COM *c);
void cntl_rts(int flag,COM *c);
void cntl_dtr(int flag,COM *c);
void clean_ser( COM *c );
#define COM1_BASE 0x03F8
#define COM1_IRQ_MASK 0xEF /*11101111B IRQ 4 For COM1 */
#define COM1_IRQ_EOI 0x64 /* IRQ 4 Spec EOI */ #define COM1_INT_NUM 0x0C /* Int # for IRQ4 */
#define COM2_BASE 0x02F8
#define COM2_IRQ_MASK 0xF7 /*11110111B IRQ 3 For COM2 */
#define COM2_IRQ_EOI 0x63 /* IRQ 3 Spec EOI */ #define COM2_INT_NUM 0x0B /* Int # for IRQ3 */
/* 8250 ACE register defs */
#define THR 0 /* Offset to Xmit hld reg (write) */ #define RBR 0 /* Receiver holding buffer (read) */ #define IER 1 /* Interrupt enable register */ #define IIR 2 /* Interrupt identification reg */ #define LCR 3 /* Line control register */
#define MCR 4 /* Modem control register */
#define LSR 5 /* Line status register */
#define MSR 6 /* Modem status register */
#define SREG(x) ((unsigned)((unsigned)x c->com_base))
/* 8259 Int controller registers */
#define INTC_MASK 0x21 /* Interrupt controller MASK reg */
#define INTC_EOI 0x20 /* Interrupt controller EOI reg */
#define MAX_PORTS 2 /* # I/O ports (DOS limit) */ static int count = 0;
static COM com_list[MAX_PORTS]; /* I/O data structure */
,static COM *com1; /* Pointers for interrupt actions */
static COM *com2;
static COM *com_xfer; /* Transfer interrupt data structure */
COM *ser_init0(int port,char *ibuf,int isize, char *obuf,int osize);
void ser_close0( COM *c );
void (_interrupt _far int_ser1)( void ); /* Int rtn for serial I/O COM 1 */
void (_interrupt _far int_ser2)( void ); /* Int rtn for serial I/O COM 2 */
void (_interrupt _far int_ser_sup)( void ); /* Support int actions */
COM *ser_init( int port,int baud,int bit,int parity,int isize,int osize )
{
unsigned status;
char ch;
COM *c;
char *in_buf,*out_buf;
status = _bios_serialcom(_COM_INIT,port,(bit | parity | _COM_STOP2| baud ));
in_buf = malloc( isize );
if( in_buf == NULL ) return( NULL );
out_buf = malloc( osize );
if( out_buf == NULL ) return( NULL );
c = ser_init0(port,in_buf,isize,out_buf,osize );
clean_ser(c);
return( c );
}