原创 VC上位机For51编写过程

2010-9-15 15:47 5106 16 21 分类: MCU/ 嵌入式

注(部分图片没有显示,请下载附件)


VC上位机For51


 


济南职业学院 电子工程系 朱志强


                               2010年8月17日


 


 


 


 


 


概述:此文章作为学习上位机的复习资料和总结性资料。是《VC++MSComm串口接收程序制做》的后继制作,在前文的基础上添加了部分新的功能,可以实现接收十六进制单个字符。但是还是没有完成上位机对下位机的发送。对于图片的应用和静态文本的更换,这此也没有解决。


第一步制作上位机程序,参考《VC++MSComm串口接收程序制做》。步骤如下:新建一个基于对话框的程序,全部选择默认选项。得到如下的对话框。



图1 新创建的对话框


我们去掉上面的所有的控件,向工程中添加入MSCOMM控件,添加变量为m_ctrlComm。再添加一个编辑框,作为接收框,使用类向导添加变量为m_strRXData。同时,我们也给对话框添加上最小化按钮(方法:右键对话框,属性,样式里勾选上最小化按钮)。双击MSCOMM控件,添加入如下的代码:


void CFor51Dlg::OnOnCommMscomm1()


{


       // 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<len;k++)


                            safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组


                     for(k=0;k<len;k++) //将数组转换为Cstring型变量


                     {


                            BYTE bt=*(char*)(rxdata+k); //字符型


                            strtemp.Format("%02X",bt); //将字符送入临时变量strtemp存放


                            strtemp=" 按下的按钮编号是 "+strtemp+"\r\n";


                            m_strRXData+=strtemp; //加入接收编辑框对应字符串


                     }


    }


    UpdateData(FALSE); //更新编辑框内容


}


编译可以通过。下面我们就要为初始化串口做工作了。以前的程序,初始化的串口是死的,无法变化,我们在这里添加上一些其他控件来实现对串口的选择。在对话框上添加一个组框,在组框中添加5个单选按钮,标题为串口1~串口5。在右边添加上两个按钮,分别为打开串口,关闭串口。添加后如下图所示:



图2 接收部分控件图


我们给单选串口1添加属性“组”。这样我们编译一下,看看是否实现了单选的功能。打开类向导,给IDC_RADIO1添加成员变量int型m_portnum,用来记录我们选择的串口号是多少。使用类向导,找到CFor51Dlg,给IDC_RADIO1添加单击响应函数。代码如下:


void CFor51Dlg::OnRadio1()


{


       // TODO: Add your control notification handler code here


       m_portnum=1//标记为串口1


}


    其余的四个代码类似。只是给变量m_portnum一个对应串口号的值即可。


下面我们给“打开串口”按钮添加响应函数。思路是,首先判断是否选择的串口,然后,在引入串口号,初始化串口,最后打开串口。我们先来查看一下m_portnum的初值。如果你找不到的话可以在初始化对话框函数(BOOL CFor51Dlg::OnInitDialog())里给m_portnum赋一个0值。


CFor51Dlg::CFor51Dlg(CWnd* pParent /*=NULL*/)


       : CDialog(CFor51Dlg::IDD, pParent)


{


       //{{AFX_DATA_INIT(CFor51Dlg)


       m_strRXData = _T("");


       m_portnum = -1;


       //}}AFX_DATA_INIT


       // Note that LoadIcon does not require a subsequent DestroyIcon in Win32


       m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);


}


看到没?在上面地方中我们看到了系统初始化的值是-1。我们双击按钮,就可以添加按钮单击响应函数了。代码如下:


void CFor51Dlg::OnButton1()


{


       // TODO: Add your control notification handler code here


              if(m_portnum==(-1))


              AfxMessageBox("请选择端口号!");


       else


       {


              m_ctrlComm.SetCommPort(m_portnum); //


 


              if( !m_ctrlComm.GetPortOpen())


              {


                     m_ctrlComm.SetPortOpen(TRUE);//打开串口


                     AfxMessageBox("串口"+CString(m_portnum+48)+"已经打开!");


//由ASCII码表得到增加值为48


                     GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);   //打开按钮无效


                     GetDlgItem(IDC_BUTTON2)->EnableWindow(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();//先预读缓冲区以清除残留数据


       }


}


注意这句AfxMessageBox("串口"+CString(m_portnum+48)+"已经打开!");


输出的是字符串,我们查看了ASCII码表之后,找到了数字1和字符1的对应关系,加上48之后强制转换为字符格式输出。还有要注意的一点是数据的格式那句我们给注释掉了。我们


下面我们又想到了一个问题,那就是我们在刚开始的时候,没有打开串口,那么按理说关闭串口按钮是不能用的。那么我们就要让它不能用,初始化后禁止它!我们在对话框初始化函数中添加上GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);   //关闭按钮无效


       就可以了。实现的效果如下所示。


 


图3 禁止关闭按钮和串口打开提示


我们此时已经看出,打开串口按钮的函数中,就有了使能关闭串口按钮,并禁止自身的代码了。我们只需给关闭串口按钮添加如下的代码:


void CFor51Dlg::OnButton2()


{


       // TODO: Add your control notification handler code here


       m_ctrlComm.SetPortOpen(FALSE);//关闭串口


       GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);   //关闭按钮无效


       GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);    //打开按钮无效


       //m_portnum=-1;


       if( !m_ctrlComm.GetPortOpen())


              AfxMessageBox("串口已经关闭");


}


