2015-11-29 22:17:28 leaf_130 阅读数 2526

##背景描述##

   基于zigbee的温室大棚

   一个协调器连接电脑,并接收多个zigbee终端发过来的数据    

   ##目的:

   1.编写上位机(MFC)

   2.想把串口接收到的多个传感器的数据分别在不同的编辑框输出

  


   解决方案:

    1.发送过来的数据打包(必须)

         *详情可以百度&谷歌

    2.MFC串口控件缓冲区必须设定一个数值(触发OnComm函数)

         *关键代码如下:

         m_ctrlComm.SetSettings("115200,n,8,1");//打开软件时端口设置默认为波特率9115200,无校验位,8位数据,1位停止位   
m_ctrlComm.SetInputMode(1); 
//1:表示以二进制方式检取数据 
m_ctrlComm.SetRThreshold(12); 
//参数12表示每当串口接收缓冲区中有12个字符时将引发一个接收数据的OnComm事件 
m_ctrlComm.SetInputLen(12);//设置当前接收区数据长度为12 
m_ctrlComm.GetInput();//先预读缓冲区以清除残留数据  

      注:我这里设置的是 12 ,是和我发过来的数据包的字节大小是一直的。

      3.直接上我的OnComm() 函数:

  

int o;
void CSmart_ZIGBEE_FLYDlg::OnComm() 
{      
      VARIANT variant_inp;//定义一个VARIANT类对象
   COleSafeArray safearray_inp;//定义一个COleSafeArray对象
   LONG len,k; 
 o++;
 BYTE rxdata[1024]; //设置BYTE数组 AN 8—intterthat is not signed.
 CString strtemp;
////////////////////////////////////
                //每次清屏
////////////////////////////


if(o>30)     //定量清除 编辑框数据
{   
        m_strRXData = _T("");
m_strRXData2= _T("");
        m_strRXData3 = _T("");
   m_strRXData4= _T("");
m_strRXData5 = _T("");  
o=0;
}
     
 if (m_ctrlComm.GetCommEvent()==2)//事件值为2表示接收缓冲区内有数据 
 {
 //OnSave();
 ///以下你可以根据自己的通信协议加入处理代码  
 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型数组  
 } 
       
  int h;
 
 for(k=0;k<1;k++)//将数组转换为Cstring型变量    
  {   
    BYTE bt=*(char*)(rxdata+k);//字符型首先取得(rxdata+k),它是一个BYTE型的指针,
//然后强制转换为char型,然后逆向引用求出其中的内容
                 
                 
            strtemp.Format("%c",bt);//将字符送入临时变量strtemp存放  
       
               

//备注:我一共有四个终端同时向协调器发送数据,

//每个终端的数据都进行了打包,然后设置一个标志位

//通过判别标志位,来进行调用不同的 编辑框进行输出
   if(strtemp =='#')//温度
{
  h=0;
 
//continue;
}
else
    if (strtemp =='@')//光强
{
h=1;
//continue;
}
else
if (strtemp =='*')//湿度
{
h=2;
//continue;

else
    if (strtemp =='$')// co2二氧化碳
{
h=3;
//continue;
}
else
if(strtemp =='&')// 烟雾
{
h=4;
//continue;
}


switch(h)
{


case 0:
{  

                  for(k=1;k<len;k++)//将数组转换为Cstring型变量    
    {    
 
 BYTE bt=*(char*)(rxdata+k);//字符型首先取得(rxdata+k),它是一个BYTE型的指针,
//然后强制转换为char型,然后逆向引用求出其中的内容
                 
            strtemp.Format("%c",bt);//将字符送入临时变量strtemp存放  
            m_strRXData+=strtemp;
               
 }OnSave();//这是我数据保存函数(也是保存到不同的文本的)
 break;
}
             case 1:
{   
                   for(k=1;k<len;k++)//将数组转换为Cstring型变量    
    {   
 BYTE bt=*(char*)(rxdata+k);//字符型首先取得(rxdata+k),它是一个BYTE型的指针,
//然后强制转换为char型,然后逆向引用求出其中的内容


            strtemp.Format("%c",bt);//将字符送入临时变量strtemp存放  
            m_strRXData2+=strtemp;
  } OnSave_1();
  break;
}
              case 2: 
 {  
 
                   for(k=1;k<len;k++)//将数组转换为Cstring型变量    
    {   
      BYTE bt=*(char*)(rxdata+k);//字符型首先取得(rxdata+k),它是一个BYTE型的指针,
//然后强制转换为char型,然后逆向引用求出其中的内容


               strtemp.Format("%c",bt);//将字符送入临时变量strtemp存放  
               m_strRXData3+=strtemp;
  } OnSave2();
  break;
 }
case 3: 
 {   
                   for(k=1;k<len;k++)//将数组转换为Cstring型变量    
    {   
     BYTE bt=*(char*)(rxdata+k);//字符型首先取得(rxdata+k),它是一个BYTE型的指针,
//然后强制转换为char型,然后逆向引用求出其中的内容


             strtemp.Format("%c",bt);//将字符送入临时变量strtemp存放  
             m_strRXData4+=strtemp;
  }OnSave3();
  break;
 }
 case 4: 
 {   
                   for(k=1;k<len;k++)//将数组转换为Cstring型变量    
    {   
       BYTE bt=*(char*)(rxdata+k);//字符型首先取得(rxdata+k),它是一个BYTE型的指针,
//然后强制转换为char型,然后逆向引用求出其中的内容


               strtemp.Format("%c",bt);//将字符送入临时变量strtemp存放  
               m_strRXData5+=strtemp;
  } OnSave4();
  break;
 }
}
}
 }
          UpdateData(FALSE);//更新编辑框内容(主要是接收编辑框中的  
 
      
}



