2011-04-11 11:47:00 lijie45655 阅读数 614
  • MFC上位机与STM32下位机通讯精讲

    本课程主要介绍C++类库MFC上位机与STM32单片机的RS232、RS422、RS485、USB、LWIP以太网、CAN等接口进行稳定通信。课程主要从MFC和STM32基础开始,以编写上位机以及下位机为主,非常注重实践。

    9334 人正在学习 去看看 王凯杰

       如果用户的应用程序需要有多个任务同时进行相应的处理,则使用多线程是较理想的选择。多线程对于网络,打印,字处理,图形图像,动画和文件管理的同一个系统下运行来说,是非常必要的。

      在一个多线程程序中,进程必须有一个主线程,主线程可以在任何需要的时候创建新的线程。所有活动的县城共享进程的资源。解决多线程访问同一共享资源的冲突问题是非常重要的。

     在MFC中有四个同步对象:

 1 如果某个线程必须等待某些事件发生后才能存取相应资源,则用CEvent

 2 如果一个应用同时可以有多个线程存取资源,则用CSemaphore

3 如果有多个应用同时存取相应资源,则用CMutex,否则用CCriticalSection。

 

2011-09-28 09:55:59 iq19900204 阅读数 515
  • MFC上位机与STM32下位机通讯精讲

    本课程主要介绍C++类库MFC上位机与STM32单片机的RS232、RS422、RS485、USB、LWIP以太网、CAN等接口进行稳定通信。课程主要从MFC和STM32基础开始,以编写上位机以及下位机为主,非常注重实践。

    9334 人正在学习 去看看 王凯杰

在程序中多线程有时候是非常必要的,MFC也可以实现多线程。

(1)在类成员函数中加入一个线程函数

    static DWORD WINAPI ShowImageThread(void *pArg);  //图像识别线程
这个线程必须是静态的,或者是全局的也可以。

值得注意的是,大家都值得静态函数中使用的资源也必须是静态的,这样会导致在这个线程函数中无法使用原类的资源变量了。用全局也是一样。

所以我用了一个解决办法,就是把当前类对象传参这个线程 *pArg

(2)在想要多线程的地方创建该线程

	HANDLE hThread = NULL;   //图像处理线程
	//创建识别线程
	hThread=CreateThread(NULL,0,ShowImageThread,(void *)this,NULL,&dwThreadID);   
        CloseHandle(hThread);
这里注意到,创建线程的函数是上面申明的ShowImageThread静态函数,传过去的参数是(void*)this就是本类的当前实体对象

(3)这样一来算线程就启动了,当然你必须把ShowImageThread函数写好

