Chinaunix首页 | 论坛 | 博客
  • 博客访问: 689222
  • 博文数量: 66
  • 博客积分: 2418
  • 博客等级: 大尉
  • 技术积分: 1659
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-28 10:04
个人简介

keep moving

文章分类

全部博文(66)

文章存档

2015年(2)

2014年(6)

2013年(7)

2011年(7)

2010年(42)

2009年(2)

分类: 嵌入式

2010-03-20 16:31:39

一、pc机上的串口通信编程过程如下:

打开VC++6.0,建立一个基于对话框的MFC应用程序SCommTest(与我源代码一致,等会你会方便一点);

  

选择Project菜单下Add To Project子菜单中的 Components and Controls…选项,在弹出的对话框中双击Registered ActiveX Controls项(稍等一会,这个过程较慢),则所有注册过的ActiveX控件出现在列表框中。 选择Microsoft Communications Control, version 6.0,,单击Insert按钮将它插入到我们的Project中来,接受缺省的选项。(如果你在控件列表中看不到Microsoft Communications Control, version 6.0,那可能是你在安装VC6时没有把ActiveX一项选上,重新安装VC6,选上ActiveX就可以了),

这时在ClassView视窗中就可以看到CMSComm类了,(注意:此类在ClassWizard中看不到,重构clw文件也一样),并且在控件工具栏Controls中出现了电话图标(如图1所示),现在要做的是用鼠标将此图标拖到对话框中,程序运行后,这个图标是看不到的。

 

打开ClassWizard->Member Viariables选项卡,选择CSCommTestDlg类,为IDC_MSCOMM1添加控制变量:m_ctrlComm,这时你可以看一看,在对话框头文件中自动加入了//{{AFX_INCLUDES()  #include "mscomm.h"  //}}AFX_INCLUDES (这时运行程序,如果有错,那就再从头开始)。

 

向主对话框中添加两个编辑框,一个用于接收显示数据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分别用来放入接收和发送的字符数据。

打开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<len;k++)
            safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组

        for(k=0;k<len;k++) //将数组转换为Cstring型变量
        {
            BYTE bt=*(char*)(rxdata+k); //字符型
            strtemp.Format("%c",bt); //将字符送入临时变量strtemp存放
            m_strRXData+=strtemp; //加入接收编辑框对应字符串 
        }
            m_strRXData+="\r\n"; //换行

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

}

 

 

 

 

 

 

 

 

 

 

 
 
 
 
 


 

 

 

 

到目前为止还不能在接收编辑框中看到数据,因为我们还没有打开串口,但运行程序不应该有任何错误,不然,你肯定哪儿没看仔细,因为我是打开VC6对照着做一步写一行的,运行试试。没错吧?那么做下一步:

 

你可以在你需要的时候打开串口,例如在程序中做一个开始按钮,在该按钮的处理函数中打开串口。现在我们在主对话框的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("2400,n,8,1"); //波特率2400,无校验,8个数据位,1个停止位 
    m_ctrlComm.SetInputMode(1); //1:表示以二进制方式检取数据
    m_ctrlComm.SetRThreshold(1);
    //参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件
    m_ctrlComm.SetInputLen(0); //设置当前接收区数据长度为0
    m_ctrlComm.GetInput();

现在你可以试试程序了,将串口线接好后(不会接?去看看我写的),打开,并将串口设在com2,选上自动发送,也可以等会手动发送。再执行你编写的程序,接收框里应该有数据显示了。

 

先为发送按钮添加一个单击消息即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));//发送数据    
}

 
 
二、单片机89C51串口通信的C语言程序:

 每当pc机通过串口向单片机发送一非0数据,单片机就通过串口向pc机发送数字0~9

#include "reg51.h"

//数码管字型码
unsigned int ds_code[18] = {0x3F,0x06,0x5B, //0,1,2
                            0x4F,0x66,0x6D, //3,4,5
                            0x7D,0x07,0x7F, //6,7,8
                            0x6F,0x77,0x7C, //9,A,B
                            0x39,0x5E,0x79, //C,D,E
                            0x71,0x76,0x73}; //F,H,P


//数码管控制端
sbit ds = P1^0;
//字型码锁存器74ls373的控制端LE
sbit ctrl373 = P3^7;
//要显示的数据
unsigned int dsData = 0;
//发送标志:标示是否向pc机发送数据
bit send = 0;

//数码管显示函数
void display(unsigned int Data)
{
    ctrl373 = 1;
    ds = 1;
    P2 = ds_code[Data];    
    ds = 0;
    ctrl373 = 0;
}

//串口中断函数
void serialPort() interrupt 4
{
    //循环的向pc机发送0~9
    if (TI == 1 && send == 1)    //发送数据
    {
        //清除发送中断申请标志
        TI = 0;
        send = 0;
        dsData++;
        if (dsData > 9)
        {
            dsData = 0;
        }

        //以ASCII方式发送数据
        SBUF = dsData + 48;
    }

    if (RI == 1)    //接收数据
    {
        //清除接收中断申请标志
        RI = 0;


        //接收到得数据为ASCII码形式,需做减8处理
        //若从pc机接收到一非0数据,就将send置1,向pc机发送1字节数据
        send = SBUF - 48;
    }
}

void main()
{
    EA = 1;         //打开总中断
    ES = 1;         //打开串口中断                                                                                    
    SCON = 0x52;    //串口工作方式1,允许接收,无校验,可发送数据
    TMOD = 0x20;    //定时器1工作方式2
    TH1 = 0xf3;
    TL1 = 0xf3;        //定时器1计数初值243,即串口波特率为2400bit/s
    TR1    = 1;        //启动定时器1

    while (1)
    {
        display(dsData);
    }
}

实验结果:

 

pc机上的串口通信编程过程完全参考于:
串口调试助手源程序及编程详细过程:http://blog.hellodsp.com/space.php?uid=32517&do=blog&id=1152

阅读(2942) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-11-27 20:22:27

该处http://blog.ednchina.com/shinep/82494/message.aspx存在不负责任的转载。请留意!

chinaunix网友2010-11-21 11:18:55

谢谢博主的资源^^ 我参照完成了上位机编程(成功打开串口2并利用串口调试助手验证收发正常)。之后进行了简单的单片机编程(输出单字符或字符串)并利用Proteus仿真(COMPIM元件绑定COM1)。结果出现异常:单片机输出ASCⅡ码1(十六进制0x31)时,上位机SCommTest数据接收区无任何数据;单片机输出字符串ASCⅡ码137(十六进制0x31 0x33 0x37)时,上位机SCommTest数据接收区却显示为gf MSComm控件InputMode为1 RThreshold为1(每接收一个字符就产生一个事件) Q1:这里的一个字符的位数是多少?单片机每送出8位,PC即认为是一个字符吗?这里PC中的一个字符的位数如何验证确定?通信异常的原因是否单片机和PC数据位数不一致导致?问题该如何解决? Q2:博主是如何验证该篇“pc机与89C51单片机的串口通信”的?是实物还是仿真验证? 呵呵,期待博主尽早帮我解惑^^Thanks...