Win32串口编程(4)

//
here
 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); //输入缓冲区和输出缓冲区的大小都是1024

 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; //波特率为9600
 dcb.ByteSize=8; //每个字节有8位
 dcb.Parity=NOPARITY; //无奇偶校验位
 dcb.StopBits=TWOSTOPBITS; //两个停止位
 SetCommState(hCom,&dcb);

 PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);

分别双击IDC_SEND按钮和IDC_RECEIVE按钮,添加两个按钮的响应函数: void CRS485CommDlg::OnSend()
{
 // TODO: Add your control notification handler code here
 // 在此需要简单介绍百特公司XMA5000的通讯协议:
 //该仪表RS485通讯采用主机广播方式通讯。
 //串行半双工,帧11位,1个起始位(0),8个数据位,2个停止位(1)
 //如:读仪表显示的瞬时值,主机发送:DC1 AAA BB ETX
 //其中:DC1是标准ASCII码的一个控制符号,码值为11H(十进制的17)
 //在XMA5000的通讯协议中,DC1表示读瞬时值
 //AAA是从机地址码,也就是XMA5000显示仪表的通讯地址
 //BB为通道号,读瞬时值时该值为01
 //ETX也是标准ASCII码的一个控制符号,码值为03H
 //在XMA5000的通讯协议中,ETX表示主机结束符

 char lpOutBuffer[7];
 memset(lpOutBuffer,''/0'',7); //前7个字节先清零
 lpOutBuffer[0]=''/x11'';  //发送缓冲区的第1个字节为DC1
 lpOutBuffer[1]=''0'';  //第2个字节为字符0(30H)
 lpOutBuffer[2]=''0''; //第3个字节为字符0(30H)
 lpOutBuffer[3]=''1''; // 第4个字节为字符1(31H)
 lpOutBuffer[4]=''0''; //第5个字节为字符0(30H)
 lpOutBuffer[5]=''1''; //第6个字节为字符1(31H)
 lpOutBuffer[6]=''/x03''; //第7个字节为字符ETX
 //从该段代码可以看出,仪表的通讯地址为001
 DWORD dwBytesWrite=7;
 COMSTAT ComStat;
 DWORD dwErrorFlags;
 BOOL bWriteStat;
 ClearCommError(hCom,&dwErrorFlags,&ComStat);
 bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL);
 if(!bWriteStat)
 {
  AfxMessageBox("写串口失败!");
 }

}
void CRS485CommDlg::OnReceive()
{
 // TODO: Add your control notification handler code here

 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);
 
}

您可以观察返回的字符串,其中有和仪表显示值相同的部分,您可以进行相应的字符串操作取出仪表的显示值。
打开ClassWizard,为静态文本框IDC_DISP添加CString类型变量m_disp,同时添加WM_CLOSE的相应函数: void

CRS485CommDlg::OnClose()
{
 // TODO: Add your message handler code here and/or call default
    CloseHandle(hCom); //程序退出时关闭串口
 CDialog::OnClose();
}

程序的相应部分已经在代码内部作了详细介绍。连接好硬件部分,编译运行程序,细心体会串口同步操作部分。
例程2

  打开VC++6.0,新建基于对话框的工程RS485Comm,在主对话框窗口IDD_RS485COMM_DIALOG上添加两个按钮,

ID分别为IDC_SEND和IDC_RECEIVE,标题分别为“发送”和“接收”;添加一个静态文本框IDC_DISP,用于显示

串口接收到的内容。在RS485CommDlg.cpp文件中添加全局变量:

HANDLE hCom; //全局变量,串口句柄在RS485CommDlg.cpp文件中的OnInitDialog()函数添加如下代码:

 hCom=CreateFile("COM1",//COM1口
  GENERIC_READ|GENERIC_WRITE, //允许读和写
  0, //独占方式
  NULL,
  OPEN_EXISTING, //打开而不是创建
  FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //重叠方式
  NULL);
 if(hCom==(HANDLE)-1)
 {
  AfxMessageBox("打开COM失败!");
  return FALSE;
 }

 SetupComm(hCom,100,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; //波特率为9600
 dcb.ByteSize=8; //每个字节有8位
 dcb.Parity=NOPARITY; //无奇偶校验位
 dcb.StopBits=TWOSTOPBITS; //两个停止位
 SetCommState(hCom,&dcb);

 PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);

分别双击IDC_SEND按钮和IDC_RECEIVE按钮,添加两个按钮的响应函数: void CRS485CommDlg::OnSend()
{
 // TODO: Add your control notification handler code here
 OVERLAPPED m_osWrite;
 memset(&m_osWrite,0,sizeof(OVERLAPPED));
 m_osWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);


 char lpOutBuffer[7];
 memset(lpOutBuffer,''/0'',7);
 lpOutBuffer[0]=''/x11'';
 lpOutBuffer[1]=''0'';
 lpOutBuffer[2]=''0'';
 lpOutBuffer[3]=''1'';
 lpOutBuffer[4]=''0'';
 lpOutBuffer[5]=''1'';
 lpOutBuffer[6]=''/x03'';
 
 DWORD dwBytesWrite=7;
 COMSTAT ComStat;
 DWORD dwErrorFlags;
 BOOL bWriteStat;
 ClearCommError(hCom,&dwErrorFlags,&ComStat);
 bWriteStat=WriteFile(hCom,lpOutBuffer,
  dwBytesWrite,& dwBytesWrite,&m_osWrite);

 if(!bWriteStat)
 {
  if(GetLastError()==ERROR_IO_PENDING)
  {
   WaitForSingleObject(m_osWrite.hEvent,1000);
  }
 }

}

void CRS485CommDlg::OnReceive()
{
 // TODO: Add your control notification handler code here
 OVERLAPPED m_osRead;
 memset(&m_osRead,0,sizeof(OVERLAPPED));
 m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);

 COMSTAT ComStat;
 DWORD dwErrorFlags;
 
 char str[100];
 memset(str,''/0'',100);
 DWORD dwBytesRead=100;//读取的字节数
 BOOL bReadStat;

 ClearCommError(hCom,&dwErrorFlags,&ComStat);
 dwBytesRead=min(dwBytesRead, (DWORD)ComStat.cbInQue);
 bReadStat=ReadFile(hCom,str,
  dwBytesRead,&dwBytesRead,&m_osRead);
 if(!bReadStat)
 {
  if(GetLastError()==ERROR_IO_PENDING)
     //GetLastError()函数返回ERROR_IO_PENDING,表明串口正在进行读操作
  {
   WaitForSingleObject(m_osRead.hEvent,2000);
      //使用WaitForSingleObject函数等待,直到读操作完成或延时已达到2秒钟
      //当串口读操作进行完毕后,m_osRead的hEvent事件会变为有信号
  }
 }

 PurgeComm(hCom, PURGE_TXABORT|
  PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
 m_disp=str;
 UpdateData(FALSE);
}

打开ClassWizard,为静态文本框IDC_DISP添加CString类型变量m_disp,同时添加WM_CLOSE的相应函数: void

CRS485CommDlg::OnClose()
{
 // TODO: Add your message handler code here and/or call default
    CloseHandle(hCom); //程序退出时关闭串口
 CDialog::OnClose();
}

您可以仔细对照这两个例程,细心体会串口同步操作和异步操作的区别。
好了,就到这吧,祝您好运。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值