串口调试助手代码分析42.docx

上传人:b****5 文档编号:5628167 上传时间:2022-12-29 格式:DOCX 页数:25 大小:96.24KB
下载 相关 举报
串口调试助手代码分析42.docx_第1页
第1页 / 共25页
串口调试助手代码分析42.docx_第2页
第2页 / 共25页
串口调试助手代码分析42.docx_第3页
第3页 / 共25页
串口调试助手代码分析42.docx_第4页
第4页 / 共25页
串口调试助手代码分析42.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

串口调试助手代码分析42.docx

《串口调试助手代码分析42.docx》由会员分享,可在线阅读,更多相关《串口调试助手代码分析42.docx(25页珍藏版)》请在冰豆网上搜索。

串口调试助手代码分析42.docx

串口调试助手代码分析42

第5章串口调试助手代码分析

1、建立基于对话框的工程SCOMM

2、绘制界面,如下图:

接收区

串口组合框:

IDC_COMBO_COMSELECT,m_Com

波特率组合框:

IDC_COMBO_SPEED,m_Speed

停止位组合框:

IDC_COMBO_STOPBITS,m_StopBits

数据位组合框:

IDC_COMBO_DATABITS,m_DataBits

校验位组合框:

IDC_COMBO_PARITY,m_Parity

十六进制显示(接收):

IDC_CHECK_HEXRECIEVE,m_ctrlHexReceieve

接收编辑框:

IDC_EDIT_RECIVE,m_ReceiveDatam_ctrlReceiveDataStyle:

VerticalScrollMultiLine

打开串口IDC_BUTTON_OPENPORT,m_ctrlOpenPort

串口开关标志图标IDC _STATIC_OPENOFF,m_ctrlIconOpenoff

数据文件保存路径IDC _EDIT_SAVEPATH,m_strCurPath

保存显示数据文件路径IDC _EDIT_SAVEPATH,m_ctrlSavePath

接收计数IDC_STATIC_RXCOUNT,m_ctrlRXCOUNT

发送区

…。

3、添加CSeraiPort类文件

将类文件SerialPort.hSerialPort.cpp复制到工程所在文件夹中(选择改进后的类),然后单击VC6.0菜单Projrct->AddtoProjrct->Files…,再在打开的文件选择对话框中选择SerialPort.h和SerialPort.cpp,点击OK,就把类文件加入当前工程,并在SCOMMDlg.h中加入头文件,#include"SerialPort.h",通过上述步骤就在当前工程中加入了CSeraiPort类。

4、完成串口消息处理函数OnCommunicatiom

在CserailPort类中有多个串口事件可以响应。

在一般串口编程中,只需要处理WM_COMM_RXCHAR消息就可以了,该类所有的消息均需要人工添加消息处理函数。

我们将处理函数名定义为OnComm()。

首先在SCOMMDlg.h中添加串口字符接收消息WM_COMM_RXCHAR(串口接收缓冲区内有一个字符)响应函数的声明:

如下图

然后,在SCOMMDlg.cpp文件中进行WM_COMM_RXCHAR消息映射:

如下图;

接着,在SCOMMDlg.cpp文件中加入函数OnCommunication(WPARAMch,LPARAMport)的实现,暂不添加代码。

LONGCSCOMMDlg:

:

OnCommunication(WPARAMch,LPARAMport)

{

return0;

}

以上步骤需要手工完成。

至此完成了程序的对话框模板,在工程中插入了串口操作类CserailPort类。

5、添加串口初始化及关闭

程序中有两种方法大开串口,一是程序启动,调用OnInitDialog()函数,就可以打开串口,缺省的串口号为COM1,如果COM1不存在或占用,就会给出提示;另外,单击“打开串口”按钮也可以打开串口。

//在初始化中打开串口

BOOLCSCOMMDlg:

:

OnInitDialog()

