`

(一) 串口通信程序设计步骤详述

阅读更多
1.建立项目 
2.在项目中插入MSComm控件

3.利用ClassWizard定义CMSComm类控制变量

4.在对话框中添加控件 

5.添加串口事件消息处理函数OnComm()

6.打开和设置串口参数

7.发送数据

8.发送十六进制字符

9.在接收框中以十六进制显示

10.如何设置自动发送

11.什么是VARIANT数据类型?如何使用VARIANT数据类型?



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中来,接受缺省的选项。(如果你在控件列表中看不到Microsoft Communications Control, version 6.0,那可能是你在安装VC6时没有把ActiveX一项选上,重新安装VC6,选上ActiveX就可以了),这时在ClassView视窗中就可以看到CMSComm类了,(注意:此类在ClassWizard中看不到,重构clw文件也一样),并且在控件工具栏Controls中出现了电话图标(如图1所示),现在要做的是用鼠标将此图标拖到对话框中,程序运行后,这个图标是看不到的。

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<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; //加入接收编辑框对应字符串

        }

    }

    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.SetInputMode(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子目录中(win2000为System32)并再进行注册设置,请参考

8.发送十六进制字符

    在主对话框中加入一个复选接钮,ID为IDC_CHECK_HEXSEND Caption: 十六进制发送,再利用ClassWizard为其添加控制变量:m_ctrlHexSend;

    在Classview中为SCommTestDlg类添加以下两个PUBLIC成员函数,并输入相应代码;//由于这个转换函数的格式限制,在发送框中的十六制字符应该每两个字符之间插入一个空隔//如:A1 23 45 0B 00 29//CByteArray是一个动态字节数组,可参看MSDN帮助

int CSCommTestDlg::String2Hex(CString str, CByteArray &senddata)

{

int hexdata,lowhexdata;

int hexdatalen=0;

int len=str.GetLength();

senddata.SetSize(len/2);

for(int i=0;i<len;)

{

char lstr,hstr=str[i];

if(hstr==' ')

{

i++;

continue;

}

i++;

if(i>=len)

break;

lstr=str[i];

hexdata=ConvertHexChar(hstr);

lowhexdata=ConvertHexChar(lstr);

if((hexdata==16)||(lowhexdata==16))

break;

else

hexdata=hexdata*16+lowhexdata;

i++;

senddata[hexdatalen]=(char)hexdata;

hexdatalen++;

}

senddata.SetSize(hexdatalen);

return hexdatalen;

}

//这是一个将字符转换为相应的十六进制值的函数,好多C语言书上都可以找到

//功能:若是在0-F之间的字符,则转换为相应的十六进制字符,否则返回-1

char CSCommTestDlg::ConvertHexChar(char ch)

{

if((ch>='0')&&(ch<='9'))

return ch-0x30;

else if((ch>='A')&&(ch<='F'))

return ch-'A'+10;

else if((ch>='a')&&(ch<='f'))

return ch-'a'+10;

else return (-1);

}

再将CSCommTestDlg::OnButtonManualsend()修改成以下形式:

void CSCommTestDlg::OnButtonManualsend()

{

// TODO: Add your control notification handler code here

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

if(m_ctrlHexSend.GetCheck())

{

CByteArray hexdata;

int len=String2Hex(m_strTXData,hexdata); //此处返回的len可以用于计算发送了多少个十六进制数

m_ctrlComm.SetOutput(COleVariant(hexdata)); //发送十六进制数据

}

else

m_ctrlComm.SetOutput(COleVariant(m_strTXData));//发送ASCII字符数据

}

现在,你先将串口线接好并打开串口调试助手V2.1,选上以十六制显示,设置好相应串口,然后运行我们这个程序,在发送框中输入00 01 02 03 A1 CC等十六进制字符,并选上以十六进制发送,单击手动发送,在串口调试助手的接收框中应该可以看到00 01 02 03 A1 CC了。

9.在接收框中以十六进制显示

    这就容易多了:在主对话框中加入一个复选接钮,IDC_CHECK_HEXDISPLAY, Caption: 十六进制显示,再利用ClassWizard为其添加控制变量:m_ctrlHexDisplay。 然后修改CSCommTestDlg::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); //字符型

if(m_ctrlHexDisplay.GetCheck())

strtemp.Format("%02X ",bt); //将字符以十六进制方式送入临时变量strtemp存放,注意这里加入一个空隔

else

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

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

}

}

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

}

测试:在串口调试助手发送框中输入00 01 02 03 A1 CC等十六进制字符,并选上以十六进制发送,单击手动发送,在本程序运行后选上以十六进制显示,在串口调试助手中单击手动发送或自动发送,则在本程序的接收框中应该可以看到00 01 02 03 A1 CC了。

10.如何设置自动发送

     最简单的设定自动发送周期是用SetTimer()函数,这在数据采集中很有用,在控制中指令的传送也可能用到定时发送。方法是:在ClassWizard中选上MessageMap卡,然后在Objects IDs选中CSCommTestDlg类,再在Messages框中选上WM_TIMER消息,单击ADD_FUNCTION加入void CSCommTestDlg::OnTimer(UINT nIDEvent) 函数,这个函数是放入“时间到”后要处理的代码:

void CSCommTestDlg::OnTimer(UINT nIDEvent)

{

// TODO: Add your message handler code here and/or call default

OnButtonManualsend();

CDialog::OnTimer(nIDEvent);

}

再在在主对话框中加入一个复选接钮,ID为IDC_CHECK_AUTOSEND Caption: 自动发送(

周期1秒),再利用ClassWizard为其添加BN_CLICK消息处理函数void

CSCommTestDlg::OnCheckAutosend():

void CSCommTestDlg::OnCheckAutosend()

{

// TODO: Add your control notification handler code here

m_bAutoSend=!m_bAutoSend;

if(m_bAutoSend)

{

SetTimer(1,1000,NULL);//时间为1000毫秒

}

else

{

KillTimer(1);  //取消定时

}

}

其中:m_bAutoSend为BOOL型变量,在CLASSVIEW中为CSCommTestDlg类加入,并在构造函数中初始化:

      m_bAutoSen=FALSE;

现在可以运行程序测试了。

11.什么是VARIANT数据类型?如何使用VARIANT数据类型?

     不知如何使用VARIANT数据类型, 有不少朋友对VARIANT这个新的数据类型大感头疼。SetOutput()函数中需要的VARIANT参数还可以使用COleVariant类的构造函数简单生成,现在GetInput()函数的返回值也成了VARIANT类型,那么如何从返回的值中提取有用的内容。 VARIANT及由之而派生出的COleVariant类主要用于在OLE自动化中传递数据。实际上VARIANT也只不过是一个新定义的结构罢了,它的主要成员包括一个联合体及一个变量。该联合体由各种类型的数据成员构成, 而该变量则用来指明联合体中目前起作用的数据类型。我们所关心的接收到的数据就存储在该联合体的某个数据成员中。 该联合体中包含的数据类型很多,从一些简单的变量到非常复杂的数组和指针。由于通过串口接收到的内容常常是一个字节串,我们将使用其中的某个数组或指针来访问接收到的数据。这里推荐给大家的是指向一个SAFEARRAY(COleSafeArray)类型变量。新的数据类型SAFEARRAY正如其名字一样,是一个“安全数组”,它能根据系统环境自动调整其16位或32 位的定义,并且不会被OLE改变(某些类型如BSTR在16位或32位应用程序间传递时会被OLE翻译从而破坏其中的二进制数据)。大家无须了解SAFEARRAY的具体定义,只要知道它是另外一个结构,其中包含一个 (void *)类型的指针pvData,其指向的内存就是存放有用数据的地方。 简而言之,从GetInput()函数返回的VARIANT类型变量中,找出parray 指针,再从该指针指向的SAFEARRAY变量中找出pvData指针,就可以向访问数组一样取得所接收到的数据了。具体应用请参见void CSCommTestDlg::OnComm()函数。

    大概我现在也说不清这个问题,我自己从第一次接触这个东西,到现在还是给别人讲不清。
分享到:
评论

相关推荐

    C#写的串口通信程序

    这样的程序设计,使得非程序员也能轻松配置和使用串口通信功能。 程序的使用步骤大致如下: 1. **初始化串口**:实例化`SerialPort`对象,设置串口号(如"COM1"),并根据需求配置波特率(如9600)、数据位(如8位...

    用单机实现双机串行通信的调试方法.pdf

    本文将详述如何使用单机模拟双机串行通信的调试方法,这对于理解和开发相关应用至关重要。 首先,理解串行通信的基本原理是必要的。串行通信是指数据逐位按顺序传输,与并行通信(数据多位同时传输)相比,它占用的...

    把单片机串口通讯改造为SPI通讯接口源程序

    串口通讯,即UART,是一种简单、通用的异步串行通信协议,常用于设备间的短距离通信。它通过数据线发送和接收数据,通常包括TX(发送)和RX(接收)两根线。而SPI是一种同步串行通信协议,适用于主设备与一个或多个...

    参考资料-基于虚拟仿真软件的单片机串行通信系统设计.zip

    6. **项目实践指南**:提供一个完整的串行通信系统设计案例,包括需求分析、硬件选型、软件设计、虚拟仿真测试等步骤,帮助读者实践所学知识。 通过学习这个资料,读者不仅能理解单片机串行通信的基本原理,还能...

    基于RS232modbus协议的双机串行通信.doc

    设计基于RS232 Modbus协议的双机串行通信系统时,需要考虑主从机的通信流程,包括主机发送请求、从机接收并处理请求、从机响应、主机接收响应等步骤。同时,硬件和软件设计必须兼容Modbus协议,以实现可靠的通信。 ...

    HAL库STM32F407:Uart串口通信实验-程序源码

    接下来,我们详述如何使用STM32CubeMX配置Uart串口通信: 1. 启动STM32CubeMX,导入或创建一个新的项目,选择STM32F407VET6作为目标MCU。 2. 在“Peripheral”(外设)选项卡下,找到并展开“UART”部分。勾选需要...

    51单片机与PC串口通讯.pdf

    《51单片机与PC串口通讯》的文档详细阐述了如何实现51单片机与个人计算机(PC)之间的串行通信。串口通讯是电子工程领域中一种常见且重要的通信方式,尤其在嵌入式系统和微控制器应用中。以下是该文档可能涵盖的关键...

    实验单片机与PC机串口通信

    知识点详述: ### 实验单片机与PC机串口通信 #### 1. 串行口的控制与状态寄存器SCON 在实验单片机与PC机的...通过上述步骤,可以有效地测试和验证单片机与PC机之间的串口通信功能,确保数据传输的准确性和稳定性。

    欧姆龙CP2E与基恩士SR700通讯

    RS-232C是一种古老的串行通信接口标准,尽管在现代高速通信技术的冲击下,但在工业控制应用中仍然有着广泛的应用。 欧姆龙CP2E系列PLC是一款经济型小型控制器,适用于各种工业自动化场合。它具有丰富的I/O点数,...

    stm32串口通信入门.docx

    - **串行通信定义**:串行通信是一种逐位发送数据的通信方式,相较于并行通信而言,其主要优点是只需要少数几根线即可完成通信,简化了电路设计。 - **串行通信分类**: - **异步通信**:每个字符前后分别有起始位...

    《USART串口编程》.pdf

    - **定义**: 串行通信接口(Serial Communication Interface),通常简称为串口(Serial Port),是一种用于实现计算机与计算机或其他设备之间数据传输的技术。在本教程中主要关注的是**USART**(Universal ...

    C51单片机和电脑串口通信电路图与源码.pdf

    此外,文中还提及了一个更复杂的程序,用于接收电脑传来的数据并在数码管上显示,但在此不再详述,因为主要关注的是C51单片机如何与电脑进行串口通信的基础知识。 总结起来,C51单片机与电脑的串口通信涉及电平转换...

    基于FX_BD的串口通信动态链接库

    首先,FX_BD是一种专门针对三菱FX系列PLC设计的串口通信协议。它允许用户通过计算机或其他设备与PLC进行数据交互,实现远程监控、编程、数据采集等功能。动态链接库(DLL)则是一种共享代码的机制,可以被多个程序...

    A/D转换器CS5550与单片机的接口程序设计.pdf

    对于ATmegal6单片机,其内建的SPI接口是一个常用的串行通信接口,支持主模式和从模式,可以实现全双工通信。在与CS5550的连接中,ATmegal6的MOSI(主设备输出,从设备输入)线对应CS5550的SDI,MISO(主设备输入,从...

    51单片机与PC的RS232接口串行通信实现研究-.docx

    本文主要探讨了如何利用51系列单片机与个人计算机(PC)通过RS232接口进行串行通信的设计与实现。RS232接口是早期广泛应用于数据通信的标准,其在各种设备间的通信中扮演了重要角色,尽管现代技术已经发展出更快的...

    单片机原理与应用及C51程序设计课件电子教案.zip

    5. **第五章 MCS-51单片机内部资源及编程.ppt**:详述MCS-51单片机的内部资源,如定时器/计数器、中断系统、串行通信接口等,并讲解如何利用这些资源进行编程。 6. **第六章 CS-51单片机系统扩展.ppt**:讲述如何...

    AVR单片机GCC程序设计

    ### AVR单片机GCC程序设计知识点详述 #### 一、AVR单片机GCC开发概述 ##### 1.1 AVR单片机介绍 - **诞生背景**:1997年,ATMEL公司挪威设计中心的两位工程师基于市场需求推出了一种全新的8位精简指令集微处理器...

    单片机解读GPS信息的程序设计

    在单片机中接收GPS数据,首先需要通过串行通信接口(如UART)来读取数据。文章中的代码示例通过中断服务函数`GetRs232_Data()`来实现这一功能。当接收缓冲区中的数据准备好后,该函数会检查接收到的第一个字符是否为...

    java程序调用串口硬件注册服务 exe4j rxtxSerial.dll 网页调用

    `RXTX`是一个开源的Java库,它提供了对串行通信的API,使得Java程序员可以方便地操作串口。在本例中,`mfz-rxtx-2.2-20081207-win-x86x64`就是`RXTX`库的一个版本,适用于Windows平台的32位和64位系统。`rxtxSerial....

    串口协议简要概述.pdf

    **串行通信** 指的是数据以串行的形式在一个通信线路上进行传输的过程。这种方式与并行通信相比,具有明显的优点: - **传输线路少**:只需要一条线路即可完成数据传输,简化了硬件设计。 - **传输距离远**:相较于...

Global site tag (gtag.js) - Google Analytics