这样就可以实现多个编辑框输出了


图示:



2015-10-19 23:22:17 u013719984 阅读数 3783
#include  <iostream> 
#include  <string> 
#include <afxinet.h> //定义了MFC CInternetSession类等    
 bool PostHttpPage(const std::string& hostName, const    std::string& pathName, const std::string& postData)  
 {  
        using namespace std;    
       CInternetSession session("your app agent name");    
   try  
   {  
            INTERNET_PORT nPort = 80;  
            DWORD dwRet = 0;    
            CHttpConnection* pServer = session.GetHttpConnection(hostName.c_str(), nPort);  
               CHttpFile* pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_POST, pathName.c_str());    
              // CString strHeaders = "Content-Type: application/x-www-form-urlencoded"; // 请求头
              CString strHeaders = "multipart/form-data"    //通过post上传数据流,如文件等
            //开始发送请求    
          pFile->SendRequest(strHeaders,(LPVOID)postData.c_str(),postData.size());  
             pFile->QueryInfoStatusCode(dwRet);      
             if (dwRet == HTTP_STATUS_OK)  
             {  
                    CString result, newline;    
                  while(pFile->ReadString(newline))  
                    { 
                              //循环读取每行内容  
                           result += newline+"\r\n";  
                    }    
                 std::cout<<result<<std::endl;//显示返回内容  
             }  
             else  
             {  
                  return false;  
             }  
             delete pFile;  
                 delete pServer;    
    }  
     catch (CInternetException* pEx)  
       {  
             //catch errors from WinInet  
           TCHAR pszError[200];  
          pEx->GetErrorMessage(pszError, 200);    
               std::cout<<pszError<<std::endl;//显示异常信息  
               return false;  
         }  
     session.Close();    
   return true;  
 }    
 int main(void)  
 { 
    //向http://current.sinaapp.com/post.php发送数据 
      PostHttpPage("current.sinaapp.com","post.php","name=rain&age=12");  
 } 
2018-09-14 21:51:52 Chiang2018 阅读数 99