我们就可以实现手动打开和关闭串口了。但是我在随后的测试时,出现了下面的错误,提示说串口已经被打开了,而实际上我并没有打开串口。我们的这个程序应该首先判断一下串口是否打开了,如果是打开了,我们提前关闭它。把这段程序放哪比较好呢?当然是对话框初识话的时候最好了啊。我们在对话框初识话函数中添加如下的代码:


       if(m_ctrlComm.GetPortOpen())    //如果串口打开,则关闭


       m_ctrlComm.SetPortOpen(FALSE);



图4 打开串口时出现的错误


添加上这些代码之后,我们在重新编译一下。最后使用下位机发送字符测试得到了下面的结果:



图5 第一次运行时出现的效果


我们发现了俩个BUG,首先是我们的数据没有换行。我们看看程序,找到了有关于这部分的代码如下:



图6 检查输入字符


我们看到我们在程序中添加上了“\r\n”,所以错误不在这。哦,是我们没有设置编辑框的属性。现在我们勾上“多行”和“垂直滚动”、“自动垂直滚动”就可以了。


(注:\r 是回车换行 \n 为另起一行输出)


    还有一个BUG是我们使用的明明是串口4,可是在串口接收完数据之后,却变成了串口5。是我们通信的时候影响到了单选的标志m_portnum。所以我们直接去掉这个‘善变的’单选变量。打开类向导,删除IDC_RADIO1的成员变量m_portnum。编译后有一个错误,说是没有定义m_portnum,因为我们本来是在对户框界面使用类向导添加的变量,这个变量系统会给他自动做初始化处理。那么我们就在头文件(上位机For51Dlg.h)中定义一个int型的变量m_portnum。然后在对话框初始化函数中添加初始化代码m_portnum=0; 同时我们也要修改相应的打开串口判断函数。



图7 在头文件中定义变量m_portnum



图8 在对话框初始化函数中初始化m_portnum



图9 重新判断m_portnum


这样处理之后,我们在编译运行,测试一次就没有了上面的两个错误了。


    下面我们在给对话框添加一个按钮,标题为清空接收区。添加如下的响应代码。


void CFor51Dlg::OnButton3()


{


       // TODO: Add your control notification handler code here


       CString qingkong;


       m_strRXData=qingkong;              //清空编辑框


       GetDlgItem(IDC_EDIT1)->SetWindowText("清空完毕!");     //显示清空完毕


}


我们是创建了一个新的CString类的变量,初始化的值为空,我们把它赋值给m_strRXData,使得m_strRXData也变为空。效果如下:



图10 显示清空的效果


现在我们在添加上发送按钮和发送编辑框。给IDC_EDIT2添加变量m_data。给发送按钮添加响应函数如下:


void CFor51Dlg::OnButton4()


{


       // TODO: Add your control notification handler code here


       UpdateData(TRUE);//读取编辑框的内容


       if(m_data.IsEmpty())


       {


              AfxMessageBox("发送不能为空!!!");


 


       }


       m_ctrlComm.SetOutput(COleVariant(m_data));


}


这个上位机就开发出来了,显示的效果如下:



图11 最后的测试


    串口上接了一个51单片机开发板,但是没有上电,这样,就实现了自己发送,自己接受的目的,图中发送的是字符1,显示区显示的是字符1的十六进制的ASCII码。所以要在下位机的程序中添加一段转换码。将字符转换成十六进制的数据。这样就实现了单个数据的发送和接收了。


 

PARTNER CONTENT

文章评论5条评论)

登录后参与讨论

用户445904 2013-8-21 09:23

很好 实用

用户430277 2012-10-26 12:56

ok

512826028 2011-11-21 18:35

额 我好像回来的晚了啊。不知你有什么要询问的啊?

用户359227 2011-7-17 22:39

麻烦了 麻烦了 速度加起 谢谢

用户359227 2011-7-17 22:36

怎么不行啊 麻烦加我QQ:359534308 便于沟通 谢谢
相关推荐阅读
512826028 2015-09-07 00:32
Discuz论坛插件开发资料留存区
这部分就是我用过的资料网站资源等等的汇总。   第一个插件开发 新手教程 http://www.cnblogs.com/upmyself/archive/2013/01/16/286339...
512826028 2015-09-06 21:39
学习Discuz论坛插件开发二
    使用filezille对指定的config文件修改之后,就在discuz论坛后台的插件里面看到了多了一项,就是我需要的 插件开发一项。点进去之后,系统会自动提示此功能仅限开发者使用。 ...
512826028 2015-09-06 20:53
学习Discuz论坛插件开发一
     接触Discuz论坛有几个月的时间了,最近感觉里面的插件很是让我激动,于是,鼓起勇气,开始学习一下怎么自己开发一下插件。       首先接触插件学习,看的是Discuz论坛提供的插...
512826028 2015-09-06 20:27
正式开始蓝线技术,自己重新写博客
        由于CSDN博客很久没有使用,结果给我封了。就暂时把网络部分写这里了。后期会有单片机和蓝牙部分,以后也发表到这个板块里面了。   给自己打打气,加油!      至于啥...
512826028 2012-08-12 11:03
POV LED(我的新版旋转灯)二
  视频的播放地址 http://v.youku.com/v_show/id_XNDM4MTYyMjIw.html   2.       程序编写         首先,我还是想的...
512826028 2012-08-12 10:46
POV LED(我的新版旋转灯)三
由于我没有画电路图。所以,也没有什么电路图给大家看。电路很简单。LED电路使用共阳接法,串接的是330欧姆的电阻。电阻和LED的型号都是0805. 从最外圈向里数,依次是一个绿色LED灯(接P6口),...
EE直播间
更多
我要评论
5
16
关闭 站长推荐上一条 /3 下一条