课程设计(论文)任务书
一、设计题目:1、题目名称 PC机通过串行口互联 2、题目来源 |
二、目的和意义 俩个PC机通过串行口互联,实现件的无差错传输。程序必须用中断方式来完成任务。 三、原始资料 相关技术资料和程序原代码 四、设计说明书应包括的内容 程序代码、8250串口芯片和中断管理芯片8259的初始化依据。 五、设计应完成的图纸 软件源代码和设计报告。软件代码可以是 C语言或汇编语言,包括流程图。 六、主要参考资料 《微机原理与接口技术》周荷琴等编 七、进度要求 周一查资料;周二和周三编制程序;周四上机实验;周五15点答辩。 八、其它要求 1 PC机使用8250串口芯片。中断管理芯片还是8259。学生需要了解每一个芯片在PC机中的地址。同时了解8250串口芯片的使用方法。 2 不准带电拔插串行口插头。 3 在U盘上自备TURBO C 2.0编译环境。因为机房的计算机(C和D盘要还原)安装有还原卡。 4 此任务书每人打印一份,然后认真阅读。 5 自购DB9P 公插头二个,2,3脚交叉连线,5脚直接连接,焊接。电缆长度一米。
|
一、设计题目
两台PC机之间进行串口通信。串口通信(Serial Communication), 是指外设和计算机间,通过数据信号线 、地线、控制线等,按位进行传输数据的一种通讯方式。这种通信方式使用的数据线少,在远距离通信中可以节约通信成本,但其传输速度比并行传输低。
二、设计目的与要求
1. 两个PC机通过串行口互联,实现文件的无差错传输。程序采用中断方式来完成任务。
2. PC机使用8250串口芯片。中断管理芯片使用8259。了解每一个芯片在PC机中的地址。了解8250串口芯片的使用方法。
三、主要原理及实现方法
1. 程序流程图
程序开始 |
主界面 |
选择波特率 |
退出 |
选择端口号 |
发送字符 |
接受字符 |
发送完毕 |
接受完毕 |
退出 |
2. RS-232C介绍与PC硬件:
RS-232C使用-3到-25V表示数字“1”,使用3V到25V表示数字“0”,RS-232C在空闲时处于逻辑“1”状态,在开始传送时,首先产生一起始位,起始位为一个宽度的逻辑“0”,紧随其后为所要传送的数据,所要传送的数据有最低位开始依此送出,并以一个结束位标志该字节传送结束,结束位为一个宽度的逻辑“1”状态。
PC机一般使用8250或16550作为串行通讯的控制器,使用9针或25针的接插件将串行口的信号送出。
3. 8250的初始化依据
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用于设定通讯所需的波特率。
8250的初始化步骤:
写除数寄存器高8位 |
设置数据格式(通信控制字) |
设置modern控制字 |
设置中断允许字 |
使用通信控制寄存器D7=1 |
8250的初始化流程图
4. 程序源代码的主要部分:
#include <dos.h>
#include <bios.h>
#include <stdio.h>
#include <math.h>
#include <conio.h>
/*8250内部寄存器宏定义,值为对基地址的偏移量*/
#define SER_RBR 0 /*接收缓冲寄存器RBR(读) DLAB=0*/
#define SER_THR 0 /*发送保持寄存器THR(写) DLAB=0*/
#define SER_IER 1 /*中断允许寄存器IER(读/写) DLAB=0*/
#define SER_IIR 2 /*中断识别寄存器IIR (读)*/
#define SER_LCR 3 /*通信线路控制寄存器LCR (读/写)*/
#define SER_MCR 4 /*Model控制寄存器MCR (读/写)*/
#define SER_LSR 5 /*通信线路状态寄存器LSR (读)*/
#define SER_MSR 6 /*Modem状态寄存器MSR (读)*/
#define SER_DLL 0 /*除数锁存器(波特率低8位)DLL(读/写) DLAB=1*/
#define SER_DLH 1 /*除数锁存器(波特率高8位)DLH(读/写) DLAB=1*/
/*8250使用1.8432MHz的基准时钟输入,所以除数=1843200/(B*16)*/
#define SER_BAUD_1200 96 /*波特率为1200时,波特率因子(除数)为96*/
#define SER_BAUD_2400 48 /*波特率为2400时,波特率因子(除数)为48*/
#define SER_BAUD_9600 12 /*波特率为9600时,波特率因子(除数)为12*/
#define SER_BAUD_19200 6 /*波特率为19200时,波特率因子(除数)为6*/
#define COM_1 0x3F8 /*COM1口 8250内部寄存器基地址*/
#define COM_2 0x2F8 /*COM2口 8250内部寄存器基地址*/
#define COM_3 0x3E8 /*COM3口 8250内部寄存器8250基地址*/
#define COM_4 0x2E8 /*COM4口 8250内部寄存器8250基地址*/
#define SER_STOP_1 0 /* 1位停止位*/
#define SER_STOP_2 4 /* 2位停止位*/
#define SER_BITS_5 0 /* 5位数据位*/
#define SER_BITS_6 1 /* 6位数据位*/
#define SER_BITS_7 2 /* 7位数据位*/
#define SER_BITS_8 3 /* 8位数据位*/
#define SER_PARITY_NONE 0 /*无校验*/
#define SER_PARITY_ODD 8 /*奇校验*/
#define SER_PARITY_EVEN 24 /*偶校验*/
#define SER_DIV_LATCH_ON 128 /*DLAB=1*/
#define PIC_IMR 0x21 /*中断屏蔽寄存器*/
#define PIC_ICR 0x20 /*中断控制寄存器*/
#define INT_SER_PORT_0 0x0C /*COM1与COM3中断向量编号*/
#define INT_SER_PORT_1 0x0B /*COM2与COM4中断向量编号*/
/*函数声明*/
void interrupt far Serial_Isr();
Open_Serial(int port_base, int baud, int configuration);
Close_Serial(int port_base);
/*全局变量定义,可在各函数间传递参数*/
void interrupt far (*Old_Isr)(); /* Old_Isr保存原来的串口中断向量*/
int old_int_mask; /*保存原来的中断屏蔽寄存器的值*/
int open_port; /*当前打开的串口编号*/
main()
{
char ch,press;
int done=0;
int i;
int j;
int ba[4];
int da[5];
ba[0]=1200;
ba[1]=2400;
ba[2]=9600;
ba[3]=19200;
da[0]=1016;
da[1]=760;
da[2]=1000;
da[3]=744;
printf("choose to use the baud rate: 0-1200,1-2400,2-9600,3-19200/n");
scanf("%d",&i);
printf("choose to use the port number: 0-1,1-2,2-3,3-4/n");
scanf("%d",&j);
Open_Serial(da[j],ba[i],SER_PARITY_EVEN|SER_BITS_8|SER_STOP_1);
printf("com:%d;bps:%d;parity:even;bits:8;stop bit:1",j+1,ba[i]);
printf("press any key to begin sending");
while(!done)
{ delay(30);
if(kbhit())/*如有键按下*/
{ press=getch();/*读取按键值*/
printf("/nSend the char %c",press);
Serial_Write(press);
if(press==27)/*如果按下的是ESC键(ESC键的ASCII代码为27),则退出*/
done=1;
}
}
Close_Serial(da[j]);/*关闭串口COM1*/
}
/*-----------初始化串口---------------*/
Open_Serial(int port_base, int baud, int configuration)
{
open_port = port_base;
disable();/*关闭中断*/
outp(port_base + SER_LCR, SER_DIV_LATCH_ON);/*DLAB=1*/
outp(port_base + SER_DLL, baud); /*通过设置波特率因子来确定波特率*/
outp(port_base + SER_DLH, 0);
outp(port_base + SER_LCR, configuration); /*通信方式设定,同时DLAB=0*/
outp(port_base + SER_IER, 1); /*允许接收数据就绪中断,关闭其它中断*/
if(port_base == COM_1||port_base==COM_3)
{
/*保存串口1、3原来的中断向量,以便在退出程序时恢复*/
Old_Isr =getvect(INT_SER_PORT_0);
/*为串口设置新的中断向量,在发生中断时就会调用执行用户所指定的中断服务程序*/
setvect(INT_SER_PORT_0, Serial_Isr);
printf("/nOpening Com Port #1/3.../n");
}
else
{
/*功能与上面的代码类似,只是处理的对象是串口2、4*/
Old_Isr =getvect(INT_SER_PORT_1);
setvect(INT_SER_PORT_1, Serial_Isr);
printf("/nOpening Com Port #2/4.../n");
}
old_int_mask = inp(PIC_IMR);/*读入中断屏蔽寄存器的值*/
/*对应位为0则允许该中断,允许3(串口1中断)、4(串口2中断)而不影响其它中断的屏蔽状态*/
outp(PIC_IMR, (port_base==COM_1) ? (old_int_mask & 0xEF) : (old_int_mask & 0xF7 ));
enable();/*允许中断*/
}
/*-------------关闭串口--------------*/
Close_Serial(int port_base)
{
outp(port_base + SER_MCR, 0);
outp(port_base + SER_IER, 0);/*禁止所有串口中断*/
outp(PIC_IMR, old_int_mask );/*恢复原来的中断屏蔽状态*/
if(port_base == COM_1)
{
setvect(INT_SER_PORT_0, Old_Isr);/*恢复原来的串口中断向量*/
printf("/nClosing Com Port #1./n");
}
else
{ setvect(INT_SER_PORT_1, Old_Isr);
printf("/nClosing Com Port #2./n");
}
}
/*--------------写串口-----------------*/
Serial_Write(char ch)
{ while(!(inp(open_port + SER_LSR) & 0x20)){}/*如串口不空闲,则循环等待*/
disable();/*当上面条件不等,说明串口空闲,退出循环*/
outp(open_port + SER_THR, ch); /*开始发送数据*/
enable();/*开中断*/
}
/*-------------串口中断服务程序-----------------*/
void interrupt far Serial_Isr()
{ char ch;
ch = inp(open_port + SER_RBR);/*从串口读出对方传来的数据*/
if(ch==27)/*如传来的是ESC键*/
printf("/nThe Sender is quit");
else
printf("/nReceive the data %c",ch);
outp(PIC_ICR,0x20);/*写入OCW2,向8259发普通EOI指令*/
}