Windows剪贴板是一种比较简单的进程间通信机制,同时它的开销相对较小。它的实现原理很简单,其实就是由由操作系统维护的一块内存区域,
这块内存区域不属于任何单独的进程,但是每一个进程又都可以访问这块内存区域,当一个进程将数据放到该内存区域中,而另一个进程,则可以从该块内存区域中取出数据,从而实现通信,其实现过程由两大部分组成,一个是共享内存操作,一个是剪贴板的操作。
1、剪贴板操作
(1)HWND GetClipboardOwner();
功能:获取指向剪贴板的当前拥有者的句柄
如果这个函数执行成功,则返回拥有剪贴板的窗口句柄。否则,返回NULL。

(2)BOOL OpenClipboard(HWND hWndNewOwner );
第一个参数 hWndNewOwner 指向一个与之关联的窗口句柄,即代表是这个窗口打开剪贴板,如果这个参数设置为 NULL 的话,则以当前的任务或者说是进程来打开剪贴板。如果打开剪贴板成功,则该函数返回非 0 值,如果其他程序已经打开了剪贴板,那么当前这个程序就无法再打开剪贴板了,所以会致使打开剪贴板失败,从而该函数返回 0 值。其实这也好理解,你想啊,剪贴板总共才那么一块内存区域,你 进程 A 要往里面写数据,你 进程 B 又要往里面写数据,那不乱套去,解决这个乱套的办法就是,如果我 进程 A 正在往剪贴板里面写数据(可以理解为 进程 A 打开剪贴板了),那么 进程 B 就不能往剪贴板里头写数据了,既然要让 进程 B 不能往剪贴板中写数据了,那我就让 进程 B 打开剪贴板失败不就得了。所以如果某个程序已经打开了剪贴板,那么其他应用程序将不能修改剪贴板,直到打开了剪贴板的这个程序调用了 CloseClipboard 函数,并且只有在调用了 EmptyClipboard 函数之后,打开剪贴板的当前窗口才能拥有剪贴板

(3)BOOL CloseClipboard(void);
如果某个进程打开了剪贴板,则在这个进程没有调用 CloseClipboard 函数关闭剪贴板句柄之前,其他进程都是无法打开剪贴板的,所以我们每次使用完剪贴板之后都应该关闭剪贴板。注意,这里的关闭剪贴板并不代表当前打开剪贴板的这个程序失去了对剪贴板的所有权,只有在别的程序调用了 EmptyClipboard 函数之后,当前的这个程序才会失去对剪贴板的所有权,而那个调用 EmptyClipboard 函数的程序才能拥有剪贴板。

(4)HANDLE SetClipboardData(UINT uFormat, HANDLE hMem );
SetClipboardData 函数来实现往剪贴板中放置数据,这个函数以指定的剪贴板格式向剪贴板中放置数据。第一个参数 uFormat 用来指定要放到剪贴板上的数据的格式,比如常见的有 CF_BITMAP ,CF_TEXT ,CF_DIB 等等(其他格式可以参考 MSDN)。第二个参数 hMem 用来指定具有指定格式的数据的句柄,该参数可以是 NULL ,如果该参数为 NULL 则表明直到有程序对剪贴板中的数据进行请求时,该程序(也就是拥有剪贴板所有权的进程)才会将数据复制到剪贴板中,也就是提供指定剪贴板格式的数据,上面提及的就是延迟提交技术,这个延迟提交技术将会在后面做详细的介绍。

(5)BOOL IsClipboardFormatAvailable( UINT format );
该函数用来判断剪贴板上的数据格式是否为 format 指定的格式。

(6)HANDLE GetClipboardData( UINT uFormat );
该函数根据 uFormat 指定的格式,返回一个以指定格式存在于剪贴板中的剪贴板对象的句柄。

