Windows环境下用VC++60实现PC机与单片机之间串行通信的方法Word文件下载.docx
《Windows环境下用VC++60实现PC机与单片机之间串行通信的方法Word文件下载.docx》由会员分享,可在线阅读,更多相关《Windows环境下用VC++60实现PC机与单片机之间串行通信的方法Word文件下载.docx(14页珍藏版)》请在冰点文库上搜索。
CharszComParams[50];
DCBdcb;
Memset(&
m_OverlappedRead,0,sizeof(OVERLAPPED));
m_OverlappedWrite,0,sizeof(OVERLAPPED));
m_hIDComDev=NULL;
m_hIDComDev=CreateFile(“COM2”,GENERIC_READ│GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL│FILE_FLAG_OVERLAPPED,NULL);
if(m_hIDComDev==NULL)
AfxMessageBox(“Cannotopenserialport!
”);
gotoendd;
}
memset(&
COMMTIMEOUTSCommTimeOuts;
CommTimeOuts.ReadIntervalTimeout=0×
FFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier=0;
CommTimeOuts.ReadTotalTimeoutConstant=0;
CommTimeOuts.WriteTotalTimeoutMultiplier=0;
CommTimeOuts.WriteTotalTimeoutConstant=5000;
SetCommTimeouts(m_hIDComDev,&
CommTimeOuts);
Wsprintf(szComparams,“COM2:
9600,n,8,1”);
m_OverlappedRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
m_OverlappedWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
dcb.DCBlength=sizeof(DCB);
GetCommState(m_hIDComDev,&
dcb);
dcb.BaudRate=9600;
dcb.ByteSize=8;
unsignedcharucSet;
ucSet=(unsignedchar)((FC_RTSCTS&
FC_DTRDSR)!
=0);
FC_RTSCTS)!
=0);
FC_XONXOFF)!
if(!
SetCommState(m_hIDComDev,&
dcb)‖
!
SetupComm(m_hIDComDev,10000,10000)‖
m_OverlappedRead.hEvent==NULL‖
m_OverlappedWrite.hEvent==NULL)
DWORDdwError=GetLastError();
if(m_OverlappedRead.hEvent!
=NULL)CloseHandle(m_OverlappedRead.hEvent);
if(m_OverlappedWrite.hEvent!
=NULL)CloseHandle(m_OverlappedWrite.hEvent);
CloseHandle(m_hIDComDev);
endd:
;
//发送数据
OnSend()
charszMessage[20]=“thankyouverymuch”;
DWORDdwBytesWritten;
for(inti=0;
i<sizeof(szMessage);
i++)
WriteFile(m_hIDComDev,(LPSTR)&
szMessage[i],1,&
dwBytesWritten,&
m_OverlappedWrite);
if(WaitForSingleObject(m_OverlapperWrite,hEvent,1000))dwBytesWritten=0;
else{
GentOverlappedResult(m_hIDComDev,&
m_OverlappedWrite,&
dwBytesWritten,FALSE);
m_OverlappedWrite.Offset+=dwBytesWritten;
dwBytesWritten++;
1.2接收例程
DCBComDcb;
//设备控制块
HANDLEhCom;
//globalhandle
hCom=CreateFile("
COM1"
GENERIC_READ|GENERIC_WRITE,0,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hCom==INVALID_HANDLE_VALUE)
AfxMessageBox("
无法打开串行口"
);
else
COMMTIMEOUTSCommTimeOuts;
SetCommMask(hCom,EV_RXCHAR);
SetupComm(hCom,4096,4096);
/*设置收发缓冲区尺寸为4K*/
PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|
PURGE_TXCLEAR|PURGE_RXCLEAR);
//清收发缓冲区
//以下初始化结构变量CommTimeOuts,设置超时参数CommTimeOuts.ReadIntervalTimeout=0×
FFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier=0;
CommTimeOuts.ReadTotalTimeoutConstant=4000;
CommTimeOuts.WriteTotalTimeoutMultiplier=0;
CommTimeOuts.WriteTotalTimeoutConstant=4000;
SetCommTimeouts(hCom,&
CommTimeOuts);
//设置超时参数
ComDcb.DCBlength=sizeof(DCB);
GetCommState(hCom,&
ComDcb);
//获取当前参数
ComDcb.BaudRate=9600;
//波特率
ComDcb.ByteSize=8;
//数据位
ComDcb.Parity=0;
/*校验0~4=no,odd,even,mark,space*/
SetCommState(hCom,&
}//设置新的通信参数
接收可用定时器或线程等
DWORDdRead,dReadNum;
unsignedcharbuff[200];
dRead=ReadFile(hCom,buff,100,&
dReadNum,NULL);
//接收100个字符,
//dReadNum为实际接收字节数
2利用端口函数直接操作
这种方式主要是采用两个端口函数_inp(),_outp()实现对串口的读写,其中读端口函数的原型为:
int_inp(unsignedshotport)
该函数从端口读取一个字节,端口号为0~65535。
写端口的函数原型为:
int_outp(unsignedshotport,intdatabyte)
该函数向指定端口写入一个字节。
不同的计算机串口地址可能不一样,通过向串口的控制及收发寄存器进行读写,可以实现灵活的串口通信功能,由于涉及具体的硬件电路讨论比较复杂,在此不加赘述。
3MSComm控件
MSComm控件是微软开发的专用通信控件,封装了串口的所有功能,使用很方便,但在实际应用中要小心对其属性进行配置。
下面详细说明该类应用方法。
3.1MSComm控件的属性
CommPort:
设置串口号,类型short:
1-comm12-comm2.
Settings:
设置串口通信参数,类型CString:
B波特率,P奇偶性(N无校验,E偶校验,O奇校验),D字节有效位数,S停止位。
PortOpen:
设置或返回串口状态,类型BOOL:
TURE打开,FALSE关闭。
InputMode:
设置从接收缓冲区读取数据的格式,类型long:
0-Text1-Bin。
Input:
从接收缓冲区读取数据,类型VARIANT。
InBufferCount:
接收缓冲区中的字节数,类型:
short。
InBufferSize:
接收缓冲区的大小,类型:
Output:
向发送缓冲区写入数据,类型:
VARIANT。
OutBufferCount:
发送缓冲区中的字节数,类型:
OutBufferSize:
发送缓冲区的大小,类型:
InputLen:
设置或返回Input读出的字节数,类型:
CommEvent:
串口事件,类型:
3.2程序示例
串口初始化
m_comm.GetPortOpen())
m_comm.SetPortOpen(TURE);
/*打开串口*/
m_comm.SetSettings("
4800,n,8,1"
/*串口参数设置*/
m_comm.SetInputMode(0);
/*设置TEXT缓冲区输入方式*/
m_comm.SetRthresHold
(1);
/*每接收一个字符则激发OnComm()事件*/
接收数据
m_comm.SetInputLen
(1);
/*每次读取一个字符
VARINATV1=m_comm.GetInput();
/*读入字符*/
m_V1=V1.bstrval;
发送字符m_comm.SetOutput(Colevariant("
Hello"
/*发送“Hello”*/
3.3注意
SetOutput方法可以传输文本数据或二进制数据。
用SetOutput方法传输文本数据,必须定义一个包含一个字符串的Variant。
发送二进制数据,必须传递一个包含字节数组的Variant到Output属性。
正常情况下,如果发送一个ANSI字符串到应用程序,可以以文本数据的形式发送。
如果发送包含嵌入控制字符、Null字符等的数据,要以二进制形式发送。
此处望引起读者注意,笔者曾经在此犯错。
4VC++类CSerial
4.1串行通信类CSerial简介
Cserial是由MuMegaTechnologies公司提供的一个免费的VC++类,可方便地实现串行通信。
以下为该类定义的说明部分。
classCSerial
public:
CSerial();
~CSerial();
BOOLOpen(intnPort=2,intnBaud=9600);
BOOLClose(void);
intReadData(void*,int);
intSendData(constchar*,int);
intReadDataWaiting(void);
BOOLIsOpened(void){return(m_bOpened);
}
protected:
BOOLWriteCommByte(unsignedchar);
HANDLEm_hIDComDev;
OVERLAPPEDm_OverlappedRead,m_OverlappedWrite;
BOOLm_bOpened;
4.2串行通信类Cserial成员函数简介
1.CSerial:
:
Cserial是类构造函数,不带参数,负责初始化所有类成员变量。
2.CSerial:
Open这个成员函数打开通信端口。
带两个参数,第一个是埠号,有效值是1到4,第二个参数是波特率,返回一个布尔量。
3.CSerial:
Close函数关闭通信端口。
类析构函数调用这个函数,所以可不用显式调用这个函数。
4.CSerial:
SendData函数把数据从一个缓冲区写到串行端口。
它所带的第一个参数是缓冲区指针,其中包含要被发送的资料;
这个函数返回已写到端口的实际字节数。
5.CSerial:
ReadDataWaiting函数返回等待在通信端口缓冲区中的数据,不带参数。
6.CSerial:
ReadData函数从端口接收缓冲区读入数据。
第一个参数是void*缓冲区指针,资料将被放入该缓冲区;
第二个参数是个整数值,给出缓冲区的大小。
4.3应用VC类的一个实例
1.固定式EBM气溶胶灭火系统简介
固定式EBM气溶胶灭火装置分区启动器是专为EBM灭火装置设计的自动控制设备。
可与两线制感温、感烟探测器配套使用,当监测部位发生火情时,探测器发出电信号给分区启动器,经逻辑判断后发出声、光报警,延时后自动启动EBM灭火装置。
为了便于火灾事故的事后分析,需对重要的火警事件和关键性操作进行记录,记录应能从PC机读出来;
PC机能控制、协调整个系统的工作,这些都涉及通信。
本例中启动器采用RS-485通信接口,系统为主从式网络,PC机为上位机。
具体的通信协议为:
(1)下位机定时向上传送记录的事件;
(2)应答发送,即PC机要得到最新事件记录,而传送时间未到时,PC机发送命令,下位机接收命令后,把最新记录传给上位机;
(3)上位机发送其它命令如校时、启动、停止、手/自动等。
2.通信程序设计
部分上位机程序
(1)发送命令字程序,代码如下
voidCCommDlg:
CSerialSerial;
//构造串口类,初始化串行口
if(Serial.Open(2,9600))//if-1
//打开串行口2,波特率为9600bps
staticcharszMessage[]="
0"
//命令码(可定义各种命令码)
intnBytesSent;
intcount=0;
resend:
nBytesSent=Serial.SendData(szMessage,strlen(szMessage));
//发送命令码
charrdMessage[20];
if(Serial.ReadDataWaiting())//if-2
Serial.ReadData(rdMessage,88);
//rdMessage定义接收字节存储区,为全局变量//
if((rdMessage[0]!
=0x7f)&
&
(count<
3))
count++;
gotoresend
if(count>
=3)
MessageBox(“发送命令字失败”);
else//if-2
MessageBox("
接收数据错误"
else//if-1
串行口打开失败"
下位机通信程序:
#include
#definecount9
#definecom_code0x00
#definecom_code10xff
unsignedcharbuffer[count];
intpo,year,month,date,hour;
intminute,second,recordID;
intsum;
main()
…
/*初始化串口和定时器*/
TMOD=0×
20;
TH1=0×
fd;
TR1=0×
01;
ET1=0×
00;
ES=1;
EA=1;
/*待发送数据送缓冲区*/
buffer[0]=0×
ff;
//数据特征码
buffer[1]=count+1;
//数据长度
buffer[2]=year;
//年
buffer[3]=month;
//月
buffer[4]=date;
//日
buffer[5]=hour;
//时
buffer[6]=minute;
//分
buffer[7]=second;
//秒
buffer[8]=recordID;
//事件号
for(po=0;
po
sum+=buffer[po];
buffer[9]=sum;
//校验和
/*发送中断服务程序*/
voidsend(void)interrupt4using1
inti;
RI=0;
EA=0;
do
for(i=0;
i<
=count;
i++)
SBUF=buffer[i];
//发送数据和校验和//
while(TI==0);
TI=0;
while(RI==0);
}while(SBUF!
=0);
//主机接收不正确,重新发送//
EA=1;
Return;
5应用总结
根据不同需要,选择合适的方法。
我们选用的用VC++类实现的上位机和下位机的串行通信方法具有使用简单、编写程序方便的特点。
经过半年多应用于EBM灭火系统的情况来看,该方法实现的系统运行稳定可靠,是一种值得推广的简单易行的通信方法。
参考文献
1KateGregoryVisualC++6开发使用手册.北京:
机械工业出版社,1999
2何立民.单片机的C语言应用程序设计.北京:
北京航空航天大学出版社,1997
3马风格.VC控件与串行通讯.1999现代计算机,2000(4)