|
本文将分别描述PC机及单片机MCS-51的串行通讯的原理及具体的软件设计。 RS-232C介绍与PC硬件 使用查询方法的串行通讯程序设计
使用中断的串行通讯程序设计
MCS-51串行通讯
关于RS485
(1)RS-232C介绍与PC硬件:
RS-232C使用-3到-25V表示数字“1”,使用3V到25V表示数字“0”,RS-232C在空闲时处于逻辑“1”状态,在开始传送时,首先产生一起始位,起始位为一个宽度的逻辑“0”,紧随其后为所要传送的数据,所要传送的数据有最低位开始依此送出,并以一个结束位标志该字节传送结束,结束位为一个宽度的逻辑“1”状态。
PC机一般使用8250或16550作为串行通讯的控制器,使用9针或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)使用查询方法的串行通讯程序设计:
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.
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 ); |
|