2、共享内存分配
(1)HGLOBAL WINAPI GlobalAlloc( UINT uFlags, SIZE_T dwBytes );
第一个参数 uFlags 用来指定分配内存的方式。其取值如下列表所示但是在剪贴板的使用中,由于要实现动态数据交换,所以必须得使用 GHND 或者 GMEM_MOVEABLE):
GHND GMEM_MOVEABLE 和 GMEM_ZEROINIT 的组合。
GMEM_FIXED 分配一块固定内存,返回值是一个指针。
GMEM_MOVEABLE 分配一块可移动内存。
GMEM_ZEROINIT 初始化内存的内容为 0
GPTR 即 GMEM_FIXED 和 GMEM_ZEROINIT 的组合。
第二个参数 dwBytes 用来指定分配的字节数。

(2)HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags);
该函数为再分配函数,即在原有的数据对象 hMem 上,为其扩大内存空间。
第一个参数 hMem 代表由 GlobalAlloc 函数返回的数据对象句柄。
第二个参数 dwBytes 指定需要重新分配的内存的大小。
第三个参数 uFlags 指定分配的方式(可以参考 GlobalAlloc 函数)。

(3)SIZE_T WINAPI GlobalSize( HGLOBAL hMem );
该函数用来返回内存块的大小。
第一个参数 hMem 代表由 GlobalAlloc 函数返回的数据对象句柄。

(4)LPVOID WINAPI GlobalLock( HGLOBAL hMem );
该函数的作用是对全局内存对象加锁,然后返回该对象内存块第一个字节的指针。
第一个参数 hMem 代表由 GlobalAlloc 函数返回的数据对象句柄。

(5)BOOL WINAPI GlobalUnlock( HGLOBAL hMem );
你通过上面的 GlobalLock 函数可以获得这块全局内存的访问权,
加锁的意思就是你已经在使用这块全局内存了,别的程序就不能再使用这块全局内存了,而如果你一直不解锁,那也不是个事啊,别的程序将会一直都使用不了这块全局内存,那还叫全局内存干吗啊?所以这个函数就是用来对全局内存对象解锁。
第一个参数 hMem 代表由 GlobalAlloc 函数返回的数据对象句柄。

(6)HGLOBAL WINAPI GlobalFree( HGLOBAL hMem );
该函数释放全局内存块。
第一个参数 hMem 代表由 GlobalAlloc 函数返回的数据对象句柄。

以下为示例代码,读者也可以通过自己自电脑上进行Ctrl+C(拷贝数据到剪贴板) Ctrl+V(从剪贴板上拷贝数据) 进行某一项测试:

// Ctrl+C.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>  
#include <process.h>  
#include <windows.h>  

using namespace std;

int main()
{
    HWND hWnd = GetClipboardOwner();//获取当前剪贴板所属的窗口句柄
    DWORD Len = 32;
    HGLOBAL pClipData;
    pClipData = GlobalAlloc(GHND,Len+1);//分配共享内存

    char* pData;
    pData = (char*)GlobalLock(pClipData);//内存控制句柄加锁,其他进程不能再访问

    for(int i = 0;i < Len;i++)
    {
        pData[i] = 'a'+i;                //在全局内存中赋值
    }

   GlobalUnlock(pClipData);//内存控制句柄解锁,其他进程可以访问

   if(!OpenClipboard(hWnd))//打开剪贴板
   {
       cout<<"OPen fail!"<<endl;
       return 0; 
   }

   EmptyClipboard();//清空剪贴板,这一步才真正拥有剪贴板
   SetClipboardData(CF_TEXT,pClipData);//将共享内存里的数据放入剪贴板
   CloseClipboard();//关闭剪贴板

   cout<<"剪贴完成"<<endl;
   return 0;
}
//Ctrl+V.cpp
#include "stdafx.h"
#include <iostream>  
#include <process.h>  
#include <windows.h>  

using namespace std;