//静态线程函数
DWORD WINAPI  CAIMouseDlg::ShowImageThread(void *pArg)
{
	CAIMouseDlg *thisdlg = (CAIMouseDlg *)pArg;
这里就参数重新转换成原类的指针,通过这个thisdlg指针你就可以调用原来的变量和函数了

2017-10-13 10:36:15 naoxudian6278 阅读数 1161
  • MFC上位机与STM32下位机通讯精讲

    本课程主要介绍C++类库MFC上位机与STM32单片机的RS232、RS422、RS485、USB、LWIP以太网、CAN等接口进行稳定通信。课程主要从MFC和STM32基础开始,以编写上位机以及下位机为主,非常注重实践。

    9334 人正在学习 去看看 王凯杰

由于之前在做ALLIED TECNOLOGY工业相机,在工业相机获取视频的基础上,将工业相机存储的pBuffer数据(包含了一幅图像的所有像素点数据,数据存储规律为B0G0R0,B1G1R1……先行后列)转换成为Mat类图像,因而,可以在OPENCV中进行图像处理。程序如下:

void CopyToMat(Mat* img, VmbUchar_t*pInBuffer)//自定义  pBffer即为工业相机获取到的图像数据容器
{
 for (int i = 0; i<(*img).rows; i++)
 {
  for (int j = 0; j < (*img).cols; j++)
  {
   ((*img).ptr<uchar>(i,j))[0] = *(pInBuffer  +i*(*img).cols*3 + (j * 3) + 0);
   ((*img).ptr<uchar>(i,j))[1] = *(pInBuffer  +i*(*img).cols * 3 + (j * 3) + 1);
   ((*img).ptr<uchar>(i,j))[2] = *(pInBuffer  +i*(*img).cols * 3 + (j * 3) + 2);
  }
 }
}

 

     由于有很多大型算法进行图像处理,所以要解决视频丢帧问题,因而需要用多线程来解决视频丢帧问题。

     思路是:用定时器来不断的获取图像,然后立即向队列里缓存图像,然后再开一个线程来不断的从队列的头部取出,在从线程中进行图像处理。

     添加定时器的方法是 添加一个定时器消息。

      定时器的初始化是: SetTimer(1,300,NULL);//300ms

     定义一个结构体来存储图像(这个结构体的作用是将图像存储到结构体里,然后再从结构体传递给队列,个人理解)。结构体定义如下:

struct DataInfo
{
Mat pBuf;//缓存内容
int iSize;//缓存大小


DataInfo()
{
pBuf = NULL;
iSize = 0;
}
};

定义一个函数,用队列来存储图像。如下:

 void ImgBuffer(Mat image)
 {
if (hthread1 == NULL)
{
hthread1 = CreateThread(NULL, 0, thread_work, &image, 0, NULL);
InitializeCriticalSection(&m_lock);//线程锁初始化
}
else
{
DataInfo dataInfo;
dataInfo.pBuf = image;
EnterCriticalSection(&m_lock);//进入临界区
m_dq_buf.push(dataInfo);//把图像压入队列
LeaveCriticalSection(&m_lock);//退出临界区
}
 }

定义线程函数,从队列中取出来图像进行图像处理。函数如下:


 DWORD WINAPI thread_work(LPVOID IpParmeter)
 {
//当缓存队列中的数据大于0时,不断将数据取出进行处理
DataInfo dataInfo;//定义一个临时变量

while (1) {
if (m_dq_buf.size() > 0)
{
dataInfo  = m_dq_buf.front();//从队列中取得第一幅图像

Mat imgGray, imgHarris, harrisCorner;
cvtColor(dataInfo.pBuf, imgGray, CV_BGR2GRAY);//将彩色图像转换为灰度图
cornerHarris(imgGray, imgHarris, 2, 3, 0.001);//角点检测
threshold(imgHarris, harrisCorner, 0.00001, 255, THRESH_BINARY);//图像二值化
imshow("线程读取结果", dataInfo.pBuf);
imshow("角点检测", harrisCorner);



//使用临界区加锁
EnterCriticalSection(&m_lock);//进入临界区
m_dq_buf.pop();//将缓存从队列中删除
LeaveCriticalSection(&m_lock);//退出临界区
}
Sleep(500);//休眠500ms,也就是每隔500ms从队列中取一次图像进行处理
}
 }


遇到的问题:

1.如果不在初始化函数中添加

namedWindow("线程读取结果", WINDOW_AUTOSIZE);//若不初始化窗口,则会在主线程所创建的从线程中,图片显示灰色
namedWindow("角点检测", WINDOW_AUTOSIZE);//同上

则会出现窗口为灰色。

2.线程函数应该是一个死循环。


PS.我是做视觉的,某人是做飞控的,这个程序是某人帮我调出来的,结果他竟然说感觉他也就能帮我到这里了,后面的都要我自己来了。

2017-04-25 15:17:59 NBE999 阅读数 1914
  • MFC上位机与STM32下位机通讯精讲

    本课程主要介绍C++类库MFC上位机与STM32单片机的RS232、RS422、RS485、USB、LWIP以太网、CAN等接口进行稳定通信。课程主要从MFC和STM32基础开始,以编写上位机以及下位机为主,非常注重实践。

    9334 人正在学习 去看看 王凯杰


1)在VS开发环境,基于MFC创建一个名为ThreadProcess的工程,自动生成窗口类CThreadProcessDlg,一个ThreadProcessDlg.cpp和ThreadProcessDlg.h文件

2)在工具栏拉出一个Progress Control控件,默认ID:IDC_PROGRESS1,添加控件变量,设置其变量名为m_speed,

在该窗口类的头文件中的public中自动生成CProgressCtrl  m_speed;

3)添加3个按钮控件h和一个Edit Control控件(给其添加int型变量:m_Var1).窗口布局如下图:




4)在ThreadProcess.h文件中的private中添加全局变量

private:

HANDLE    m_ThreadSpeed;  //声明这个句柄是用于接受创建线程时返回的句柄,可以使用这个句柄对线程控制

5)自己新建.h文件,在该文件中自定义一个结构体,用于传递参数到多线程函数中去。新建.h文件方法:在解决方案中选择   “头文件” -》右键 -》添加  -》新建项 ,选择头文件-》输入名称。我这里的名称为“ThreadFuantion.h”。下面是我新建的头文件中添加的内容。主要是建立了一个结构体,用于存储需要传递到多线程程序中的各种类型的变量

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


