串口异步同步通讯

 

  
  
  
  
  1. /*------+------+------+------+------+------+------+------+------+------+------+------  
  2. 串口编程的一个实例  
  3.   为了让您更好地理解串口编程,下面我们分别编写两个例程(见附带的源码部分),  
  4.     这两个例程都实现了工控机与百特显示仪表通过RS485接口进行的串口通信。其中  
  5.     第一个例程采用同步串口操作,第二个例程采用异步串口操作。  
  6.   我们只介绍软件部分,RS485接口接线方法不作介绍,感兴趣的读者可以查阅相关资料。  
  7. /*------+------+------+------+------+------+------+------+------+------+------+----*/ 
  8.  
  9. /*------+------+------+------+------+------+------+------+------+------+------+------+  
  10.     打开VC++6.0,新建基于对话框的工程RS485Comm,在主对话框窗口IDD_RS485COMM_DIALOG  
  11.     上添加两个按钮,ID分别为IDC_SEND和IDC_RECEIVE,标题分别为“发送”和“接收”;添加一  
  12.     个静态文本框IDC_DISP,用于显示串口接收到的内容。  
  13. ------+------+------+------+------+------+------+------+------+------+------+-------*/ 
  14.  
  15. //在RS485CommDlg.cpp文件中添加全局变量:  
  16.  
  17. HANDLE hCom;  //全局变量,串口句柄  
  18.  
  19. //在RS485CommDlg.cpp文件中的OnInitDialog()函数添加如下代码:  
  20.  
  21. // TODO: Add extra initialization here  
  22. hCom=CreateFile(    "COM1",                     //COM1口  
  23.                     GENERIC_READ|GENERIC_WRITE, //允许读和写  
  24.                     0,                          //独占方式  
  25.                     NULL,  
  26.                     OPEN_EXISTING,              //打开而不是创建  
  27.                     0,                          //同步方式  
  28.                     NULL    );  
  29. if(hCom==(HANDLE)-1)  
  30. {  
  31.     AfxMessageBox("打开COM失败!");  
  32.     return FALSE;  
  33. }  
  34.  
  35. SetupComm(hCom,100,100); //输入缓冲区和输出缓冲区的大小都是1024  
  36.  
  37. COMMTIMEOUTS TimeOuts;  
  38.  
  39. //设定读超时  
  40. TimeOuts.ReadIntervalTimeout=MAXDWORD;  
  41. TimeOuts.ReadTotalTimeoutMultiplier=0;  
  42. TimeOuts.ReadTotalTimeoutConstant=0;  
  43.  
  44. //在读一次输入缓冲区的内容后读操作就立即返回,  
  45. //而不管是否读入了要求的字符。  
  46.  
  47. //设定写超时  
  48. TimeOuts.WriteTotalTimeoutMultiplier=100;  
  49. TimeOuts.WriteTotalTimeoutConstant=500;  
  50.  
  51. SetCommTimeouts(hCom,&TimeOuts);    //设置超时  
  52.  
  53. DCB dcb;  
  54. GetCommState(hCom,&dcb);  
  55. dcb.BaudRate=9600;                  //波特率为9600  
  56. dcb.ByteSize=8;                     //每个字节有8位  
  57. dcb.Parity=NOPARITY;                //无奇偶校验位  
  58. dcb.StopBits=TWOSTOPBITS;           //两个停止位  
  59. SetCommState(hCom,&dcb);  
  60.  
  61. PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);  
  62.  
  63. //分别双击IDC_SEND按钮和IDC_RECEIVE按钮,添加两个按钮的响应函数:  
  64. void CRS485CommDlg::OnSend()   
  65. {  
  66.     /*------+------+------+------+------+------+------+------+-------  
  67.     |   TODO: Add your control notification handler code here       |  
  68.     |   在此需要简单介绍百特公司XMA5000的通讯协议:                   |  
  69.     |   该仪表RS485通讯采用主机广播方式通讯。                       |  
  70.     |   串行半双工,帧11位,1个起始位(0),8个数据位,2个停止位(1)  |  
  71.     |   如:读仪表显示的瞬时值,主机发送:DC1 AAA BB ETX         |  
  72.     |   其中:DC1是标准ASCII码的一个控制符号,码值为11H(十进制的17)   |  
  73.     |   在XMA5000的通讯协议中,DC1表示读瞬时值                        |  
  74.     |   AAA是从机地址码,也就是XMA5000显示仪表的通讯地址           |  
  75.     |   BB为通道号,读瞬时值时该值为01                               |  
  76.     |   ETX也是标准ASCII码的一个控制符号,码值为03H                 |  
  77.     |   在XMA5000的通讯协议中,ETX表示主机结束符                   |  
  78.     ------+------+------+------+------+------+------+------+------+*/ 
  79.     char lpOutBuffer[7];  
  80.     memset(lpOutBuffer,''\0'',7);   //前7个字节先清零  
  81.     lpOutBuffer[0]=''\x11'';        //发送缓冲区的第1个字节为DC1  
  82.     lpOutBuffer[1]=''0'';           //第2个字节为字符0(30H)  
  83.     lpOutBuffer[2]=''0'';           //第3个字节为字符0(30H)  
  84.     lpOutBuffer[3]=''1'';           // 第4个字节为字符1(31H)  
  85.     lpOutBuffer[4]=''0'';           //第5个字节为字符0(30H)  
  86.     lpOutBuffer[5]=''1'';           //第6个字节为字符1(31H)  
  87.     lpOutBuffer[6]=''\x03'';        //第7个字节为字符ETX  
  88.       
  89.     //从该段代码可以看出,仪表的通讯地址为001   
  90.     DWORD dwBytesWrite=7;  
  91.     COMSTAT ComStat;  
  92.     DWORD dwErrorFlags;  
  93.     BOOL bWriteStat;  
  94.     ClearCommError(hCom,&dwErrorFlags,&ComStat);  
  95.     bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL);  
  96.     if(!bWriteStat)  
  97.     {  
  98.         AfxMessageBox("写串口失败!");  
  99.     }  
  100.  
  101. }  
  102.  
  103. void CRS485CommDlg::OnReceive()   
  104. {  
  105.     // TODO: Add your control notification handler code here  
  106.     char str[100];  
  107.     memset(str,''\0'',100);  
  108.     DWORD wCount=100;       //读取的字节数  
  109.     BOOL bReadStat;  
  110.     bReadStat=ReadFile(hCom,str,wCount,&wCount,NULL);  
  111.     if(!bReadStat)  
  112.         AfxMessageBox("读串口失败!");  
  113.     PurgeComm(hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);  
  114.     m_disp=str;  
  115.     UpdateData(FALSE);  
  116.    
  117. }  
  118.  
  119. //您可以观察返回的字符串,其中有和仪表显示值相同的部分,您可以进行相应的字符串操作取出仪表的显示值。  
  120. //打开ClassWizard,为静态文本框IDC_DISP添加CString类型变量m_disp,同时添加WM_CLOSE的相应函数:  
  121.  
  122. void CRS485CommDlg::OnClose()   
  123. {  
  124.  // TODO: Add your message handler code here and/or call default  
  125.     CloseHandle(hCom);  //程序退出时关闭串口  
  126.     CDialog::OnClose();  
  127. }  
  128.  
  129.  
  130. //--------------------------------------------------------------------------------------------------  
  131. //--------------------------------------------------------------------------------------------------  
  132.  
  133.  
  134. //程序的相应部分已经在代码内部作了详细介绍。连接好硬件部分,编译运行程序,细心体会串口同步操作部分。  
  135. //例程2  
  136.  
  137. /*------+------+------+------+------+------+------+------+------+------+------+------+------+-------  
  138.     打开VC++6.0,新建基于对话框的工程RS485Comm,在主对话框窗口IDD_RS485COMM_DIALOG上添加两个按钮,  
  139.     ID分别为IDC_SEND和IDC_RECEIVE,标题分别为“发送”和“接收”;添加一个静态文本框IDC_DISP,用于显示  
  140.     串口接收到的内容。在RS485CommDlg.cpp文件中添加全局变量:  
  141. /*------+------+------+------+------+------+------+------+------+------+------+------+------+------*/ 
  142.  
  143. HANDLE hCom; //全局变量,  
  144.  
  145. //串口句柄在RS485CommDlg.cpp文件中的OnInitDialog()函数添加如下代码:  
  146.  
  147. hCom=CreateFile(    "COM1",                                     //COM1口  
  148.                     GENERIC_READ|GENERIC_WRITE,                 //允许读和写  
  149.                     0,                                          //独占方式  
  150.                     NULL,  
  151.                     OPEN_EXISTING,                              //打开而不是创建  
  152.                     FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //重叠方式  
  153.                     NULL    );  
  154. if(hCom==(HANDLE)-1)  
  155. {  
  156.     AfxMessageBox("打开COM失败!");  
  157.     return FALSE;  
  158. }  
  159.  
  160. SetupComm(hCom,100,100); //输入缓冲区和输出缓冲区的大小都是100  
  161.  
  162. COMMTIMEOUTS TimeOuts;  
  163. //设定读超时  
  164. TimeOuts.ReadIntervalTimeout=MAXDWORD;  
  165. TimeOuts.ReadTotalTimeoutMultiplier=0;  
  166. TimeOuts.ReadTotalTimeoutConstant=0;  
  167. //在读一次输入缓冲区的内容后读操作就立即返回,  
  168. //而不管是否读入了要求的字符。  
  169.  
  170. //设定写超时  
  171. TimeOuts.WriteTotalTimeoutMultiplier=100;  
  172. TimeOuts.WriteTotalTimeoutConstant=500;  
  173. SetCommTimeouts(hCom,&TimeOuts);        //设置超时  
  174.  
  175. DCB dcb;  
  176. GetCommState(hCom,&dcb);  
  177. dcb.BaudRate=9600;                      //波特率为9600  
  178. dcb.ByteSize=8;                         //每个字节有8位  
  179. dcb.Parity=NOPARITY;                    //无奇偶校验位  
  180. dcb.StopBits=TWOSTOPBITS;               //两个停止位  
  181. SetCommState(hCom,&dcb);  
  182.  
  183. PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);  
  184.    
  185. //分别双击IDC_SEND按钮和IDC_RECEIVE按钮,添加两个按钮的响应函数:  
  186.  
  187. void CRS485CommDlg::OnSend()   
  188. {  
  189.     // TODO: Add your control notification handler code here  
  190.     OVERLAPPED m_osWrite;  
  191.     memset(&m_osWrite,0,sizeof(OVERLAPPED));  
  192.     m_osWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);  
  193.  
  194.     char lpOutBuffer[7];  
  195.     memset(lpOutBuffer,''\0'',7);  
  196.     lpOutBuffer[0]=''\x11'';  
  197.     lpOutBuffer[1]=''0'';  
  198.     lpOutBuffer[2]=''0'';  
  199.     lpOutBuffer[3]=''1'';  
  200.     lpOutBuffer[4]=''0'';  
  201.     lpOutBuffer[5]=''1'';  
  202.     lpOutBuffer[6]=''\x03'';  
  203.  
  204.     DWORD dwBytesWrite=7;  
  205.     COMSTAT ComStat;  
  206.     DWORD dwErrorFlags;  
  207.     BOOL bWriteStat;  
  208.     ClearCommError(hCom,&dwErrorFlags,&ComStat);  
  209.     bWriteStat=WriteFile(hCom,lpOutBuffer,  
  210.     dwBytesWrite,& dwBytesWrite,&m_osWrite);  
  211.  
  212.     if(!bWriteStat)  
  213.     {  
  214.         if(GetLastError()==ERROR_IO_PENDING)  
  215.         {  
  216.             WaitForSingleObject(m_osWrite.hEvent,1000);  
  217.         }  
  218.     }  
  219.  
  220. }  
  221.  
  222. void CRS485CommDlg::OnReceive()   
  223. {  
  224.     // TODO: Add your control notification handler code here  
  225.     OVERLAPPED m_osRead;  
  226.     memset(&m_osRead,0,sizeof(OVERLAPPED));  
  227.     m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);  
  228.  
  229.     COMSTAT ComStat;  
  230.     DWORD dwErrorFlags;  
  231.  
  232.     char str[100];  
  233.     memset(str,''\0'',100);  
  234.     DWORD dwBytesRead=100;//读取的字节数  
  235.     BOOL bReadStat;  
  236.  
  237.     ClearCommError(hCom,&dwErrorFlags,&ComStat);  
  238.     dwBytesRead=min(dwBytesRead, (DWORD)ComStat.cbInQue);  
  239.     bReadStat=ReadFile(hCom,str,  
  240.     dwBytesRead,&dwBytesRead,&m_osRead);  
  241.     if(!bReadStat)  
  242.     {  
  243.         if(GetLastError()==ERROR_IO_PENDING)    //GetLastError()函数返回ERROR_IO_PENDING,表明串口正在进行读操作  
  244.         {  
  245.             WaitForSingleObject(m_osRead.hEvent,2000);  
  246.             //使用WaitForSingleObject函数等待,直到读操作完成或延时已达到2秒钟  
  247.             //当串口读操作进行完毕后,m_osRead的hEvent事件会变为有信号  
  248.         }  
  249. }  
  250.  
  251.     PurgeComm(hCom, PURGE_TXABORT|  
  252.     PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);  
  253.     m_disp=str;  
  254.     UpdateData(FALSE);  
  255. }  
  256.  
  257. //打开ClassWizard,为静态文本框IDC_DISP添加CString类型变量m_disp,同时添加WM_CLOSE的相应函数:  
  258.  
  259. void CRS485CommDlg::OnClose()   
  260. {  
  261.     // TODO: Add your message handler code here and/or call default  
  262.     CloseHandle(hCom);      //程序退出时关闭串口  
  263.     CDialog::OnClose();  
  264. }  
  265.  
  266.  
  267. //您可以仔细对照这两个例程,细心体会串口同步操作和异步操作的区别。 

 

你可能感兴趣的:(职场,休闲,同步通讯,串口异步)