int main()
{
    HWND hWnd = GetClipboardOwner();//获取当前剪贴板所属的窗口句柄

    if(!OpenClipboard(hWnd))//打开剪贴板
    {
        cout<<"OPen fail!"<<endl;
        return 0; 
    }

    if(IsClipboardFormatAvailable(CF_TEXT))
    {
         HANDLE hCilpData = GetClipboardData(CF_TEXT);
         DWORD Len = GlobalSize(hCilpData);

          char* pData;
          pData = (char*)GlobalLock(hCilpData);//内存控制句柄加锁,其他进程不能再访问
          cout<<"剪贴板内容是:"<<pData<<endl;
          GlobalUnlock(hCilpData);//内存控制句柄解锁,其他进程可以访问
    }

   EmptyClipboard();//清空剪贴板,这一步才真正拥有剪贴板

   CloseClipboard();//关闭剪贴板

   cin.get();
   return 0;
}
2013-05-15 21:49:43 zy_dreamer 阅读数 1201

完整工程可以到:http://download.csdn.net/detail/zy_dreamer/5385153 下载

基于MFC

用于存储数据的自定义结构体:

struct MSG_STRUCT 
{
	wchar_t msg[256];
};

发送端,发送按钮响应事件的代码

void CSendWM_COPYDATADlg::OnBnClickedSendmessage()
{
	MSG_STRUCT smsg;
	GetDlgItemText(IDC_MESSAGE,smsg.msg,256);
	HWND hTargetWnd=NULL;
	hTargetWnd=::FindWindow(NULL,_T("ReceiveWM_COPYDATA
		COPYDATASTRUCT cds;
		cds.cbData=sizeof(MSG_STRUCT);
		cds.lpData=&smsg;
		if(hTargetWnd==NULL)
			return;
		::SendMessage(hTargetWnd,WM_COPYDATA,reinterpret_cast<WPARAM>(m_hWnd), 
			reinterpret_cast<LPARAM>(&cds));
}


接收端,响应WM_COPYDATA的代码

BOOL CReceiveWM_COPYDATADlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
	// TODO: Add your message handler code here and/or call default
	CString cs_str;
	CString cs_PrivStr;
	GetDlgItemText(IDC_RECEIVEMSG,cs_PrivStr);
	++m_ReceiveNum;
	MSG_STRUCT smsg;
	if(pCopyDataStruct->cbData==sizeof(smsg))
	{
		memcpy_s(&smsg,sizeof(smsg),pCopyDataStruct->lpData,pCopyDataStruct->cbData);
	}
	//MessageBox(smsg.msg);
	cs_str.Format(_T("消息%d:%s\r\n"),m_ReceiveNum,smsg.msg);
	cs_str=cs_PrivStr+cs_str;
	SetDlgItemText(IDC_RECEIVEMSG,cs_str);
	return CDialog::OnCopyData(pWnd, pCopyDataStruct);
}


最终效果图:

发送端


接收端:


2013-05-02 23:24:19 kuangdang178 阅读数 11704

此文章以visual C++数据采集与串口通信测控应用实战为参考教程

此文章适合VC++串口通信入门

一、页面布局及添加控件

1, 安装好vs2010如图


2, 新建一个基于VC++的MFC项目comm


注意:点击ok,然后next,这时候要将application type改成dialog base,接着next到最后一个对话框是将generated dasses改成CcommDlg,然后finish


4, 将新生成的项目的对话框默认dialog edit删去,如图


5,在对话框中添加两个static text,两个edit text,两个按钮,

成品图如下


6,添加comm控件

    1)在解决方案窗口右击新建的解决方案,点击add->class

     2)选择MFC class from activex control如图


点击add,available activex controls选择microsoft communication controls versions 6.0,然后点确定就行

这时候对话框会出现一个电话图标,可能有一半白边去不了,这时候右击电话图标点击edit control就可以去掉了。

7,同时定义各个控件的类型、ID及相关属性


注:此项目只添加了发送和退出程序按钮

这时候得到了完整的串口通信对话框:


8, 添加成员变量,右击对话框,点击class wizard,点击member variables标签,选中需要添加的id,双击即可添加

