CY7C68013_AD5933_上位机
目录
1、CreateEvent()控制线程
(1)CreateEvent()函数相关
CreateEvent是一个Windows API函数。它用来创建或打开一个命名的或无名的事件对象。可以在一个线程的执行函数中创建一个事件对象,然后观察它的状态,“有信号”(触发,开,true),如果是”无信号”(未触发,关,false)就让该线程睡眠,这样该线程占用的CPU时间就比较少:
HANDLE CreateEvent ( LPSECURITY_ATTRIBUTES lpEventAttributes, // SD 一般为空 BOOL bManualReset, // reset type 事件是自动复位(false)还是人工复位(true) BOOL bInitialState, // initial state 初始状态,有信号(true),无信号(false) LPCTSTR lpName // object name 事件对象名称 ); ******
代码中CreateEvent默认初始状态是true即有信号状态,当执行waitForSingleObject时不会等待。 并且是自动复位的,在执行waitForSingleObject之后会变成未触发(无信号)状态。
bManualReset:TRUE,使用ResetEvent()手动重置为无信号状态;FALSE,当一个等待线程被释放时,自动重置状态为无信号状态。
bInitialState:指定事件对象的初始状态,当TRUE,初始状态为有信号状态;当FALSE,初始状态为无信号状态。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 lpEventAttributes[输入] 2 一个指向SECURITY_ATTRIBUTES结构的指针,确定返回的句柄是否可被子进程继承。如果lpEventAttributes是NULL,此句柄不能被继承。 3 Windows NT/2000:lpEventAttributes的结构中的成员为新的事件指定了一个安全符。如果lpEventAttributes是NULL,事件将获得一个默认的安全符。 4 bManualReset[输入] 5 指定将事件对象创建成手动复原还是自动复原。如果是TRUE,那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态。如果设置为FALSE,当一个等待线程被释放以后,系统将会自动将事件状态复原为无信号状态。 6 bInitialState[输入] 7 指定事件对象的初始状态。如果为TRUE,初始状态为有信号状态;否则为无信号状态。 8 lpName[输入] 9 指定事件的对象的名称,是一个以0结束的字符串指针。名称的字符格式限定在MAX_PATH之内。名字是对大小写敏感的。 10 如果lpName指定的名字,与一个存在的命名的事件对象的名称相同,函数将请求EVENT_ALL_ACCESS来访问存在的对象。这时候,由于bManualReset和bInitialState参数已经在创建事件的进程中设置,这两个参数将被忽略。如果lpEventAttributes是参数不是NULL,它将确定此句柄是否可以被继承,但是其安全描述符成员将被忽略。 11 如果lpName为NULL,将创建一个无名的事件对象。
(2)Event相关
一个Event被创建以后,可以用OpenEvent()来获得它的Handle,用CloseHandle()来关闭它(在主线程中使用CloseHandle()函数,很有可能导致子线程的Event对象信号控制机制失效,但需要将Event关闭,否则容易造成句柄泄漏问题,故合理使用关闭句柄函数);用SetEvent()或PulseEvent()来设置它使其有信号,用ResetEvent() 来使其无信号,用WaitForSingleObject()或WaitForMultipleObjects()来等待其变为有信号.
SetEvent(HANDLE hEvent ); PulseEvent(HANDLE hEvent ); ResetEvent(HANDLE hEvent );
PulseEvent()是一个比较有意思的使用方法,正如这个API的名字,它使一个Event 对象的状态发生一次脉冲变化,从无信号变成有信号再变成无信号,而整个操作是原子的.
对自动复位的Event对象,它仅释放第一个等到该事件的thread(如果有),而对于人工复位的Event对象,它释放所有等待的thread.
这里有两个API函数用来修改事件对象的信号状态:SetEvent和ResetEvent。前者把事件对象设为”有信号”状态,而后者正好相反。
在事件对象生成后,必须调用WaitForSingleObject来让线程进入等待状态,该函数的语法如下:
WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);
hHandle-->指向同步对象的指针。事件对象其实是同步对象的一种。
dwMilliseconds--> 等待同步对象变成”有信号”前等待的时间,以毫秒计。当等待的时间超过该值后无信号同步对象仍处于”无信号”状态,线程不再等待, WaitForSingleObject函数会返回WAIT_TIMEOUT。如果想要线程一直等待,请把该参数设为INFINITE(该值等于0xffffffff)为一直等待。
参考博客:
https://blog.csdn.net/richerg85/article/details/7471426 有具体例子
https://blog.csdn.net/u011028345/article/details/78358324 定义
2、OVERLAPPED结构体
OVERLAPPED即OVERLAPPED是一个包含了用于异步输入输出的信息的结构体。
第一种声明:
typedef struct _OVERLAPPED { DWORD Internal; DWORD InternalHigh; DWORD Offset; DWORD OffsetHigh; HANDLE hEvent; } OVERLAPPED
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 Internal: 预留给操作系统使用。它指定一个独立于系统的状态,当GetOverlappedResult函数返回时没有设置扩展错误信息ERROR_IO_PENDING时有效。 2 InternalHigh: 预留给操作系统使用。它指定长度的数据转移,当GetOverlappedResult函数返回TRUE时有效。 3 Offset: 该文件的位置是从文件起始处的字节偏移量。调用进程设置这个成员之前调用ReadFile或WriteFile函数。当读取或写入命名管道和通信设备时这个成员被忽略设为零。 4 OffsetHigh: 指定文件传送的字节偏移量的高位字。当读取或写入命名管道和通信设备时这个成员被忽略设为零。 5 hEvent: 在转移完成时处理一个事件设置为有信号状态。调用进程集这个成员在调用ReadFile、 WriteFile、TransactNamedPipe、 ConnectNamedPipe函数之前。
第二种声明:
typedef struct _OVERLAPPED { ULONG_PTR Internal; //操作系统保留,指出一个和系统相关的状态 ULONG_PTR InternalHigh; //指出发送或接收的数据长度 union { struct { DWORD Offset; //文件传送的字节偏移量的低位字 DWORD OffsetHigh; //文件传送的字节偏移量的高位字 }; PVOID Pointer; //指针,指向文件传送位置 }; HANDLE hEvent; //指定一个I/O操作完成后触发的事件 } OVERLAPPED, *LPOVERLAPPED;
3、Qt多线程
(1) 使用重写QTread类中的虚函数:run()
新建一个类并继承QThread,然后重新改写类QThread中的虚函数run()。当要开启新线程时,只需要实例该类(即创建该类的对象),然后调用函数start(),就可以开启一条多线程(执行run()中的代码)
创建多线程步骤如下:
a1新建一个类MyThread,基类为QThread。
a2重写类MyThread的虚函数void run();,即新建一个函数protected void run(),然后对其进行定义。
a3在类MyThread中定义方法clseThread(),并定义标志位isStop,在run()函数中判断isStop的状态,如果为ture则退出线程(即退出run()函数)
a3在需要用到多线程的地方,实例MyThread,然后调用函数MyThread::start()后,则开启一条线程,即自动运行函数run()。
a4当停止线程时,调用MyThread::wait()函数,等待线程结束,并且回收线程资源。
1)创建一个Qt工程,并放入两个按钮进去;
2)新建一个MyThread类,先新建一个mythread.h文件和mythread.cpp文件,自己定义run()和closeThread()方法,并定义线程结束或者是开始标志位isStop
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #ifndef MYTHREAD_H 2 #define MYTHREAD_H 3 4 #include <QThread> 5 6 class MyThread : public QThread 7 { 8 private: 9 volatile bool isStop; //volatile关键字确保本条指令不会因为编译器的优化而省略 10 protected: 11 virtual void run(); 12 public: 13 MyThread(); //构造函数 14 void closeThread(); 15 }; 16 17 #endif // MYTHREAD_H
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include "mythread.h" 2 #include <QDebug> 3 #include <QMutex> 4 5 //构造函数,对私有变量进行初始化 6 MyThread::MyThread() 7 { 8 isStop=false; 9 } 10 11 void MyThread::run() 12 { 13 isStop=false; //如果不加上这一句,在第二次运行时,isStop就保持了上一次等于true的状态,从进入run函数只有就退出了 14 while(1) 15 { 16 if(isStop) 17 return; //退出run()函数 18 qDebug()<<tr("mythread Qthread::currentThreadId()=")<<QThread::currentThreadId(); 19 sleep(1); 20 } 21 } 22 23 void MyThread::closeThread() 24 { 25 isStop=true; 26 }
3)编写widget.h和widget.cpp
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #ifndef WIDGET_H 2 #define WIDGET_H 3 4 #include <QWidget> 5 #include "mythread.h" 6 #include <QDebug> 7 8 namespace Ui { 9 class Widget; 10 } 11 12 class Widget : public QWidget 13 { 14 Q_OBJECT 15 16 public: 17 explicit Widget(QWidget *parent = 0); 18 ~Widget(); 19 private slots: 20 void openThreadBtnSlot(); //打开线程按钮对应的槽函数 21 void closeThreadBtnSlot(); //关闭线程按钮对应的槽函数 22 void finishedThreadBtnSlot(); //线程结束会发出一个finished()信号,该信号对应这个槽函数 23 24 private: 25 Ui::Widget *ui; 26 MyThread *thread1; //创建线程对象 27 }; 28 29 #endif // WIDGET_H
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include "widget.h" 2 #include "ui_widget.h" 3 4 5 Widget::Widget(QWidget *parent) : 6 QWidget(parent), 7 ui(new Ui::Widget) 8 { 9 ui->setupUi(this); 10 11 thread1 = new MyThread; //线程初始化 12 13 connect(ui->StartThreadPushButton,SIGNAL(clicked(bool)),this,SLOT(openThreadBtnSlot())); //关联线程打开按钮和开启线程的槽函数 14 connect(ui->QuitThreadPushButton,SIGNAL(clicked(bool)),this,SLOT(closeThreadBtnSlot())); //关联线程关闭按钮和关闭线程的槽函数 15 connect(thread1,SIGNAL(finished()),this,SLOT(finishedThreadBtnSlot())); //关联线程结束信号finished()和该信号对应的槽函数 16 } 17 18 //打开线程对应的槽函数 19 void Widget::openThreadBtnSlot() 20 { 21 thread1->start(); //开启thread1对应的线程,执行类MyTread中的run() 22 qDebug()<<tr("Main Thread id: ")<<QThread::currentThreadId(); 23 } 24 25 //关闭线程对应的槽函数 26 void Widget::closeThreadBtnSlot() 27 { 28 thread1->closeThread(); //关闭线程thread1,即不再执行MyThread类中的槽函数 29 thread1->wait(); 30 } 31 32 //关闭线程后会触发线程的一个finished()信号,该信号对应下面的这个槽函数 33 void Widget::finishedThreadBtnSlot() 34 { 35 qDebug()<<tr("Thread End Signal finished() has benn touched"); 36 } 37 38 Widget::~Widget() 39 { 40 delete ui; 41 }
运行结果:
参考博客:
https://blog.csdn.net/naibozhuan3744/article/details/81174681
(2)使用一个槽函数运行所有的线程代码
新建一个类Mythrea,并继承对象QObject,来实现多线程。
利用继承QObject方法创建多线程,主要的步骤有一下几点:(注意:退出线程循环后,还要调用QThread::quit()函数,该线程才会触发QThread::finished()信号)
a1:首先创建一个类MyThread,基类为QObject。
a2:在类MyThread中创建一个槽函数,用于运行多线程里面的代码。所有耗时代码,全部在这个槽函数里面运行。在MyThread类中新建一个closeThread()共有函数,用于关闭线程(退出MyThread类中用于执行线程 代码的槽函数)
a3:实例一个QThread线程对象(容器),将类MyThread的实例对象转到该容器中,用函数void QObject::moveToThread(QThread *thread);
1 myThread->moveToThread(thread1); //thread1是QThread类对象,myThread是MyThread类对象
a4:用一个信号触发该多线程槽函数,比如用QThread::started()信号。
1 connect(thread1,SIGNAL(started()),myThread,SLOT(startThreadSlot())); //startThreadSlot()是MyThread类中用于执行线程代码的槽函数
a5:用信号QThread::finished绑定槽函数QThread::deleteLatater(),在线程退出时,销毁该线程和相关资源。
1 connect(thread1,SIGNAL(finished()),myThread,SLOT(deleteLater())); //deleteLater()是QObject类中的一个函数
a6:所有线程初始化完成后,启动函数QThread::start()开启多线程,然后自动触发多线程启动信号QThread::started()。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #ifndef MYTHREAD_H 2 #define MYTHREAD_H 3 4 #include <QObject> 5 6 class MyThread : public QObject 7 { 8 Q_OBJECT 9 private: 10 volatile bool isStop; //volatile关键字确保本条指令不会因为编译器的优化而省略 11 12 public: 13 explicit MyThread(QObject *parent = nullptr); //构造函数 14 void closeThread(); //关闭线程 15 16 public slots: 17 void startThreadSlot(); //开启线程槽函数 18 }; 19 20 #endif // MYTHREAD_H
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include "mythread.h" 2 #include <QDebug> 3 #include <QTHread> 4 5 //构造函数,对私有变量进行初始化 6 MyThread::MyThread(QObject *parent) : QObject(parent) 7 { 8 isStop=false; 9 } 10 11 void MyThread::startThreadSlot() 12 { 13 isStop=false; //如果不加上这一句,在第二次运行时,isStop就保持了上一次等于true的状态,从进入run函数只有就退出了 14 while(1) 15 { 16 if(isStop) 17 return; //退出run()函数 18 qDebug()<<tr("mythread Qthread::currentThreadId()=")<<QThread::currentThreadId(); 19 QThread::sleep(1); 20 } 21 } 22 23 //关闭线程 24 void MyThread::closeThread() 25 { 26 isStop=true; 27 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #ifndef WIDGET_H 2 #define WIDGET_H 3 4 #include "mythread.h" 5 #include <QWidget> 6 #include <QThread> 7 #include <QDebug> 8 9 namespace Ui { 10 class Widget; 11 } 12 13 class Widget : public QWidget 14 { 15 Q_OBJECT 16 17 public: 18 explicit Widget(QWidget *parent = 0); 19 ~Widget(); 20 private slots: 21 void openThreadBtnSlot(); //打开线程按钮对应的槽函数 22 void closeThreadBtnSlot(); //关闭线程按钮对应的槽函数 23 void finishedThreadBtnSlot(); //线程结束会发出一个finished()信号,该信号对应这个槽函数 24 25 private: 26 Ui::Widget *ui; 27 QThread *thread1; 28 MyThread *myThread; 29 }; 30 31 #endif // WIDGET_H
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include "widget.h" 2 #include "ui_widget.h" 3 #include <QThread> 4 5 Widget::Widget(QWidget *parent) : 6 QWidget(parent), 7 ui(new Ui::Widget) 8 { 9 ui->setupUi(this); 10 11 connect(ui->StartThreadPushButton,SIGNAL(clicked(bool)),this,SLOT(openThreadBtnSlot())); //关联线程打开按钮和开启线程的槽函数 12 connect(ui->QuitThreadPushButton,SIGNAL(clicked(bool)),this,SLOT(closeThreadBtnSlot())); //关联线程关闭按钮和关闭线程的槽函数 13 14 } 15 16 //开始线程按钮对应的槽函数 17 void Widget::openThreadBtnSlot() 18 { 19 qDebug()<<tr("statr thread"); 20 thread1 = new QThread; //线程容器初始化 21 myThread = new MyThread; //初始化 22 23 myThread->moveToThread(thread1); //将创建的对象移到线程容器thread1中去 24 25 connect(thread1,SIGNAL(finished()),myThread,SLOT(deleteLater())); //线程终止时要调用deleteLater槽函数,deleteLater()是QObject类中的槽函数 26 connect(thread1,SIGNAL(started()),myThread,SLOT(startThreadSlot())); //关联线程thread1开始信号和myThread中的槽函数,startThreadSlot()是MyThread类中的槽函数 27 connect(thread1,SIGNAL(finished()),this,SLOT(finishedThreadBtnSlot())); //关联线程结束信号finished()和该信号对应的槽函数,finishedThreadBtnSlot()是Widget类中的槽函数 28 29 thread1->start(); //开启线程,执行MyThread类中的槽函数startThreadSlot() 30 qDebug()<<"mainWidget QThread::currentThreadId()="<<QThread::currentThreadId(); 31 } 32 33 //关闭线程对应的槽函数 34 void Widget::closeThreadBtnSlot() 35 { 36 qDebug()<<"close the thread"; 37 if(thread1->isRunning()) 38 { 39 myThread->closeThread(); //关闭线程槽函数 40 thread1->quit(); //退出循环事件 41 thread1->wait(); //释放线程槽函数资源 42 } 43 } 44 45 //关闭线程后会触发线程的一个finished()信号,该信号对应下面的这个槽函数 46 void Widget::finishedThreadBtnSlot() 47 { 48 qDebug()<<tr("Thread End Signal finished() has benn touched"); 49 } 50 51 Widget::~Widget() 52 { 53 delete ui; 54 }
运行结果:
参考博客:
https://blog.csdn.net/naibozhuan3744/article/details/81201502
4、Qt添加CyAPI.lib库
(1)在C:\Cypress\Cypress Suite USB 3.4.7\CyAPI\lib\x64路径下找到CyAPI.lib文件放到工程路径下,后执行下面的操作:
(2)添加步骤
#pragma comment(lib,*User32.lib)
上图还是把“为debug版本添加'd'作为后缀去掉吧”
然后会报错:CyAPId.lib文件不存在,解决方法如下:
->
->
错误即可消失,刚刚完成库添加之后可能执行qmake是灰色的的,但是等一会是可以的
但是只是添加CyAPI.lib也是可以的,并没有添加别的库文件