typedef struct tag_Param
{
	HANDLE hMutex;
	int thread_id;
	int var1;
	int var2;
	CWnd* kk;
	bool bStop;
}TESTPARAM;

6)在ThreadProcessDlg.h文件中申明一个结构体。

private:
TESTPARAM TestParam;

7)双击窗体中的【开始】按钮  在其响应函数中创建一个线程:

//开始
void CThreadProcessDlg::OnBnClickedButton1()
{
	m_ThreadSpeed = CreateThread(\
	0,				//lpThreadAttributes:指向SECURITY_ATTRIBUTES型态的结构的指针。
	0,				//dwStackSize,   设置初始栈的大小,以字节为单位,如果为0,那么默认将使用与调用该函数的线程相同的栈空间大小
	ThreadSpeed,	//lpStartAddress,指向线程函数的指针,形式:@函数名,函数名称没有限制,
					//但是必须以下列形式声明:DWORD WINAPI 函数名 (LPVOID lpParam) ,格式不正确将无法调用成功。
	reinterpret_cast<LPVOID *>(&TestParam),//向线程函数传递的参数,是一个指向结构的指针,不需传递参数时,为NULL。
	0,				//线程标志,可取值如下 a) CREATE_SUSPENDED(0x00000004):创建一个挂起的线程,  b) 0:表示创建后立即激活。c)...	
	0);				//保存新线程的id。
//	CloseHandle(m_ThreadSpeed);     //一般创建后马上关闭线程句柄,因为主线程不关系创建的新线程。如果创建新线程后马上注销的话,
								    //不能再对线程进行 挂起  唤醒等操作
}

注意:对结构体类型的强制转换,非常必要!!!

8)双击【+1】添加如下代码     每按一次【+1】按钮变量m_Var1自增10;
void CThreadProcessDlg::OnBnClickedButton2()
{
	// TODO: 在此添加控件通知处理程序代码
	m_Var1+=10;
	TestParam.kk = this;
	TestParam.var1=m_Var1;
	UpdateData(false);
}
9)8)双击【-1】添加如下代码     每按一次【-1】按钮变量m_Var1自减10;
void CThreadProcessDlg::OnBnClickedButton3()
{
	// TODO: 在此添加控件通知处理程序代码
	m_Var1-=10;
	TestParam.kk = this;
	TestParam.var1=m_Var1;
	TestParam.var2=m_Var1;
	UpdateData(false);
}

10)同样在ThreadProcessDlg.cpp文件中添加开辟新线程的执行函数

//线程函数的实现
DWORD WINAPI CThreadProcessDlg::ThreadSpeed(LPVOID lpParameter)
{
	int Count;
	TESTPARAM *ptr=reinterpret_cast<TESTPARAM *>(lpParameter);   //lpParameter参数带来了丰富的信息,具体自己可以在结构体中定义
	CThreadProcessDlg *Dlg=(CThreadProcessDlg *)ptr->kk;         //TestParam.kk = this;将主窗口的指针带回,方便获取其中变量和资源
	CWnd * pwnd = Dlg->GetDlgItem(IDC_PROGRESS1);                //通过窗体指针,获取进度条的句柄
	CProgressCtrl *Speed = (CProgressCtrl*)pwnd; 		     //获取进度条的指针,从而方便在新开辟的线程中对其操作
	Speed->SetRange(0,100);					     //设置进度条的范围
	while(1)					             //while(1)循环,只要主线程中的m_Var1改变,我们就能在进度条上反映出来
	{
		Speed->SetPos(Dlg->m_Var1);
		_sleep(200);
	}
	return 0;
}
 

最终实现:按下【开始】开辟新线程,  按下【+1】或【-10】改变m_Var1,自定义的结构将改变的变量传递给线程执行的函数。从而改变进度条的位置。

 

          













2017-07-15 22:32:15 Dangkie 阅读数 1356
  • MFC上位机与STM32下位机通讯精讲

    本课程主要介绍C++类库MFC上位机与STM32单片机的RS232、RS422、RS485、USB、LWIP以太网、CAN等接口进行稳定通信。课程主要从MFC和STM32基础开始,以编写上位机以及下位机为主,非常注重实践。

    9334 人正在学习 去看看 王凯杰

本文介绍MFC中图像采集及图像处理的多线程编方法。创建了三个线程,分别为图像采集、图像处理及图像显示线程。线程之间的共享数据有保存的图像链表和图像处理结果存储结构。

