c++串口上位机调试助手的总结和部分代码

MFC 同时被 3 个专栏收录
11 篇文章 0 订阅
13 篇文章 0 订阅
9 篇文章 0 订阅
          我记得是大一下学期学习的C++,是选修课。老师也是随便点几章讲讲,当时什么都不懂,就记得一些类的概念。毕业了,工作了。公司给了个小考核,其中有一项串口上位机软件的,于是花了几天时间,站在前人的肩膀上,做了一个还看得过去的串口上位机软件。今天就总结一下学习的感受和贴出部分重要的代码,以防以后需要,找不到。

       我个人觉得学习力,就是学习某种知识的能力,我们学习的时间越短,效率就越高,能力就越强。不过学习力也是需要培养的,方法和经验也需要积累的。高手也是从菜鸟开始的,以下是我做上位机的一些感受。

       一、我觉得学会搜索很重要。很多东西前人都做过,我们只需站在前人的肩膀上,再加工或修改就会变成自己的,这样可以缩短时间,提高效率。所以能有效的搜索到最靠近的资料,就越快达到目标。个人觉得www.baigoogledu.com这个集成谷歌、百度的搜索很好用。

       二、在什么都不懂的情况下,我们要先拿来,借鉴别人所作的东西,去完成自己要做的东西。

       三、当我们已经会做某一东西时,我们要回过头来看看。想想为什么要这样做?这样做的目的是什么?有没有其他更好的方法?这种方法有没有缺点等等。这样既能巩固我们学习的知识,又能引发我们的思考,让我们达到更高的层次。

       四、高手们常教导我们,笔记很重要。及时记录一些内容,并整理有利于以后翻阅,查找,我也是刚刚起步。

以下是我写上位机的一些重要代码。一些变量代码命名有些不规范,希望自己在以后学习和运用中不断改正。我转了一篇C++串口调试助手的文章,步骤可以模仿,在这里就不写步骤了,就直接贴部分代码了。

在初始化函数中添加:

 // TODO: Add extra initialization here

 m_bAutoSend=FALSE;  //m_bAutoSend为全局变量
 m_nCycleTime=1000;

 m_GPSCOM.SetCommPort(1);   //选择COM1
 m_GPSCOM.SetInputMode(1); //输入方式为二进制方式
 m_GPSCOM.SetInBufferSize(1024); //设置输入缓冲区大小
 m_GPSCOM.SetOutBufferSize(512); //设置输出缓冲区大小
// m_GPSCOM.SetSettings("9600,n,8,1"); //波特率115200,无校验,8个数据位,1个停止位
 if(m_GPSCOM.GetPortOpen())   //如果串口是打开的
   m_GPSCOM.SetPortOpen(FALSE);//则关闭串口

 //参数1表示每当串口接收缓冲区中有多于
 //或等于1个字符时将引发一个接收数据的OnComm事件
 m_GPSCOM.SetRThreshold(1);
 m_GPSCOM.SetInputLen(0);  //设置当前接收区数据长度为0
 //m_GPSCOM.GetInput();    //先预读缓冲区以清除残留数据 

 

显示接收到的内容

m_RXDATA建立的变量是CEidtl类型,不是CString

 

static long  RXcount=0;
void CGPS_COM1Dlg::OnGPSCOM()           //编辑框接收函数——用于显示串口接收到的数据
{
 // 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;
 CString strRXData;
  
 strRXData.Empty();
    if(m_GPSCOM.GetCommEvent()==2)     //事件值为2表示接收缓冲区内有字符
 {
  variant_inp=m_GPSCOM.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_hexdisplay.GetCheck())
   {
    strtemp.Format("%02x ",bt);         //将十六进制送入临时变量strtemp存放
   }
   else
   {
    strtemp.Format("%c",bt);         //将字符送入临时变量strtemp存放
   }
   strRXData=strRXData+strtemp;    //加入接收编辑框对应字符串
   
  }

  m_RXDATA.ReplaceSel(strRXData);
  
  RXcount=RXcount+len;
  CString rxdatacount;
  rxdatacount.Format("%ld",RXcount);
//  rxdatacount="接收:"+rxdatacount;

  m_RXdatacount.SetWindowText(rxdatacount); //显示接收计数
  
 }
}

//不用UpdateData(),这样写的好处就是当一直在接收时,也能自由发送而不受UpdateData()函数影响。

 

串口打开或关闭

void CGPS_COM1Dlg::OnButton1()     //串口打开或关闭
{
 // TODO: Add your control notification handler code here
 if(m_ctrlAutoSend.GetCheck())
 {
  AfxMessageBox("请先关闭自动发送,才可以关闭串口");
 }
 else
 {
  
  if(!m_GPSCOM.GetPortOpen())
  {
   m_GPSCOM.SetPortOpen(TRUE);//打开串口
   SetDlgItemText(IDC_BUTTON1,"关闭串口");

  }
  else
  {
   m_GPSCOM.SetPortOpen(FALSE);//关闭串口
   SetDlgItemText(IDC_BUTTON1,"打开串口");
  }
 }
}

 m_TXDATA建立的变量是CEidtl类型,不是CString

long TX_count=0;
void CGPS_COM1Dlg::OnButton2Tx()   //数据发送函数
{
 // TODO: Add your control notification handler code here
 if(!m_GPSCOM.GetPortOpen())
 {
  AfxMessageBox("请先打开串口");
 }
 else
 {
  UpdateData(TRUE); //读取编辑框内容
  if(m_strHexSend.GetCheck())
  {
   CByteArray hexdata;
   int len=String2Hex(m_TXDATA,hexdata); //此处返回的len可以用于计算发送了多少个十六进制数
   m_GPSCOM.SetOutput(COleVariant(hexdata)); //发送十六进制数据
   TX_count+=(long) ((m_TXDATA.GetLength()+1)/3); //十六进制计数要注意算法
  }
  else
  {
   m_GPSCOM.SetOutput(COleVariant(m_TXDATA));//发送ASCII字符数据
   TX_count+=m_TXDATA.GetLength();
  }
  CString strTemp;
  strTemp.Format("%d",TX_count);
  m_TXcount.SetWindowText(strTemp);
 }
}

 

void CGPS_COM1Dlg::OnButton3Clear()  //清除接收编辑框
{
 // TODO: Add your control notification handler code here
 m_RXDATA.SetWindowText("");//清除接收对话框中的数据


}

void CGPS_COM1Dlg::OnCHECK1hexdisplay()
{
 // TODO: Add your control notification handler code here
 
}


void CGPS_COM1Dlg::OnCOMchose()
{
 // TODO: Add your control notification handler code here
 char str[10];
 
 int iPos=m_COMChose.GetCurSel();
 int iNum=m_COMChose.GetLBText( iPos, (LPTSTR) str) ;
 int i=atoi(str+3);
 if(m_GPSCOM.GetPortOpen())
 {
  AfxMessageBox("请先关闭串口,再选择COM口");
 }
 if(!m_GPSCOM.GetPortOpen())
 {
  m_GPSCOM.SetCommPort(i);   //选择COM口

 }

}

 

void CGPS_COM1Dlg::OnHexSend()
{
 // TODO: Add your control notification handler code here


}


void CGPS_COM1Dlg::OnTimer(UINT nIDEvent)
{
 // TODO: Add your message handler code here and/or call default
 switch(nIDEvent)
 {
  case 1:  OnButton2Tx();
   break;
/*  case 2:
   m_strCurPath.SetWindowText(m_strCurPath); //重新显示路径
   KillTimer(2);//关闭定时器

*/
  default:      ;
   break;
 
 }
 CDialog::OnTimer(nIDEvent);
}

void CGPS_COM1Dlg::OnCheck2_AutoSend()
{
 // TODO: Add your control notification handler code here
 
 m_bAutoSend=!m_bAutoSend;  //标志是否打开自动发送
 if(m_bAutoSend)
 {
  if(!m_GPSCOM.GetPortOpen())
  {
   m_bAutoSend=!m_bAutoSend;
   m_ctrlAutoSend.SetCheck(0);
   AfxMessageBox("串口没有打开,请打开串口");
   return;
  }
  else
   SetTimer(1,m_nCycleTime,NULL); //设置定时器1 m_nCycleTime
 }
 else
 {
  KillTimer(1);  //“杀”掉定时器1
 }
}

void CGPS_COM1Dlg::OnChangeEdit_CycleTime()
{
 // TODO: If this is a RICHEDIT control, the control will not
 // send this notification unless you override the CDialog::OnInitDialog()
 // function and call CRichEditCtrl().SetEventMask()
 // with the ENM_CHANGE flag ORed into the mask.
 
 // TODO: Add your control notification handler code here
 
 CEdit* pEdit=(CEdit*)GetDlgItem(IDC_EDIT1);
 CString strText;
 pEdit->GetWindowText(strText);
 m_nCycleTime=atoi(strText);


}

void CGPS_COM1Dlg::OnClearCount()
{
 // TODO: Add your control notification handler code here
 RXcount=0;  
 TX_count=0;
 m_RXdatacount.SetWindowText("");//清除接收对话框中的数据
 m_TXcount.SetWindowText("");//清除接收对话框中的数据
}

void CGPS_COM1Dlg::OnButtonSavedata()
{
 // TODO: Add your control notification handler code here
 UpdateData(TRUE);

 CFile m_rFile;
 LPCSTR lpszPath="c:\\comdata";   //存盘路径为c:\\comdata
 SetCurrentDirectory(lpszPath);

 CString  m_Filename,m_name1;
 m_name1=m_strFilename;   //填写的名字
 m_Filename=m_name1+".txt";  //以TXT格式存储
 if(0==m_strFilename.GetLength())
 {
  AfxMessageBox("请先输入保存的文件名");
 }
 else
 {
  if(!m_rFile.Open(m_Filename,CFile::modeCreate | CFile::modeWrite))
  {
   AfxMessageBox("创建记录文件失败!");
   return;
  }

  char TxtTemp[60000];   //字符串的长度
  int Maxsize=60000;    //
  int i=m_RXDATA.GetWindowText(TxtTemp,Maxsize);//将接受编辑框的数据取出放到数组TxtTemp中
  
  //在文件开始处写上保存日期
  CTime t=CTime::GetCurrentTime();
  CString str=t.Format("%Y年%m月%d日%H时%M分%S秒\r\n");
  m_rFile.Write((LPCTSTR)str,str.GetLength());
  //保存数据
  m_rFile.Write((LPCTSTR)TxtTemp,m_RXDATA.GetWindowTextLength());
  m_rFile.Flush(); 
  m_rFile.Close();  //关闭文件
  AfxMessageBox("保存成功");
  UpdateData(FALSE);
 }
}

 

在头文件中要声明这两个函数

  //由于这个转换函数的格式限制,在发送框中的十六制字符应该每两个字符之间插入一个空隔
  //如:A1 23 45 0B 00 29
  //CByteArray是一个动态字节数组,可参看MSDN帮助
int CGPS_COM1Dlg::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 CGPS_COM1Dlg::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);
}

 

我做成时的界面

 

  • 6
    点赞
  • 4
    评论
  • 24
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值