转自:http://blog.csdn.net/lqxandroid2012/article/details/8701162
RS485是半双工协议,有的工控主板厂家在做RS485口时,完整的实现了自动RTS,则我们编程人员不用关心底层硬件变化,就像平时使用RS232串口一样使用,这包括我们到电子市场买的232转422或485的“博世头”,都内部自动实现了自动RTS;有的厂家没有实现自动RTS,则需要我们自己实现。前面也说过,在WIN32下,只需要关心DCB数据结构的fRtsControl成员,将其值改为RTS_CONTROL_TOGGLE即可,如下面程序:
初始化部分:
hCom=CreateFile("COM1",//COM1
口
GENERIC_READ|GENERIC_WRITE, //
允许读和写
0, //
独占方式
NULL,
OPEN_EXISTING, //
打开而不是创建
0, //
同步方式
NULL);
if(hCom==(HANDLE)-1)
{
AfxMessageBox("
打开COM失败!"
);
return FALSE;
}
SetupComm(hCom,100,100); //
输入缓冲区和输出缓冲区的大小都是
COMMTIMEOUTS TimeOuts;
//
设定读超时
TimeOuts.ReadIntervalTimeout=MAXDWORD;
TimeOuts.ReadTotalTimeoutMultiplier=0;
TimeOuts.ReadTotalTimeoutConstant=0;
//
在读一次输入缓冲区的内容后读操作就立即返回,
//
而不管是否读入了要求的字符。
//
设定写超时
TimeOuts.WriteTotalTimeoutMultiplier=100;
TimeOuts.WriteTotalTimeoutConstant=500;
SetCommTimeouts(hCom,&TimeOuts); //
设置超时
DCB dcb;
GetCommState(hCom,&dcb);
dcb.BaudRate=9600; //
波特率为
dcb.ByteSize=8; //
每个字节有位
dcb.Parity=NOPARITY; //
无奇偶校验位
dcb.StopBits=TWOSTOPBITS; //
两个停止位
dcb.fRtsControl = RTS_CONTROL_TOGGLE;
SetCommState(hCom,&dcb);
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
写部分:
char lpOutBuffer[7];
memset(lpOutBuffer,'/0',7); //
前个字节先清零
lpOutBuffer[0]='/x11'; //
发送缓冲区的第个字节为DC1
lpOutBuffer[1]='0'; //
第个字节为字符(30H)
lpOutBuffer[2]='0'; //
第个字节为字符(30H)
lpOutBuffer[3]='1'; //
第个字节为字符(31H)
lpOutBuffer[4]='0'; //
第个字节为字符(30H)
lpOutBuffer[5]='1'; //
第个字节为字符(31H)
lpOutBuffer[6]='/x03'; //
第个字节为字符ETX
//
从该段代码可以看出,仪表的通讯地址为
DWORD dwBytesWrite=7;
COMSTAT ComStat;
DWORD dwErrorFlags;
BOOL bWriteStat;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL);
if(!bWriteStat)
{
AfxMessageBox("
写串口失败!"
);
}
读部分:
char str[100];
memset(str,'/0',100);
DWORD wCount=100;//
读取的字节数
BOOL bReadStat;
bReadStat=ReadFile(hCom,str,wCount,&wCount,NULL);
if(!bReadStat)
AfxMessageBox("
读串口失败!"
);
PurgeComm(hCom, PURGE_TXABORT|
PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
m_disp=str;
UpdateData(FALSE);
上述代码在XP下通过,但是同样程序移植到WinCE下,发送出去的内容的最有一个字节总是0XFF,在MSDN上找了篇文章,解释了原因,如下:
PRB: Using SetCommState() to Toggle DTR/RTS for Flow Control
ID: Q99861
|
The information in this article applies to:
- Microsoft Windows Software Development Kit (SDK) 3.1
SYMPTOMS
When SetCommState() is used to raise the DTR and RTS lines for hardware flow control, the first several incoming characters may be lost.
CAUSE
SetCommState() calls the communications driver's setcom function, which calls $SETCOM. $SETCOM disables interrupts from the specified port by clearing the UART's interrupt enable register (IER). After changing the state of the UART and the DTR and RTS lines, $SETCOM delays while interrupts from the UART are still disabled. In Windows 3.1, this delay is approximately 200 milliseconds; in Windows 3.0, the delay is approximately 55 milliseconds. If the DTR and RTS lines are raised from low to high, any characters that arrive before interrupts from the UART are enabled will be lost.
RESOLUTION
SetCommState() should not be used to toggle the states of the DTR and RTS lines for hardware flow control.
Use EscapeCommFunction() to toggle the the states of the DTR and RTS lines because it does not delay while interrupts are disabled.
Use EscapeCommFunction() to toggle the the states of the DTR and RTS lines because it does not delay while interrupts are disabled.
Additional query words: 3.00 3.10 comm
Keywords : kb16bitonly
Version : WINDOWS:3.1
Platform : WINDOWS
Issue type :
Version : WINDOWS:3.1
Platform : WINDOWS
Issue type :
里面大致意思是使用:
dcb.fRtsControl = RTS_CONTROL_TOGGLE;
SetCommState(hCom,&dcb);
有问题,需要使用:
EscapeCommFunction(
hCom, CLRRTS) 来清除RTS位,或 EscapeCommFunction(
hCom, SETRTS)来设置RTS位。
考虑上述程序结构,可以在发送之前总是“SETRTS”(即为允许发送状态),发送完毕后“CLRRTS”(即设为允许接收状态)。如在程序初始化中添加:
hCom=CreateFile("COM1",//COM1
口
GENERIC_READ|GENERIC_WRITE, //
允许读和写
0, //
独占方式
NULL,
OPEN_EXISTING, //
打开而不是创建
0, //
同步方式
NULL);
if(hCom==(HANDLE)-1)
{
AfxMessageBox("
打开COM失败!"
);
return FALSE;
}
SetupComm(hCom,100,100); //
输入缓冲区和输出缓冲区的大小都是
COMMTIMEOUTS TimeOuts;
//
设定读超时
TimeOuts.ReadIntervalTimeout=MAXDWORD;
TimeOuts.ReadTotalTimeoutMultiplier=0;
TimeOuts.ReadTotalTimeoutConstant=0;
//
在读一次输入缓冲区的内容后读操作就立即返回,
//
而不管是否读入了要求的字符。
//
设定写超时
TimeOuts.WriteTotalTimeoutMultiplier=100;
TimeOuts.WriteTotalTimeoutConstant=500;
SetCommTimeouts(hCom,&TimeOuts); //
设置超时
DCB dcb;
GetCommState(hCom,&dcb);
dcb.BaudRate=9600; //
波特率为
dcb.ByteSize=8; //
每个字节有位
dcb.Parity=NOPARITY; //
无奇偶校验位
dcb.StopBits=TWOSTOPBITS; //
两个停止位
// dcb.fRtsControl = RTS_CONTROL_TOGGLE;
SetCommState(hCom,&dcb);
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
if(!EscapeCommFunction(hCom,CLRRTS))
{
AfxMessageBox("
不能设置CLRRTS"
);
}
写部分中:
if(!EscapeCommFunction(hCom,SETRTS))
{
AfxMessageBox("
不能设置SETRTS"
);
}
char lpOutBuffer[7];
memset(lpOutBuffer,'/0',7); //
前个字节先清零
lpOutBuffer[0]='/x11'; //
发送缓冲区的第个字节为DC1
lpOutBuffer[1]='0'; //
第个字节为字符(30H)
lpOutBuffer[2]='0'; //
第个字节为字符(30H)
lpOutBuffer[3]='1'; //
第个字节为字符(31H)
lpOutBuffer[4]='0'; //
第个字节为字符(30H)
lpOutBuffer[5]='1'; //
第个字节为字符(31H)
lpOutBuffer[6]='/x03'; //
第个字节为字符ETX
//
从该段代码可以看出,仪表的通讯地址为
DWORD dwBytesWrite=7;
COMSTAT ComStat;
DWORD dwErrorFlags;
BOOL bWriteStat;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL);
if(!bWriteStat)
{
AfxMessageBox("
写串口失败!"
);
}
Sleep(10);
if(!EscapeCommFunction(hCom,CLRRTS))
{
AfxMessageBox("
不能设置CLRRTS"
);
}
读部分不用改动,写动作中的Sleep功能是调试中试出的。