图像链表:list<Hobject> imgList;
存储结构体:
struct ResultContainer
{
Hobject result_img;
HTuple time_needed;
HTuple result_handle;
HTuple result_data;
};

创建4个事件保证线程同步性

HANDLE  fgStopEvent;
HANDLE  newImageEvent;
HANDLE  newResultEvent;
HANDLE  containerIsFreeEvent;

使用2个关键段保证共享数据使用的互斥性

CRITICAL_SECTION    newImageMutex;
CRITICAL_SECTION    resultDataMutex;

同时在头文件中加入私有成员变量:

HANDLE             dispThrHandle;        //Win32线程句柄        
unsigned int       dispThreadId;         //Win32线程标识符  
HANDLE             ipThrHandle;          //Win32线程句柄
unsigned int       ipThreadId;           //Win32线程标识符
HANDLE             fgThrHandle;          //Win32线程句柄
unsigned int       fgThreadId;           //Win32线程标识符
  1. 在初始化中进行关键段的初始化,创建线程等其他数据初始化过程:
    关键段初始化:
  InitializeCriticalSection(&newImageMutex);    
  InitializeCriticalSection(&resultDataMutex);

设置事件句柄以同步线程:

fgStopEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
newImageEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
newResultEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
containerIsFreeEvent =CreateEvent(NULL,FALSE,TRUE,NULL);

初始化共享数据:

resultData.time_needed = NULL; 
resultData.result_img = NULL;
resultData.result_handle = NULL;
resultData.result_data = NULL;

其他:

ResetEvent(fgStopEvent);    //设置fgStopEvent为无信号状态
InitialGrabOfImage();       //图像采集初始化
  1. 设置一个启动按钮,开启线程,线程开启函数如下:
void CMultiThreading::StartThreads()
{
  //所有事件设置为初始状态
  ResetEvent(fgStopEvent);
  ResetEvent(newImageEvent);
  ResetEvent(newResultEvent);
  SetEvent(containerIsFreeEvent);

  imgList.clear();

// 开启线程 
  dispThrHandle = (HANDLE)_beginthreadex(NULL0, 
                (unsigned (__stdcall *)(void*))&DISPRun, 
                 this,                  
                 0,                 
                 &dispThreadId);            

  ipThrHandle = (HANDLE)_beginthreadex(NULL, 0,                 
                (unsigned (__stdcall *)(void*))&IPRun,  
                 this,                  
                 0,                 
                 &ipThreadId);              

  fgThrHandle = (HANDLE)_beginthreadex(NULL, 0,                 
              (unsigned (__stdcall *)(void*))&ImgAcqRun,    
              this,                 
               0,                   
              &fgThreadId);
}
  1. 设置一个停止按钮,停止所有线程,只需将停止事件设置为有信号状态:
SetEvent(fgStopEvent); 
  1. 图像采集线程:
void ImgAcqRun(void *pars)
{
  HTuple      sequenceName;
  Hobject     grabbedImage;
  Hlong       FGHandle;

  CMultiThreadingDlg *MultiThrDlg = (CMultiThreadingDlg*) pars;

  // ---------------------  INIT  ----------------------
  sequenceName = "datacode/ecc200/ecc200.seq";
  open_framegrabber("File",1,1,0,0,0,0,"default",-1,
  "default",-1,"default",sequenceName,
  "default",-1,-1,&FGHandle);


  // -----------------  WAIT FOR EVENTS  ---------------
  while (WAIT_OBJECT_0 != WaitForSingleObject((MultiThrDlg->fgStopEvent),0))    //Stop按钮没有触发
  {

    grab_image_async(&grabbedImage,FGHandle,-1);        
    EnterCriticalSection(&MultiThrDlg->newImageMutex);        // CriticalSect关键段
    if((MultiThrDlg->imgList).size()<MAX_BUFFERS)                     
    {                                                                                       
      (MultiThrDlg->imgList).push_back(grabbedImage);              
    }                                                                                      
    LeaveCriticalSection(&MultiThrDlg->newImageMutex);        // CriticalSect

    SetEvent(MultiThrDlg->newImageEvent);   //触发事件
  }

  // -----------------  RESET/CLOSE ALL HANDLES  -------
  ResetEvent( MultiThrDlg->newImageEvent);
  close_framegrabber(FGHandle);

  return;
}
  1. 图像处理线程:
void IPRun(void *pars)
{

  HTuple      T1,resultHandles,T2;
  Hobject     result_data, image;
  CString     sVal;
  HANDLE      eventHandle[2];

  struct ResultContainer ResultDataIP;
  CMultiThreadingDlg *MultiThrDlg = (CMultiThreadingDlg*) pars;     

  // --------------------  INIT ------------------------
  //图像初始化操作

  // -----------------  WAIT FOR EVENTS  ---------------
  eventHandle[0] = (*MultiThrDlg).newImageEvent; 
  eventHandle[1] = (*MultiThrDlg).fgStopEvent;  

  while (WAIT_OBJECT_0 == WaitForMultipleObjects(2,eventHandle,
                                                 FALSE,INFINITE))
  {
    EnterCriticalSection(&MultiThrDlg->newImageMutex);      // CriticalSect
    image =  (MultiThrDlg->imgList).front();    
    MultiThrDlg->imgList.pop_front();   
    LeaveCriticalSection(&MultiThrDlg->newImageMutex);        // CriticalSect

    count_seconds(&T1);
    //图像处理过程
    count_seconds(&T2);

    ResultDataIP.time_needed   = 1000*(T2[0].D() - T1[0].D());
    ResultDataIP.result_img    = image;  
    ResultDataIP.result_handle = resultHandles;
    ResultDataIP.result_data   = result_data;   

    WaitForSingleObject(MultiThrDlg->containerIsFreeEvent,INFINITE);
    EnterCriticalSection(&MultiThrDlg->resultDataMutex); 
// CriticalSect     
    MultiThrDlg->resultData = ResultDataIP;   
// CriticalSect                
    LeaveCriticalSection(&MultiThrDlg->resultDataMutex);     

    ResetEvent(MultiThrDlg->containerIsFreeEvent);
    SetEvent( MultiThrDlg->newResultEvent); 
  }

  // -----------------  RESET/CLOSE ALL HANDLES  -------
  ResetEvent(MultiThrDlg->newResultEvent);

  return;
}
  1. 显示线程:
void DISPRun(void *pars)
{

  HTuple      time,resultHandles,i;
  Hobject     result_data, image;
  CString     sVal;
  Hlong       wWindowID;
  CRect       rect; 
  HANDLE      eventHandle[2];

  struct ResultContainer rData;
  CMultiThreadingDlg *MultiThrDlg = (CMultiThreadingDlg*) pars;
  wWindowID = (Hlong)MultiThrDlg->ipWinStatic.m_hWnd;
  MultiThrDlg->ipWinStatic.GetClientRect(&rect);


  // --------------------  INIT  -----------------------

  set_check("~father");
     open_window(0,0,rect.Width(),rect.Height(),wWindowID,
    "visible","", &(MultiThrDlg->windowID));
  set_check("father");

  set_window_attr("border_width",0);
  set_part(MultiThrDlg->windowID,0,0,MultiThrDlg->height-1,
           MultiThrDlg->width-1);
  set_color((MultiThrDlg->windowID),"green");
  set_line_width(MultiThrDlg->windowID,3);


  eventHandle[0] = ((*MultiThrDlg).newResultEvent); 
  eventHandle[1] = ((*MultiThrDlg)).fgStopEvent;  


  // -----------------  WAIT FOR EVENTS  ---------------
  while (WAIT_OBJECT_0 == WaitForMultipleObjects(2,eventHandle,
                                                 FALSE,INFINITE))
  {   
    EnterCriticalSection(&MultiThrDlg->resultDataMutex);      // CriticalSect
    rData = MultiThrDlg->resultData;                          // CriticalSect
    LeaveCriticalSection(&MultiThrDlg->resultDataMutex);      
    SetEvent(MultiThrDlg->containerIsFreeEvent);                 

    time               = rData.time_needed;
    image              = rData.result_img;  
    resultHandles      = rData.result_handle;
    result_data         = rData.result_data;    

    disp_obj(image,HTuple(MultiThrDlg->windowID));

    sVal.Format("%4.2f",time[0].D());
    (MultiThrDlg->ipProcTime).SetWindowText(sVal + " ms");

    disp_obj(symbolXLDs,HTuple(MultiThrDlg->windowID));

    for (i=0; i<=(resultHandles.Num())-1; i+=1)
    {
      (MultiThrDlg->ipImgLabel).SetWindowText(decodedDataStrings[i]);
    }  
  }

  // -----------------  RESET/CLOSE  ALL HANDLES  ------
  close_window(MultiThrDlg->windowID);
  SetEvent(MultiThrDlg->containerIsFreeEvent);
  MultiThrDlg->ipProcTime.SetWindowText("");

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