深入浅出串口编程之DOS的串口编程Word格式文档下载.docx
《深入浅出串口编程之DOS的串口编程Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《深入浅出串口编程之DOS的串口编程Word格式文档下载.docx(11页珍藏版)》请在冰豆网上搜索。
#defineSTR"
author:
sbh"
unionREGSinregs,outregs;
main()
{
//设置串口参数
init_rs232();
//写串口的例子
write_rs232(STR,strlen(STR));
//读串口的例子
read_rs232();
return(0);
}
init_rs232()
{
do{
inregs.h.ah=0;
//AH=0表示初始化端口
inregs.h.al=0xe7;
inregs.x.dx=0;
//COM1
int86(0x14,&
inregs,&
outregs);
}while(outregs.h.ah>
=0x80);
write_rs232(char*string,intlen)
inti;
inregs.h.ah=1;
//发送AL寄存器的字符
inregs.h.al=*string;
}while(outregs.h.al>
for(i=1;
i<
len;
i++)
{
inregs.h.al=*(string+i);
}
read_rs232()
inregs.h.ah=2;
//读取AL寄存器中的字符
}while(outregs.h.al!
=3||outregs.h.ah>
其中使用的int86函数的原型为:
int_Cdeclint86(intintno,unionREGS*inregs,unionREGS*outregs);
int86()函数可以调用BIOS功能,现在的程序员们已经很少接触这个函数,80%的程序员甚至都未曾见过这个函数。
其实,在茹毛饮血的DOS时代,int86()函数几乎是最常用和最核心的函数之一。
几乎可以说,在那个时代,不会int86()就等于不会编程。
而与int86配合使用的,就是REGS这样一个联合体,定义为:
unionREGS{
structWORDREGSx;
structBYTEREGSh;
};
其中的WORDREGS定义为:
structWORDREGS{
unsignedintax,bx,cx,dx,si,di,
cflag/*进位标志*/,
flags/*标志寄存器*/;
而BYTEREGS则定义为:
structBYTEREGS{
unsignedcharal,ah,bl,bh,cl,ch,dl,dh;
原来WORDREGS和BYTEREGS是16位的8086处理器内部的寄存器啊!
因此,当CPU发展到286、386以后,再安装DOS也是建立在利用CPU实模式的基础上的!
另外一个函数与int86()的功能是类似的:
Int_Cdeclint86x(intintno,unionREGSinregs,unionREGSoutregs,structSREGSsegregs);
其中的SREGS为段寄存器结构体,定义为:
structSREGS
unsignedintes;
unsignedintcs;
unsignedintss;
unsignedintds;
int86和int86x这两个函数的功能都是执行一个由参数intno指定的8086软中断。
在执行软中断之前,两个函数都把inregs中的内容放置到各寄存器中(int86x还把segregs.x.es和segregs.x.ds的值存到相应的段寄存器中),软中断返回后,这两个函数都把当前寄存器的值存到outregs,并把系统进位标志拷贝到outregs.s.cflag中,把8086标志寄存器值存到outregs.x.flag中(int86x还恢复DS,并设置Segregs.es和Segregs.ds的值为对应段寄存器的值)。
查阅BIOS中断调用手册,发现绝大多数调用都未用到ES和DS段寄存器,故在程序设计中经常只利用了int86函数。
2.硬件中断
为了给读者一个直观的印象,我们通过在Windows操作系统中查看COM的资源属性获得某COM对应的中断号,如图2(该对话框中设备管理器中开启)。
图2COM中断号
实际上COM的确直接对应于一个中断,而系统也按照一定的规律为各类硬件分配了一个较固定的中断号,如表1。
表1中断向量表
INT(Hex)
IRQ
CommonUses
08
0
SystemTimer
09
1
Keyboard
0A
2
Redirected
0B
3
SerialComms.COM2/COM4
0C
4
SerialComms.COM1/COM3
0D
5
Reserved/SoundCard
0E
6
FloppyDiskController
0F
7
ParallelComms.
70
8
RealTimeClock
71
9
Reserved
72
10
73
11
74
12
PS/2Mouse
75
13
MathsCo-Processor
76
14
HardDiskDrive
77
15
Reserved
通过编写COM对应的中断服务程序,我们也可以操作串口,涉及到的相关函数有:
(1)设置中断向量表
/*dos.h*/
void_Cdeclsetvect(intinterruptno,voidinterrupt(*isr)());
例如,COM3对应的中断号是4,那么对应中断向量表中的地址是0x0C,设置0x0C对应中断程序的函数为:
setvect(0x0C,PORT1INT);
其中的中断服务程序PORT1INT为:
voidinterruptPORT1INT()
intc;
do
c=inportb(PORT1+5);
if(c&
1)
{
buffer[bufferin]=inportb(PORT1);
bufferin++;
if(bufferin==1024)
bufferin=0;
}
while(c&
1);
outportb(0x20,0x20);
上述中断服务程序检查是否有字符可接收,其后将其通过inportb(PORT1)语句将其从UART中读出并放入输入buffer。
持续的检查UART,以便能在一次中断里读取所有可获得的数据。
最后的"
outportb(0x20,0x20);
"
语句告诉可编程中断控制器(ProgrammableInterruptController,PIC)中断已经完成。
(2)读取中断向量表
voidinterrupt(*_Cdeclgetvect(intinterruptno))();
例如:
oldport1isr=getvect(INTVECT);
其中的oldport1isr定义为:
voidinterrupt(*oldport1isr)();
我们融合setvect()函数、中断服务程序和getvect()函数,给出一个由CraigPeacock编写的完备例程:
/*Name:
SampleComm'
sProgram-1024ByteBuffer-buff1024.c*/
/*WrittenBy:
CraigPeacock<
cpeacock@.au>
*/
conio.h>
#definePORT10x3F8/*PortAddressGoesHere*/
#defineINTVECT0x0C/*ComPort'
sIRQhere(MustalsochangePICsetting)*/
/*DefinesSerialPortsBaseAddress*/
/*COM10x3F8*/
/*COM20x2F8*/
/*COM30x3E8*/
/*COM40x2E8*/
intbufferin=0;
intbufferout=0;
charch;
charbuffer[1025];
voidinterrupt(*oldport1isr)();
voidinterruptPORT1INT()/*InterruptServiceRoutine(ISR)forPORT1*/
{
}
voidmain(void)