{

m_nBaud=9600;//波特率

m_nCom=1;//串口号

m_cParity='N';//奇偶校验

m_nDatabits=8;//数据位

m_nStopbits=1;//停止位

m_dwCommEvents=EV_RXFLAG|EV_RXCHAR;//串口事件

//if(m_Port.InitPort(this,1,9600,'N',8,1,dwCommEvents,512))

CStringstrStatus;

if(m_Port.InitPort(this,m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits,m_dwCommEvents,512))//如果启动串口成功

{

m_Port.StartMonitoring();//启动监测辅助线程

strStatus.Format("STATUS:

COM%dOPENED,%d,%c,%d,%d",m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits);//打印串口状态及参数

m_ctrlIconOpenoff.SetIcon(m_hIconRed);//设置串口状态灯

//m_ctrlIconOpenoff.SetIcon(m_hIconOff);

//"当前状态:

串口打开,无奇偶校验,8数据位,1停止位");

}

else//如果启动失败

{

AfxMessageBox("没有发现此串口");

m_ctrlIconOpenoff.SetIcon(m_hIconOff);

}

m_ctrlPortStatus.SetWindowText(strStatus);//显示串口的状态及参数

returnb;

}

6、在ClassWizard中为按钮“打开串口”控制IDC_BUTTON_OPENPORT添加单击响应函数。

//打开,关闭串口

voidCSCOMMDlg:

:

OnButtonOpenport()

{

//TODO:

Addyourcontrolnotificationhandlercodehere

m_bOpenPort=!

m_bOpenPort;//取反

if(m_bOpenPort)//如果串口是打开的

{

if(m_ctrlAutoSend.GetCheck())//检测自动发送标志是否打开

{

m_bOpenPort=!

m_bOpenPort;//恢复原来的标志

AfxMessageBox("请先关掉自动发送");

return;//返回

}

m_ctrlOpenPort.SetWindowText("打开串口");

m_Port.ClosePort();//关闭串口

m_ctrlPortStatus.SetWindowText("STATUS:

COMPortClosed");

m_ctrlIconOpenoff.SetIcon(m_hIconOff);

//m_hIconRed;//串口打开时的红灯图标句柄

//HICONm_hIconOff;//串口关闭时的指示图标句柄}

else//打开串口

{

m_ctrlOpenPort.SetWindowText("关闭串口");

CStringstrStatus;

if(m_Port.InitPort(this,m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits,m_dwCommEvents,512))

{

m_Port.StartMonitoring();//启动监视线程

m_ctrlIconOpenoff.SetIcon(m_hIconRed);//m_hIconRed;串口打开时的红灯图标句柄

strStatus.Format("STATUS:

COM%dOPENED,%d,%c,%d,%d",m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits);

//"当前状态:

串口打开,无奇偶校验,8数据位,1停止位");

}

else//如果没有打开串口成功

{

AfxMessageBox("没有发现此串口或被占用");

m_ctrlIconOpenoff.SetIcon(m_hIconOff);//m_hIconOff串口关闭时的红灯指示图标句柄

}

m_ctrlPortStatus.SetWindowText(strStatus);

}

}

7、为了在程序关闭时通过关闭串口并释放占用资源,在ClassWizard中为CSCOMMDlg添加了WM_DISTROY的消息响应函数OnDestroy(),函数在主窗口即将销毁时调用。

//为主窗口关闭时添加关闭响应函数

voidCSCOMMDlg:

:

OnDestroy()

{

CDialog:

:

OnDestroy();

m_ctrlAutoSend.SetCheck(0);//强行关闭自动发送

KillTimer

(1);//关闭定时器

KillTimer(4);

m_Port.ClosePort();//关闭串口

m_ReceiveData.Empty();//清空接收数据字符串

}

8、十六进制数据发送处理

首先为CSCOMMDlg类添加两个成员函数Str2Hex()和HexChar,前者对后者进行了调用,Str2Hex()的作用是将一个字符串作为十六进制转化为一个字符组,其中,data即为返回的数组,函数的返回值为data数组的长度。

//将一个字符串作为十六进制转化为一个字符数组,字节间可用空格分隔,

//返回转换后的字节数组长度,同时字节数组长度自动设置

intCSCOMMDlg:

:

Str2Hex(CStringstr,char*data)

{

intt,t1;

intrlen=0,len=str.GetLength();//获取字符串的长度

//data.SetSize(len/2);

for(inti=0;i

{

charl,h=str[i];

if(h=='')//如果有空格

{

i++;

continue;//跳出本次循环,进入for语句下次循环

}

i++;

if(i>=len)break;//跳出for循环

l=str[i];

t=HexChar(h);

t1=HexChar(l);

if((t==16)||(t1==16))

break;

else

t=t*16+t1;

i++;

data[rlen]=(char)t;

rlen++;

}

returnrlen;

}

charCSCOMMDlg:

:

HexChar(charc)

{

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

returnc-0x30;

elseif((c>='A')&&(c<='F'))

returnc-'A'+10;

elseif((c>='a')&&(c<='f'))

returnc-'a'+10;

else

return0x10;

}

9、手动发送处理

在ClassWizard中为手动发送按钮IDC_BUTTON_MANUALSEND添加单击处理函数(或直接在对话框模板中双击该控件),在OnButtonManualsend()添加如下代码:

longTX_count=0;

voidCSCOMMDlg:

:

OnButtonManualsend()

{

//TODO:

Addyourcontrolnotificationhandlercodehere

if(m_Port.m_hComm==NULL)//发送时要检验串口是否打开,否则会出错

{

m_ctrlAutoSend.SetCheck(0);

AfxMessageBox("串口没有打开,请打开串口");

return;

}

else//如果串口已经打开

{

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

if(m_ctrlHexSend.GetCheck())//发送十六进制数据

{

chardata[512];//定义一个512字节的数组

intlen=Str2Hex(m_strSendData,data);

m_Port.WriteToPort(data,len);

TX_count+=(long)((m_strSendData.GetLength()+1)/3);

//计数发送的十六进制数据,注意这里的计算方法,

//只有严格按照规则输入才能正确计算

//m_Port.WriteToPort(hexdata);

}

else//发送ASCII文本

{

m_Port.WriteToPort((LPCTSTR)m_strSendData);//发送数据

TX_count+=m_strSendData.GetLength();//发送计数

}

CStringstrTemp;

strTemp.Format("TX:

%d",TX_count);

m_ctrlTXCount.SetWindowText(strTemp);//显示计数

}

}

10、自动发送处理

自动发送时,需要用到定时器。

打开ClassWizard,为CSCOMMDlg类添加WM_TIMER消息处理函数OnTimer(UINTnIDEvent)。

需要注意的是,在VC6.0中,每个定时器都有自己的ID号,所有定时器处理均要在该函数中,因此,必须事先为相应的定时器设置ID号,OnTimer(UINTnIDEvent)函数则根据调用的nIDEvent值来确定是哪个定时器的定时时间到,再做相应的处理。

voidCSCOMMDlg:

:

OnTimer(UINTnIDEvent)

{

//TODO:

Addyourmessagehandlercodehereand/orcalldefault

CStringstrStatus;

switch(nIDEvent)

{

case1:

//定时器ID=1为自动发送时间到

OnButtonManualsend();//调用手动发送处的理函数即可

break;

case2:

//其他定时器

m_ctrlSavePath.SetWindowText(m_strCurPath);

KillTimer

(2);

break;

case3:

m_ctrlManualSend.EnableWindow(TRUE);

m_ctrlAutoSend.EnableWindow(TRUE);

m_ctrlSendFile.EnableWindow(TRUE);

m_strSendFilePathName=m_strTempSendFilePathName;

m_ctrlEditSendFile.SetWindowText(m_strSendFilePathName);//m_strSendFilePathName

KillTimer(3);

if(!

(m_ctrlAutoSend.GetCheck()))

{

if(m_Port.InitPort(this,m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits,m_dwCommEvents,512))

{

m_Port.StartMonitoring();

strStatus.Format("STATUS:

COM%dOPENED,%d,%c,%d,%d",m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits);

m_ctrlIconOpenoff.SetIcon(m_hIconRed);

}

else

{

AfxMessageBox("Failedtoresetsendbuffersize!

");

m_ctrlIconOpenoff.SetIcon(m_hIconOff);

}

m_ctrlPortStatus.SetWindowText(strStatus);

}

break;

case4:

m_animIcon.ShowNextImage();

break;

default:

break;

}

CDialog:

:

OnTimer(nIDEvent);

}

我们再来看看如何设置定时器1,在ClassWizar中,为自动发送选项IDC_CHECK_AUTOSEND添加响应函数OnCheckAutosend(),或者在对话框模板中直接双击该控件。

在OnCheckAutosend()中添加如下代码:

voidCSCOMMDlg:

:

OnCheckAutosend()

{

//TODO:

Addyourcontrolnotificationhandlercodehere

m_bAutoSend=!

m_bAutoSend;//标志是否打开自动发送

if(m_bAutoSend)

{

if(m_Port.m_hComm==NULL)//先检测串口是不是打开

{

m_bAutoSend=!

m_bAutoSend;

m_ctrlAutoSend.SetCheck(0);

AfxMessageBox("串口没有打开,请打开串口");

return;

}

else

SetTimer(1,m_nCycleTime,NULL);//设置定时器1,启动

}

else//如果自动发送标志没有打开

{

KillTimer

(1);//关掉定时器1

}

}

 

在自动发送时,如果输入编辑框中的内容改变时,要及时将串口发送的内容改变,在ClassWizar中编辑框IDC_EDIT_SEND添加响应函数。

voidCSCOMMDlg:

:

OnChangeEditSend()

{

//TODO:

IfthisisaRICHEDITcontrol,thecontrolwillnot

//sendthisnotificationunlessyouoverridetheCDialog:

:

OnInitDialog()

//functionandcallCRichEditCtrl().SetEventMask()

//withtheENM_CHANGEflagORedintothemask.

//TODO:

Addyourcontrolnotificationhandlercodehere

UpdateData(TRUE);//在编辑内部改变时,及时响应读取编辑框的内容

}

同样,当自动发送周期改变后,也需要将发送周期更新,但实际的发送周期需要重新用SetTimer()函数对定时器的定时间进行设置,在这个程序里,必须先关闭串口的“自动发送”然后再打开,新设的自动发送周期才能生效。

voidCSCOMMDlg:

:

OnChangeEditCycletime()

{

//TODO:

IfthisisaRICHEDITcontrol,thecontrolwillnot

//sendthisnotificationunlessyouoverridetheCDialog:

:

OnInitDialog()

//functionandcallCRichEditCtrl().SetEventMask()

//withtheENM_CHANGEflagORedintothemask.

//TODO:

Addyourcontrolnotificationhandlercodehere

CEdit*pEdit=(CEdit*)GetDlgItem(IDC_EDIT_CYCLETIME);

CStringstrText;

pEdit->GetWindowText(strText);

m_nCycleTime=atoi(strText);

}

11、接收处理及十六进制显示

接收处理均在串口事件消息处理函数OnCommunication(WPARAMch,LPARAMport)函数中实现。

其中,十六进制的接收显示时并不像发送那样麻烦,只要将数据直接以十六进制打印输出就可以了,注意中间插入一个空格。

LONGCSCOMMDlg:

:

OnCommunication(WPARAMch,LPARAMport)

{

if(port<=0||port>4)

return-1;

rxdatacount++;//接收的字节计数

CStringstrTemp;

strTemp.Format("%ld",rxdatacount);

strTemp="RX:

"+strTemp;

m_ctrlRXCOUNT.SetWindowText(strTemp);//显示接收计数

if(m_bStopDispRXData)//如果选择了“停止显示”接收数据,则返回

return-1;//注意,这种情况下,计数仍在继续,只是不显示

//若设置了“自动清空”,则达到50行后,自动清空接收编辑框中显示的数据

if((m_ctrlAutoClear.GetCheck())&&(m_ctrlReceiveData.GetLineCount()>=50))

{

m_ReceiveData.Empty();

UpdateData(FALSE);

}

//如果没有“自动清空”,数据行达到400后,也自动清空

//因为数据过多,影响接收速度,显示是最费CPU时间的操作

if(m_ctrlReceiveData.GetLineCount()>400)

{

m_ReceiveData.Empty();

m_ReceiveData="***TheLengthoftheTextistoolong,EmptiedAutomaticly!

!

!

***\r\n";

UpdateData(FALSE);

}

//如果选择了"十六进制显示",则显示十六进制值

CStringstr;

if(m_ctrlHexReceieve.GetCheck())

str.Format("%02X",ch);

else

str.Format("%c",ch);

//以下是将接收的字符加在字符串的最后,这里费时很多

//但考虑到数据需要保存成文件,所以没有用ListControl

intnLen=m_ctrlReceiveData.GetWindowTextLength();

m_ctrlReceiveData.SetSel(nLen,nLen);

m_ctrlReceive

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 环境科学食品科学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1