依次为下表中的ID添加变量


期间,IDC_MSCOMM1控件在标签中没有,则在生成的对话框中右击comm控件点击add variables即可

9, 为mscomm,两个button添加响应事件,切换到class wizard的virtual function双击控件ID,添加响应事件,默认即可,也可改为自己想要的标题

为comm控件添加响应事件可能双击不了(我就是遇到这种问题),这时候只要右击comm控件图标,点击add event handler即可。如图



这时候基本界面已经布置好了,开始添加代码了。

二、代码添加

1、找到解决方案(solution explorer)的sources files点开,双击其中的mscommDlg.cpp我们的所有代码将添加到这个源文件中

2、进行串口初始化及其他串口设置

将以下代码添加到oninitialdialog函数

m_ctrlcomm.put_CommPort(3);//选择com3口
m_ctrlcomm.put_InputMode(1);//输入方式为二进制方式
m_ctrlcomm.put_InBufferSize(1024);//输入缓冲区大小为1024byte
m_ctrlcomm.put_OutBufferSize(512);//输出缓冲区大小为512byte
m_ctrlcomm.put_Settings(_T("9600,n,8,1"));//设置串口参数:9600波特率,无奇偶校验,8个数据位,1个停止位
if(!m_ctrlcomm.get_PortOpen())
    m_ctrlcomm.put_PortOpen(1);//打开串口
m_ctrlcomm.put_RThreshold(1);//每当串口接收缓冲区有多余或等于1个字符时将引发一个接收数据的oncomm事件
m_ctrlcomm.put_InputLen(0);//设置当前接收区数据长度为0
m_ctrlcomm.get_Input();//预读缓冲区以清空残留数据

m_ctrlcomm.put_CommPort(3);//选择com3口
m_ctrlcomm.put_InputMode(1);//输入方式为二进制方式
m_ctrlcomm.put_InBufferSize(1024);//输入缓冲区大小为1024byte
m_ctrlcomm.put_OutBufferSize(512);//输出缓冲区大小为512byte
m_ctrlcomm.put_Settings(_T("9600,n,8,1"));//设置串口参数:9600波特率,无奇偶校验,8个数据位,1个停止位
if(!m_ctrlcomm.get_PortOpen())
    m_ctrlcomm.put_PortOpen(1);//打开串口
m_ctrlcomm.put_RThreshold(1);//每当串口接收缓冲区有多余或等于1个字符时将引发一个接收数据的oncomm事件
m_ctrlcomm.put_InputLen(0);//设置当前接收区数据长度为0
m_ctrlcomm.get_Input();//预读缓冲区以清空残留数据
2、实现发送按钮,退出按钮相应的响应函数

void CmscommDlg::OnBnClickedOk()
{
// TODO: Add your control notification handler code here
CDialogEx::OnOK();
UpdateData(1);//读取编辑框内容
m_ctrlcomm.put_Output(COleVariant(m_strsend));//发送数据
}




void CmscommDlg::OnBnClickedExit()
{
// TODO: Add your control notification handler code here
m_ctrlcomm.put_PortOpen(0);//关闭串口
CDialog::OnCancel();//退出程序
}
3、实现MSComm控件相应的响应函数OnOnCommMsComm1()

VARIANT variant_inp;
COleSafeArray safearray_inp;
LONG len,k;
BYTE rxdata[2048];//设置byte数组
CString strtemp;
if(m_ctrlcomm.get_CommEvent()==2)//事件2表示接受缓冲区有字符
{
variant_inp=m_ctrlcomm.get_Input();//读缓冲区
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((char) bt);//将字符送入临时变量strtemp存放
m_strreceive+=strtemp;//加入接收编辑框相应字符串
}
}
UpdateData(0);//更新编辑框内容

4、编译运行程序

在调试运行时,必须两台机子同时运行此程序,并且都要开启同一个串口号


C++中串口通信

阅读数 211

没有更多推荐了,返回首页