单片机与计算机串行通信实验心得
- 格式:pdf
- 大小:254.26 KB
- 文档页数:7
单片机应用电子报/2005年/02月/20日/第011版/单片机与计算机串行通信实验心得北京赵宁 很多单片机教材里提到了单片机和计算机串口通信的硬件和软件设计,给出了如图1所示的最简单的三线连接电路和B IOS IN T14H的应用。
笔者按照教材所述的方法进行了实验,但未成功。
通过实验,发现在简单的三线连接电路中,IN T14H不能用来通信,无法发送和接收。
下面详细给出笔者采用的能实现通信的方法,供参考。
一、计算机串口编程PC/XT计算机串口的核心是通用异步接收/发送器8250。
附表是计算机串口的系统地址和8250内部寄存器的对应关系。
DLAB(除数寄存器访问控制位)是通信线控制寄存器的D7位,当该位为1时,对地址3F8H(2F8H)、3F9H(2F9H)的读写是针对除数寄存器的,在此用途之外应使该位置0;接收缓冲器和发送保持寄存器的地址相同,由读写信号区分。
寄存器可以分为3类。
发送保持寄存器和接收缓冲器用于暂存待发送数据或接收到的数据;通信线控制寄存器、除数寄存器、MODEM控制寄存器、中断允许寄存器用于设置和控制串口;通信线状态寄存器、MODEM状态寄存器、中断识别寄存器用来反映串口当前的状态。
有关寄存器的设置,请读者查阅相关资料。
8250的初始化编程步骤如下:1.将80H送通信线控制寄存器3FB(2FBH),使DLAB=1。
2.将分频系数送入除数寄存器,确定波特率3F9H(2F9H)、3F8H(2F8H)。
3.把D7=0的命令字送入通信线控制寄存器,确定一帧数据格式。
4.将中断允许命令字送中断允许寄存器3F9H(2F9H)。
查询方式时为0H。
5.设置MODEM控制寄存器3FCH(2FCH),查询方式时D3=0,中断方式时D3 =1,以允许8250送出中断请求。
正常收发时应使D4=0,内环自检时使D4=1。
二、IN T14H功能调用IN T14H功能调用的子功能如下:功能号00H为初始化串口;功能号01H为向串口写数据;功能号02H为从串口读数据;功能号03H为读取串口状态。
在C语言中,可以使用int86()等函数设置寄存器变量后,直接使用上述功能调用,但最简单的方法是用bioscom()函数,它的函数说明是int bioscom(int cmd,char abyte,int port)。
其中,cmd是子功能号,abyte是初始化参数或待发送的字符,port是串口号。
Cmd取0、1、2、3时,bioscom()的功能分别和IN T14H的00H、01H、02H、03H子功能对应。
无论cmd取何值,返回值的高8位对应IN T14H出口参数中的AH,低8位对应AL。
当cmd=0时,abyte为初始化参数;当cmd=1时,abyte是待发送数据;当cmd=2时,返回值的低8位是所接收到的数据;当cmd取1或2时,返回值的最高位为0,表示成功,否则失败;当cmd=3时,返回值为串口状态,高8位为通信线状态,低8位为MODEM状态。
三、单片机的串行通信实验下面给出笔者实验时编写的单片机串行通信源程序:org00hjmp mainorg23h;串行中断入口地址jmp com-int;串行中断服务程序org30hmain:mov sp,#30h;设置堆栈lcall comm;串口初始化jmp$;原地等待comm:mov tmod,#20h;T1方式2mov tl1,#0f3h;定时器计数初值,波特率2400mov th1,#0f3h;定时器重装值setb ea;开总中断setb es;开串行中断mov pcon,#00h;波特率不倍增mov scon,#50h;置串口工作方式1,REN=1允许接收setb tr1;定时器ret;返回com-int:clr es;关串行中断clr ri;清接收标志mov a,sbuf;从缓冲区取数据mov sbuf,ajnb ti,$;等待发送完毕clr ti;清发送标志setb es;允许串行中断reti;中断返回end该程序将MCU的串口初始化为2400bps的波特率,然后等待中断。
中断服务程序的功能是将所接收的数据发给计算机。
笔者最初用C语言编写的通信程序如下:#include″dos.h″#include″bios.h″main0{int i;bioscom(0,0xa3,0);for(i=0;i<256;i++){bioscom(1,i,0);printf(″%c″,i);while(!(bioscom(3,0,0)&0x0100));printf(″-%c″,bioscom(2,0,0)&0x00ff);}printf(″\n″);getch0;}该程序无法实现与单片机的串口通信,用int86函数直接调用14H功能调用也不行,所以笔者剖析了bioscom函数的执行过程,发现了问题所在。
笔者用图1所示的连接线将计算机的COM1和COM2连接起来,具体如图2所示,然后执行下列程序对bioscom函数的1号发送功能进行测试。
#include″dos.h″#include″bios.h″#define COM3main(){outportb(0x3fc,0);outportb(0x2fc,0);bioscom(0,0xa3,0);bioscom(0,0xa3,1);outportb(0x2fc,COM);printf(″%X″,bioscom(1,65,0)&0x8000);printf(″\n″);getch();}COM1和COM2初始化后,将COM2的MODEM控制寄存器(2FCH)的D0、D1位置1,使COM2的D TR、R TS有效,从而使COM1的DSR、CTS有效。
程序显示的结果是0,说明发送正确。
通过改变程序中宏定义COM的值,可以改变COM1的DSR、CTS信号有效的组合。
结果表明,只有COM=3时,即DSR和CTS都有效时, bioscom才能发送成功。
当COM取1、2或0,即DSR、CTS分别有效或全无效时,程序显示8000,表明发送失败。
利用下列程序段对bioscom的接收功能进行测试:#include″dos.h″#include″bios.h″#define COM1main(){int a;outportb(0x3fc,0);outportb(0x2fc,0);bioscom(0,0xa3,0);bioscom(0,0xa3,1);outportb(0x3fc,COM);outportb(0x3f8,65);delay(10000);a=bioscom(2,0,1);printf(″%X,%c″,a&0x8000,a&0x00ff);printf(″\n″);getch();}可以得出如下结论:当cmd=0时,bioscom函数对串口初始化,写通信线控制寄存器和除数寄存器,设置数据帧格式和波特率,并写中断允许寄存器,清除所有中断允许位,串口读写只能工作于程序查询方式,但不写MODEM控制寄存器;当cmd=1时, bioscom函数发送数据,改写MODEM控制寄存器,使D TR、R TS信号有效,并查询MODEM状态寄存器,等待DSR、CTS两个回答信号,只有在一定延时内,两个回答信号都有效才发送成功;当cmd=2时,bioscom函数接收数据,改写MODEM控制寄存器使D TR有效,并查询MODEM状态寄存器,等待DSR回答信号,同样需在一定延时内得到回答否则接收失败;当cmd=3时,bioscom函数读取通信线状态寄存器和MODEM状态寄存器,并返回。
弄清了bioscom函数的执行过程,就可以用图3所示的连接进行通信,使串口的D TR和DSR短接,R TS和CTS短接,这样,只要bioscom使D TR、R TS有效,便可得到所需的回答信号。
在这种连接下,前面给出的不能通信的程序就可以正常通信了。
那么,能否用图1所示的简单三线连接进行计算机和单片机的串行通信呢,答案是肯定的。
只要用上述程序中给出的inportb和outportb两个函数直接驱动8250即可,其说明如下:unsigned char inportb(int portid);void char inportb(int portid,unsigned char value);portid是硬件端口地址;Value是发送的字符数据。
下面是笔者编写的初始化、写串口、读串口函数。
void initcom(int com,int bps){int co-a,io-a;char ch;switch(bps){case110:ch=0x03;break;case150:ch=0x23;break;case300:ch=0x43;break;case600:ch=0x63;break;case1200:ch=0x83;break;case2400:ch=0xa3;break;case4800:ch=0xc3;break;case9600:ch=0xe3;break;default:ch=0xa3;}co-a=(com-1)?0x2fc:0x3fc;io-a=(com-1)?0x2f8:0x3f8;bioscom(0,ch,com-1);outportb(co-a,0);inportb(io-a);}参数com是串口号,COM1为1,COM2为2。
bps是所需的波特率。
这里是用bioscom函数实现初始化的大部分功能。
若按照前边给出的8250初始化步骤,可以用下列程序段对COM1进行初始化:outportb(0x3fb,0x80);outportb(0x3f9,0);outportb(0x3f8,0x30);outportb(0x3fb,0x03);outportb(0x3f9,0);outportb(0x3fc,0);下面是写串口函数和读串口函数:void outcom(int com,char ch){int st-a,io-a;st-a=(com-1)?0x2fd:0x3fd;io-a=(com-1)?0x2f8:0x3f8;while(!(inportb(st-a)&0x20));outportb(io-a,ch);}int incom(int com,char3ch){int st-a,io-a;st-a=(com-1)?0x2fd:0x3fd;io-a=(com-1)?0x2f8:0x3f8;if(inportb(st-a)&0x01){3ch=inportb(io-a);return1;}else return0;}outcom函数将ch从com指定的串口发送出去,incom函数从com指定的串口读取字符,若成功则返回1并改写ch单元。