目次:
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() #i nclude "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); // 以二进制方式检取数据
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_ctrlHexDiaplay。 然后修改 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_加入 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()函数。
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() #i nclude "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); // 以二进制方式检取数据
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_ctrlHexDiaplay。 然后修改 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_加入 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()函数。