doc sever

中国DOS 联盟联盟域名:www.cn-dos.net 论坛域名:bbs.cn-dos.net DOS ,代表着自由开放与发展,我们努力起来,学习FreeDOS 和Linux 的自由开放与GN

中国DOS 联盟

联盟域名:www.cn-dos.net 论坛域名:bbs.cn-dos.net DOS ,代表着自由开放与发展,我们努力起来,学习FreeDOS 和Linux 的自由开放与GNU

精神,共同创造和发展美好的自由与GNU GPL世界吧!

» 游客: 注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助

中国DOS 联盟论坛 » DOS 开发编程 & 发展交流 (开发室) » MS-DOS下如何编程控制RS232串口详细资料及源程序

<< >> >

上一主题 | 下一主题 作者: 标题: MS-DOS下如何编程控制RS232串口详

细资料及源程序

BA_WANG_

MAO

初级用户

『楼 主』: MS-DOS下如何编程控制RS232串口详细资料及源程序 PC 机与单片机的通讯 大多数的电脑设备都具有RS-232C 接口,尽管它的性能指标并非很好。在广泛的市场支

持下依然常胜不衰。就使用而言,RS-232也确实有其优势:仅需3根线便可在两个数字设备之间全双工的传送数据。不过,RS-232C 的控制要比使用并行通讯的打印机接口更 难于控制。RS-232C 使用了远较并行口更多的寄存器。这些寄存器用来实现串行数据的传送及RS-232C 设备之间的握手与流量控制。本文将分别描述PC 机及单片机MCS-51的串行通讯的原理及具体的软件设计。

(1)RS-232C 介绍与PC 硬件

RS-232C 使用-3到-25V 表示数字“1”,使用3V 到25V 表示数字“0”,RS-232C 在空闲时处于逻辑“1”状态,在开始传送时,首先产生一起始位,起始位为一个宽度的逻辑“0”,紧随其后为所要传送的数据,所要传送的数据有最低位开始依此送出,并以一个结束位标志该字节传送结束,结束位为一个宽度的逻辑“1”状态。

PC 机一般使用8250或16550作为串行通讯的控制器,使用9针或25针的接插件将串 积分 147 发帖 13 注册 2005-3-25 状态 离线

,

行口的信号送出。该插座的信号定义如下:

DB-25 DB-9 信号名称 方向 含义

2 3 TXD 输出 数据发送端

3 2 RXD 输入 数据接收端

4 7 RTS 输出 请求发送(计算机要求发送数据)

5 8 CTS 输入 清除发送(MODEM 准备接收数据) 6 6 DSR 输入 数据设备准备就绪

7 5 SG - 信号地

8 1 DCD 输入 数据载波检测

20 4 DTR 输出 数据终端准备就绪(计算机)

22 9 RI 输入 响铃指示

以上信号在通讯过程之中可能会被全部或部分使用,最简单的通讯仅需TXD 及RXD 及SG 即可完成,其他的握手信号可以做适当处理或直接悬空,至于是否可以悬空这视乎你的通讯软件。比如说,如果使用DOS 所提供的BIOS 通讯驱动程序,那么,这些握手信号则需要做如下处理,因为BIOS 的通讯驱动使用了这些信号。如果使用自己编写的串行驱动程序则可以完全不使用这些握手信号(详见下面有关章节)。

PC 机一般使用8250或16550的作为串行通讯控制器,8250及16550的管脚排列如下:

8250(16550)的寄存器如下表所示:

基地址 读/写 寄存器缩写 注释

0 Write - 发送保持寄存器(DLAB=0)

0 Read - 接收数据寄存器(DLAB=0)

0 Read/Write - 波特率低八位(DLAB=1)

1 Read/Write IER 中断允许寄存器

1 Read/Write - 波特率高八位(DLAB=1)

2 Read IIR 中断标识寄存器

2 Write FCR FIFO 控制寄存器

3 Read/Write LCR 线路控制寄存器

4 Read/Write MCR MODEM 控制寄存器

5 Read LSR 线路状态寄存器

6 Read MSR MODEM 状态寄存器

7 Read/Write - Scratch Register

PC 机支持1-4个串行口,即COM1-COM4,其基地址在BIOS 数据区0000:0400-0000:0406中描述,对应地址分别为3F8/2F8/3E8/2E8,COM1及COM3使用PC 机中断4,COM2及COM4使用中断3。

在上表中,8250共有12个寄存器,使用了8个地址,其中部分寄存器共用一个地址,由DLAB=0/1来区分,在DLAB=1用于设定通讯所需的波特率。常用的波特率参数见下表:

速率(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

以下几个表格为8250的寄存器的功能描述:

中断允许寄存器(IER ):

位 注释

7 未使用

6 未使用

5 进入低功耗模式(16750)

4 进入睡眠模式(16750)

3 允许MODEM 状态中断

2 允许接收线路状态中断

1 允许发送保持器空中断

0 允许接收数据就绪中断

Bit0置1将允许接收到数据时产生中断,Bit1置1时允许发送保持寄存器空时产生中断,Bit2置1将在LSR 变化时产生中断,相应的Bit3置位将在MSR 变化时产生中断。 中断识别寄存器(IIR ):

位 注释

Bit6:7=00 无FIFO

Bit6:7=01 允许FIFO ,但不可用

Bit6:7=11 允许FIFO

Bit5 允许64字节FIFO (16750)

Bit4 未使用

Bit3 16550超时中断

Bit2:1=00 MODEM 状态中断(CTS/RI/DTR/DCD)

Bit2:1=01 发送保持寄存器空中断

Bit2:1=10 接收数据就绪中断

Bit2:1=11 接收线路状态中断

Bit0=0 有中断产生

Bit0=1 无中断产生

IIR 为只读寄存器,Bit6:7用来指示FIFO 的状态,均为0时则无FIFO ,此时为8250或16450芯片,为01时有FIFO 但不可以使用,为11时FIFO 有效并可以正常工作。Bit3用来指示超时中断(16550/16750)。

Bit0用来指示是否有中断发生,Bit1:2标识具体的中断类型,这些中断具有不同的优先级别,其中LSR 中断级别最高,其次是数据就绪中断,然后是发送寄存器空中断,而MSR 中断级别最低。

FIFO 控制寄存器(FCR ):

位 注释

,

Bit7:6=00 1Byte 产生中断

Bit7:6=01 4Byte 产生中断

Bit7:6=10 8Byte 产生中断

Bit7:6=11 14Byte 产生中断

Bit5 允许64字节FIFO

Bit4 未使用

Bit3 DMA 模式选择

Bit2 清除发送FIFO

Bit1 清除接收FIFO

Bit0 允许FIFO

FCR 可写但不可以读,该寄存器用来控制16550或16750的FIFO 寄存器。Bit0置1将允许发送/接收的FIFO 工作,Bit1和Bit2置1分别用来清除接收及发送FIFO 。清除接收及发送FIFO 并不影响移位寄存器。Bit1:2可自行复位,因此无需使用软件对其清零。Bit6:7用来设定产生中断的级别,发送/接收中断将在发送/接收到对应字节数时产生。 线路控制寄存器(LCR ):

位 注释

Bit7=1 允许访问波特率因子寄存器

Bit7=0 允许访问接收/发送及中断允许寄存器

Bit6 设置间断,0-禁止,1-设置

Bit5:3=XX0 无校验

Bit5:3=001 奇校验

Bit5:3=011 偶校验

Bit5:3=101 奇偶保持为1

Bit5:3=111 奇偶保持为0

Bit2=0 1位停止位

Bit2=1 2位停止位(数据位6-8位),1.5位停止位(5位数据位)

Bit1:0=00 5位数据位

Bit1:0=01 6位数据位

Bit1:0=10 7位数据位

Bit1:0=11 8位数据位

LCR 用来设定通讯所需的一些基本参数。Bit7为1指定波特率因子寄存器有效,为0则指定发送/接收及IER 有效。Bit6置1会将发送端置为0,这将会使接收端产生一个“间断”。Bit3-5用来设定是否使用奇偶校验以及奇偶校验的类型,Bit3=1时使用校验,Bit4为0则为奇校验,1为偶校验,而Bit5则强制校验为1或0,并由Bit4决定具体为0或

1。Bit2用来设定停止位的长度,0表示1位停止位,为1则根据数据长度的不同使用

1.5-2位停止位。Bit0:1用来设定数据长度。

MODEM 控制寄存器(MCR ):

位 注释

Bit7 未使用

Bit6 未使用

Bit5 自动流量控制(仅16750)

Bit4 环路测试

Bit3 辅助输出2

Bit2 辅助输出1

,

Bit1 设置RTS

Bit0 设置DSR

MCR 寄存器可读可写,Bit4=1进入环路测试模式。Bit3-0用来控制对应的管脚。 线路状态寄存器(LSR ):

位 注释

Bit7 FIFO 中接收数据错误

Bit6 发送移位寄存器空

Bit5 发送保持寄存器空

Bit4 间断

Bit3 帧格式错

Bit2 奇偶错

Bit1 超越错

Bit0 接收数据就绪

LSR 为只读寄存器,当发生错误时Bit7为1,Bit6为1时标示发送保持及发送移位寄存器均空,Bit5为1时标示仅发送保持寄存器空,此时,可以由软件发送下一数据。当线路状态为0时Bit4置位为1,帧格式错时Bit3置位为1,奇偶错和超越错分别将Bit2及Bit1置位为1。Bit0置位为1表示接收数据就绪。

MODEM 状态寄存器(MSR ):

位 注释

Bit7 载波检测

Bit6 响铃指示

Bit5 DSR 准备就绪

Bit4 CTS 有效

Bit3 DCD 已改变

Bit2 RI 已改变

Bit1 DSR 已改变

Bit0 CTS 已改变

MSR 寄存器的高4位分别对应MODEM 的状态线,低4位表示MODEM 的状态线是否发生了变化。

以上我们详细介绍了PC 机的串行通讯硬件环境,以下将分别给出使用查询及中断驱动的方法编写的串行口驱动程序。这些程序仅使用RXD/TXD,无需硬件握手信号。

(2)使用查询方法的串行通讯程序设计

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 以下的应用。

,

(3)使用中断的串行通讯程序设计

该程序由两部分组成,serial.c 及sercom.c ,sercom.c 为通讯的底层驱动,使用中断的串行通讯程序可以工作到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 count */

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 );

}

标签: