papa123

papa123

0个粉丝

41

问答

0

专栏

11

资料

papa123  发布于  2008-08-27 23:16:57
采纳率 0%
41个问答
5069

串口发送数据的程序vc实现

给你一个api的例子吧:   
   
  ⑴.在中mainfrm.cpp定义全局变量   
   
  handle    hcom;   //   准备打开的串口的句柄   
   
  handle    hcommwatchthread   ;//辅助线程的全局函数   
   
  ⑵.打开串口,设置串口   
   
  hcom   =createfile(   "com2",   generic_read   |   generic_write,   //   允许读写   
   
             0,          //   此项必须为0   
   
             null,           //   no   security   attrs   
   
             open_existing,    //设置产生方式   
   
             file_flag_overlapped,   //   我们准备使用异步通信   
   
             null   );   
   
  请大家注意,我们使用了file_flag_overlapped结构。这正是使用api实现非阻塞通信的关键所在。   
   
  assert(hcom!=invalid_handle_value);   //检测打开串口操作是否成功   
   
  setcommmask(hcom,   ev_rxchar|ev_txempty   );//设置事件驱动的类型   
   
  setupcomm(   hcom,   1024,512)   ;   //设置输入、输出缓冲区的大小   
   
  purgecomm(   hcom,   purge_txabort   |   purge_rxabort   |   purge_txclear   
   
               |   purge_rxclear   );   //清干净输入、输出缓冲区   
   
  commtimeouts   commtimeouts   ;   //定义超时结构,并填写该结构   
   
       …………   
   
  setcommtimeouts(   hcom,   &commtimeouts   )   ;//设置读写操作所允许的超时   
   
  dcb    dcb   ;   //   定义数据控制块结构   
   
  getcommstate(hcom,   &dcb   )   ;   //读串口原来的参数设置   
   
  dcb.baudrate   =9600;   dcb.bytesize   =8;   dcb.parity   =   noparity;   
   
  dcb.stopbits   =   onestopbit   ;dcb.fbinary   =   true   ;dcb.fparity   =   false;   
   
  setcommstate(hcom,   &dcb   )   ;   //串口参数配置   
   
  上述的commtimeouts结构和dcb都很重要,实际工作中需要仔细选择参数。   
   
  ⑶启动一个辅助线程,用于串口事件的处理。   
   
  windows提供了两种线程,辅助线程和用户界面线程。区别在于:辅助线程没有窗口,所以它没有自己的消息循环。但是辅助线程很容易编程,通常也很有用。   
   
  在次,我们使用辅助线程。主要用它来监视串口状态,看有无数据到达、通信有无错误;而主线程则可专心进行数据处理、提供友好的用户界面等重要的工作。   
   
  hcommwatchthread=   
   
         createthread(   (lpsecurity_attributes)   null,   //安全属性   
   
             0,//初始化线程栈的大小,缺省为与主线程大小相同   
   
             (lpthread_start_routine)commwatchproc,   //线程的全局函数   
   
             getsafehwnd(),   //此处传入了主框架的句柄   
   
             0,   &dwthreadid   );   
   
    assert(hcommwatchthread!=null);   
   
  ⑷为辅助线程写一个全局函数,主要完成数据接收的工作。   
   
  请注意overlapped结构的使用,以及怎样实现了非阻塞通信。   
   
  uint   commwatchproc(hwnd   hsendwnd){   
   
    dword   dwevtmask=0   ;   
   
    setcommmask(   hcom,   ev_rxchar|ev_txempty   );//有哪些串口事件需要监视?   
   
    waitcommevent(   hcom,   &dwevtmask,   os   );//   等待串口通信事件的发生   
   
    检测返回的dwevtmask,知道发生了什么串口事件:   
   
    if   ((dwevtmask   &   ev_rxchar)   ==   ev_rxchar){   //   缓冲区中有数据到达   
   
    comstat   comstat   ;   dword   dwlength;   
   
    clearcommerror(hcom,   &dwerrorflags,   &comstat   )   ;   
   
    dwlength   =   comstat.cbinque   ;   //输入缓冲区有多少数据?   
   
    if   (dwlength   >   0)   {   
   
  bool   freadstat   ;     
   
    freadstat   =   readfile(   hcom,   lpbuffer,dwlength,   &dwbytesread,   
   
              &read_os(   npttyinfo   )   );   //读数据   
   
  注:我们在crearefile()时使用了file_flag_overlapped,现在readfile()也必须使用   
   
    lpoverlapped结构.否则,函数会不正确地报告读操作已完成了.   
   
      使用lpoverlapped结构,   readfile()立即返回,不必等待读操作完成,实现非阻塞   
   
      通信.此时,   readfile()返回false,   getlasterror()返回error_io_pending.   
   
  if   (!freadstat){   
   
       if   (getlasterror()   ==   error_io_pending){   
   
         while(!getoverlappedresult(hcom,   
   
           &read_os(   npttyinfo   ),   &   dwbytesread,   true   )){   
   
           dwerror   =   getlasterror();   
   
           if(dwerror   ==   error_io_incomplete)   continue;   
   
                 //缓冲区数据没有读完,继续   
   
           ……   ……         
   
       ::postmessage((hwnd)hsendwnd,wm_notifyprocess,0,0);//通知主线程,串口收到数据  }   
   
    所谓的非阻塞通信,也即异步通信。是指在进行需要花费大量时间的数据读写操作时,一旦调用readfile()、writefile(),   就能立即返回,而让实际的读写操作在后台运行;相反,如使用阻塞通信,则必须在读或写操作全部完成后才能返回。由于操作可能需要任意长的时间才能完成,于是问题就出现了。   
   
  非常阻塞操作还允许读、写操作能同时进行,在实际工作中非常有用。   
   
  要使用非阻塞通信,首先在createfile()时必须使用file_flag_overlapped;然后在   readfile()时lpoverlapped参数一定不能为null,接着检查函数调用的返回值,调用getlasterror(),看是否返回error_io_pending。如是,最后调用getoverlappedresult()返回重叠操作(overlapped   operation)的结果;writefile()的使用类似。   
   
  ⑸.在主线程中发送下行命令。   
   
  bool  fwritestat   ;   char   szbuffer[count];   
   
           …………//准备好发送的数据,放在szbuffer[]中   
   
  fwritestat   =   writefile(hcom,   szbuffer,   dwbytestowrite,   
   
               &dwbyteswritten,   &write_os(   npttyinfo   )   );   //写数据   
   
  注:我们在crearefile()时使用了file_flag_overlapped,现在writefile()也必须使用     lpoverlapped结构.否则,函数会不正确地报告写操作已完成了.   
   
       使用lpoverlapped结构,writefile()立即返回,不必等待写操作完成,实现非阻塞   通信.此时,   writefile()返回false,   getlasterror()返回error_io_pending.   
   
  int   err=getlasterror();   
   
  if   (!fwritestat)   {   
   
       if(getlasterror()   ==   error_io_pending){   
   
      while(!getoverlappedresult(hcom,   &write_os(   npttyinfo   ),   
   
               &dwbyteswritten,   true   ))   {   
   
        dwerror   =   getlasterror();   
   
        if(dwerror   ==   error_io_incomplete){   
   
               //   normal   result   if   not   finished   
   
          dwbytessent   +=   dwbyteswritten;   continue;   }   
   
  
发表者:delphihero
回车用   /r/n   表示;如果用mscomm   控件也很简单   
  如果你还没有下载源程序,又对本文有兴趣,请   立即下载     
         
  1.建立项目:打开vc++6.0,建立一个基于对话框的mfc应用程序scommtest;   
   
  2.在项目中插入mscomm控件       选择project菜单下add   to   project子菜单中的   components   and   controls…选项,在弹出的对话框中双击registered   activex   controls项,则所有注册过的activex控件出现在列表框中。   选择microsoft   communications   control,   version   6.0,,单击insert按钮将它插入到我们的project中来,接受缺省的选项。,   
   
  这时在classview视窗中就可以看到cmscomm类了,,并且在控件工具栏controls中出现了电话图标,现在要做的是用鼠标将此图标拖到对话框中,程序运行后,这个图标是看不到的。   
   
   
   
  3.利用classwizard定义cmscomm类控制对象     打开classwizard->member   viariables选项卡,选择cscommtestdlg类,为idc_mscomm1添加控制变量:m_ctrlcomm,这时你可以看一看,在对话框头文件中自动加入了//{{afx_includes()     #include   "mscomm.h"     //}}afx_includes   。   
   
  4.在对话框中添加控件     向主对话框中添加两个编辑框,一个用于接收显示数据id为idc_edit_rxdata,另一个用于输入发送数据,id为idc_edit_txdata,再添加一个按钮,功能是按一次就把发送编辑框中的内容发送一次,将其id设为idc_button_manualsend。别忘记了将接收编辑框的properties->styles中把miltiline和vertical   scroll属性选上,发送编辑框若你想输入多行文字,也可选上miltiline。   
   
  再打开classwizard->member   viariables选项卡,选择cscommtestdlg类,   为idc_edit_rxdata添加cstring变量m_strrxdata,   为idc_edit_txdata添加cstring变量m_strtxdata。说明:   m_strrxdata和m_strtxdata分别用来放入接收和发送的字符数据。   
                  
  5.添加串口事件消息处理函数oncomm()   打开classwizard->message   maps,选择类cscommtestdlg,选择idc_mscomm1,双击消息oncomm,将弹出的对话框中将函数名改为oncomm,ok。   
   
    这个函数是用来处理串口消息事件的,如每当串口接收到数据,就会产生一个串口接收数据缓冲区中有字符的消息事件,我们刚才添加的函数就会执行,我们在oncomm()函数加入相应的处理代码就能实现自已想要的功能了。请你在函数中加入如下代码:   
   
  void   cscommtestdlg::oncomm()     
  {   
          //   todo:   add   your   control   notification   handler   code   here   
          variant   variant_inp;   
          colesafearray   safearray_inp;   
          long   len,k;   
          byte   rxdata[2048];   //设置byte数组   an   8-bit   integerthat   is   not   signed.   
          cstring   strtemp;   
          if(m_ctrlcomm.getcommevent()==2)   //事件值为2表示接收缓冲区内有字符   
          {                           ////////以下你可以根据自己的通信协议加入处理代码   
                  variant_inp=m_ctrlcomm.getinput();   //读缓冲区   
                  safearray_inp=variant_inp;   //variant型变量转换为colesafearray型变量   
                  len=safearray_inp.getonedimsize();   //得到有效数据长度   
                  for(k=0;k                           safearray_inp.getelement(&k,rxdata+k);//转换为byte型数组   
                  for(k=0;k                   {   
                          byte   bt=*(char*)(rxdata+k);   //字符型   
                          strtemp.format("%c",bt);   //将字符送入临时变量strtemp存放   
                          m_strrxdata+=strtemp;   //加入接收编辑框对应字符串     
                  }   
          }   
          updatedata(false);   //更新编辑框内容   
  }   
   
   
  到目前为止还不能在接收编辑框中看到数据,因为我们还没有打开串口,但运行程序不应该有任何错误,不然,你肯定哪儿没看仔细,因为我是打开vc6对照着做一步写一行的,运行试试。没错吧?那么做下一步:   
   
  6.打开串口和设置串口参数     你可以在你需要的时候打开串口,例如在程序中做一个开始按钮,在该按钮的处理函数中打开串口。现在我们在主对话框的cscommtestdlg::oninitdialog()打开串口,加入如下代码:   
   
  //   todo:   add   extra   initialization   here   
  if(m_ctrlcomm.getportopen())   
  m_ctrlcomm.setportopen(false);   
   
  m_ctrlcomm.setcommport(1);   //选择com1   
  if(   !m_ctrlcomm.getportopen())   
  m_ctrlcomm.setportopen(true);//打开串口   
  else   
  afxmessagebox("cannot   open   serial   port");   
   
  m_ctrlcomm.setsettings("9600,n,8,1");   //波特率9600,无校验,8个数据位,1个停止位     
   
  m_ctrlcomm.setinputmodel(1);   //1:表示以二进制方式检取数据   
  m_ctrlcomm.setrthreshold(1);     
  //参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的oncomm事件   
  m_ctrlcomm.setinputlen(0);   //设置当前接收区数据长度为0   
  m_ctrlcomm.getinput();//先预读缓冲区以清除残留数据   
   
   
  现在你可以试试程序了,将串口线接好后,打开串口调试助手,并将串口设在com2,选上自动发送,也可以等会手动发送。再执行你编写的程序,接收框里应该有数据显示了。   
   
  7.发送数据     先为发送按钮添加一个单击消息即bn_clicked处理函数,打开classwizard->message   maps,选择类cscommtestdlg,选择idc_button_manualsend,双击bn_clicked添加onbuttonmanualsend()函数,并在函数中添加如下代码:   
   
  void   cscommtestdlg::onbuttonmanualsend()     
  {   
  //   todo:   add   your   control   notification   handler   code   here   
  updatedata(true);   //读取编辑框内容   
  m_ctrlcomm.setoutput(colevariant(m_strtxdata));//发送数据   
  }   
   
  运行程序,在发送编辑框中随意输入点什么,单击发送按钮,啊!看看,在另一端的串口调试助手接收框里出现了什么。   
   
  最后说明一下,由于用到vc控件,在没有安装vc的计算机上运行时要从vc中把mscomm32.ocx、msvcrt.dll、mfc42.dll拷到windows目录下的system子目录中
我来回答
回答0个
时间排序
认可量排序
易百纳技术社区暂无数据
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
相关问答
无更多相似问答 去提问
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区