精华内容
下载资源
问答
  • 多线程串口通信

    千次阅读 2017-04-27 15:02:16
    多线程实现串口通信 备注:用了刘大师的“QT多线程示例+一种通用高并发数据处理最简单思路”思路,在模仿刘大师的基础上增加了串口通信功能; 截图如下: 说明: 1、线程数量:3(GUI、串口...
    多线程实现串口通信
    备注:用了刘大师的“ QT多线程示例+一种通用高并发数据处理最简单思路”思路,在模仿刘大师的基础上增加了串口通信功能;


    截图如下:

    说明:
    1、线程数量:3(GUI、串口读写线程、数据处理线程)
    2、左上角的两个LineEdit 作为串口的两路数据来源,串口读取数据时对两路数据添加了标记(一路加“*”标记,一路加“#”标记);
    3、串口读写按钮:控制串口读写数据的开始与停止
    4、显示按钮:控制界面的显示
    5、串口:虚拟串口软件

    运行效果:


    存在问题:因为使用的虚拟串口,则需要同时运行两个界面,一个充当串口发送端,一个充当串口接收端,也正因此,接受界面的串口停止按钮被按下、关闭显示时,会有点小问题,如果不是虚拟串口,此问题应该可以避免。

    代码:多线程串口通信|http://www.qtcn.org/bbs/read-htm-tid-62982.html
    虚拟软件:百度网盘 点击打开链接
    展开全文
  • 多线程串口通信.pdf

    2021-09-30 20:25:39
    多线程串口通信.pdf
  • 异步多线程串口通信

    2018-06-26 17:18:57
    VC实现的多线程实现的串口异步通信 VC实现的多线程实现的串口异步通信
  • 多线程串口通信技术及应用.pdf
  • 在开发串口通讯的时候一直用的微软的,顺序执行,后来找到一个可以用多线程的帮组类,共享给大家,本人测试过xmodel都可以使用 ,调试也很方便,
  • 多线程串口通讯

    2014-10-21 00:20:27
    * 模块名称:多线程串口通讯类(MultiThread Com class) * 主要类说明(Main class): * CComPort 串口类 内聚合一个CSerialPort类用于串口的操作 * 接收模式说明(Receive Mode): * 1.ManualReceiveByQuery, //手动...
  • 多线程串口通信 源代码 学习和实践的标本
  • 多线程串口通讯实例源码分析,主要是在windows下 用MFC编程 实现excel读数据
  • CnComm v1.50 多线程串口通讯库 已经更新至V1.51版
  • Qt下实现多线程串口通信

    千次阅读 2019-05-20 07:19:37
    Qt下实现多线程串口通信 Qt下无论是RS232、RS422、RS485的串口通信都可以使用统一的编码实现。本文把每路串口的通信各放在一个线程中,使用movetoThread的方式实现。 用SerialPort类实现串口功能,Widget类调用...

    Qt下实现多线程串口通信

    Qt下无论是RS232RS422RS485的串口通信都可以使用统一的编码实现。本文把每路串口的通信各放在一个线程中,使用movetoThread的方式实现。

    SerialPort类实现串口功能,Widget类调用串口。

    serialport.h如下:

    #include <QObject>

    #include <QSerialPort>

    #include <QString>

    #include <QByteArray>

    #include <QObject>

    #include <QDebug>

    #include <QObject>

    #include <QThread>

     

    class SerialPort : public QObject

    {

      Q_OBJECT

    public:

      explicit SerialPort(QObject *parent = NULL);

      ~SerialPort();

     

      void init_port();  //初始化串口

     

    public slots:

      void handle_data();  //处理接收到的数据

      void write_data();     //发送数据

     

    signals:

      //接收数据

      void receive_data(QByteArray tmp);

     

    private:

      QThread *my_thread;

      QSerialPort *port;

    };

    serailport.cpp如下

    #include "serialport.h"

     

    SerialPort::SerialPort(QObject *parent) : QObject(parent)

    {

        my_thread = new QThread();

     

        port = new QSerialPort();

        init_port();

        this->moveToThread(my_thread);

        port->moveToThread(my_thread);

        my_thread->start();  //启动线程

     

    }

     

    SerialPort::~SerialPort()

    {

        port->close();

        port->deleteLater();

        my_thread->quit();

        my_thread->wait();

        my_thread->deleteLater();

    }

     

    void SerialPort::init_port()

    {

        port->setPortName("/dev/ttyS1");                   //串口名 windows下写作COM1

        port->setBaudRate(38400);                           //波特率

        port->setDataBits(QSerialPort::Data8);             //数据位

        port->setStopBits(QSerialPort::OneStop);           //停止位

        port->setParity(QSerialPort::NoParity);            //奇偶校验

        port->setFlowControl(QSerialPort::NoFlowControl);  //流控制

        if (port->open(QIODevice::ReadWrite))

        {

            qDebug() << "Port have been opened";

        }

        else

        {

            qDebug() << "open it failed";

        }

        connect(port, SIGNAL(readyRead()), this, SLOT(handle_data()), Qt::QueuedConnection); //Qt::DirectConnection

    }

     

    void SerialPort::handle_data()

    {

        QByteArray data = port->readAll();

        qDebug() << QStringLiteral("data received(收到的数据):") << data;

        qDebug() << "handing thread is:" << QThread::currentThreadId();

        emit receive_data(data);

    }

     

    void SerialPort::write_data()

    {

        qDebug() << "write_id is:" << QThread::currentThreadId();

        port->write("data", 4);   //发送“data”字符

    }

    widget.h的调用代码

    #include "serialport.h"

    public slots:

      void on_receive(QByteArray tmpdata);

    private:

      SerialPort *local_serial;

    widget.cpp调用代码

    //构造函数中

    local_serial = new QSerialPort();

    connect(ui->pushButton, SIGNAL(clicked()), local_serial, SLOT(write_data()));

    connect(local_serial, SIGNAL(receive_data(QByteArray)), this, SLOT(on_receive(QByteArray)), Qt::QueuedConnection);

    //on_receive槽函数

    void Widget::on_receive(QByteArray tmpdata)

    {

     ui->textEdit->append(tmpdata);

    }

    本文例子实现的串口号是 /dev/ttyS1(对应windows系统是COM1口),波特率38400,数据位8,停止位1,无校验位的串口通信。当然,使用串口程序前,需要在.pro文件中添加 QT += serialport,把串口模块加入程序。

    展开全文
  • Qt练习:多线程串口通信

    千次阅读 2020-04-06 22:14:42
    最近在学习Qt编程,为了练手,想做一个串口通信的小软件为之后的项目做准备,经过几天的学习与练习初步搭建起了多线程串口通信的框架及较少的其他功能 功能简介 串口接收 主线程显示ui,子线程接收串口数据,数据...

    最近在学习Qt编程,为了练手,想做一个串口通信的小软件为之后的项目做准备,经过几天的学习与练习初步搭建起了多线程串口通信的框架及较少的其他功能

    功能简介

    1. 串口接收
    2. 主线程显示ui,子线程接收串口数据,数据通过信号和槽发送到主线程
    3. 打开串口启动子线程,关闭串口后关闭子线程
    4. 采用定时器延时方法读取缓存区的数据
    5. 自行选择串口号与波特率,默认数据位为8、停止位为1、无奇偶校验
    6. 16进制显示项目中暂未用到,程序附在最后留存

    界面设计

    由于以后要进行其他数据的解析,用于测试的界面很简单,只设计了很少的控件,UI界面设计如下:
    在这里插入图片描述
    在这里插入图片描述

    子线程

    最开始练习时设计过单线程的串口助手,但是当数据量太大时软件会卡死,因此这次采用了多线程设计。
    首先创建子线程类serialThread,并创建QSerialPort对象及相关初始化方法,主要代码如下:

    serialthread.h

    #ifndef SERIALTHREAD_H
    #define SERIALTHREAD_H
    
    #include<QThread>
    #include<QDebug>
    #include<QSerialPort>
    #include<QSerialPortInfo>
    #include<QString>
    #include<QTimer>
    
    
    class serialThread : public QThread
    {
        Q_OBJECT
    public:
        serialThread();
    
    public:
        QSerialPort *Serial;
        void InitPortName(const QString &portName);                 //初始化串口名
        void InitPortBaudRate(qint32 baudRate);                     //...波特率
        void InitPortDataBits(QSerialPort::DataBits dataBits);      //...数据位
        void InitPortParity(QSerialPort::Parity parity);            //...奇偶校验
        void InitPortStopBits(QSerialPort::StopBits stopbits);      //...停止位
        void InitFlowControl(QSerialPort::FlowControl flowcontrol); //...控制流
        bool OpenPort();                                            //打开串口
        void ClosePort();                                           //关闭串口
    public:
        QByteArray buffer;
    
    signals:
        void dataSend(QByteArray);                                  //发送从串口读取到的数据的信号
        void timeout();
    
    private slots:
        void timeUpdate();
        void data_receive();
        void run();
    
    private:
        QTimer *time;
    };
    
    
    
    #endif // SERIALTHREAD_H
    
    

    然后声明子线程相关方法,连接信号和槽,主要代码如下:
    serialthread.cpp

    #include "serialthread.h"
    
    serialThread::serialThread()
    {
        Serial=new QSerialPort();
        time=new QTimer;
    }
    
    /**
     * @brief 数据接收处理步骤
     * 1.打开串口,开启子线程
     * 2.串口收到数据后启动定时器,延时10ms,防止数据未发送完
     * 3.延时结束后读缓存区的数据
     * 4.将读取到的数据通过信号发送至主线程
     */
    
    void serialThread::run()
    {
        QObject::connect(Serial,&QSerialPort::readyRead,this,&serialThread::data_receive);  //收到数据触发槽函数启动定时器
        QObject::connect(time,SIGNAL(timeout()),this,SLOT(timeUpdate()));                   //延时结束开始读数据
    }
    
    void serialThread::data_receive()
    {
        time->start(10);
    }
    
    void serialThread::timeUpdate()
    {
        time->stop();
        buffer = Serial->readAll();              //读数据
        emit dataSend(buffer);                   //数据发送至主函数
    
    #if 0  
        //以下代码为测试其他功能用的
        for (int i=0;i<(buffer.size()-10);i++)
        {
    
            if(buffer.at(i)==0x55)
            {
                switch (buffer.at(i+1))
                {
                case 0x51:{}break;
                case 0x52:{}break;
                case 0x53:{}break;
                case 0x54:{}break;
                case 0x56:{}break;
                case 0x57:{}break;
                case 0x58:{}break;
                case 0x59:{}break;
                case 0x5A:{}break;
                default:{}break;
                }
            }
        }
    #endif
        buffer.clear();
    }
    
    void serialThread::InitPortName(const QString &portName)
    {
        Serial->setPortName(portName);                          //设置串口名的方法,下同
    }
    
    void serialThread::InitPortBaudRate(qint32 baudRate)
    {
         Serial->setBaudRate(baudRate);
    }
    
    void serialThread::InitPortDataBits(QSerialPort::DataBits dataBits)
    {
        Serial->setDataBits(dataBits);
    }
    
    void serialThread::InitPortStopBits(QSerialPort::StopBits stopbits)
    {
        Serial->setStopBits(stopbits);
    }
    
    void serialThread::InitPortParity(QSerialPort::Parity parity)
    {
        Serial->setParity(parity);
    }
    
    void serialThread::InitFlowControl(QSerialPort::FlowControl flowcontrol)
    {
        Serial->setFlowControl(flowcontrol);
    }
    
    bool serialThread::OpenPort()
    {
        if(Serial->open(QIODevice::ReadWrite))
            return true;
        else
            return false;
    }
    
    void serialThread::ClosePort()
    {
        Serial->close();
    }
    

    主线程

    主线程主要用于UI界面的显示以及启动子线程,其中按钮的槽方法时通过UI编辑器生成的,代码如下:
    mainwindow.h

    #include "serialthread.h"
    
    serialThread::serialThread()
    {
        Serial=new QSerialPort();
        time=new QTimer;
    }
    
    /**
     * @brief 数据接收处理步骤
     * 1.打开串口,开启子线程
     * 2.串口收到数据后启动定时器,延时10ms,防止数据未发送完
     * 3.延时结束后读缓存区的数据
     * 4.将读取到的数据通过信号发送至主线程
     */
    
    void serialThread::run()
    {
        QObject::connect(Serial,&QSerialPort::readyRead,this,&serialThread::data_receive);  //收到数据触发槽函数启动定时器
        QObject::connect(time,SIGNAL(timeout()),this,SLOT(timeUpdate()));                   //延时结束开始读数据
    }
    
    void serialThread::data_receive()
    {
        time->start(10);
    }
    
    void serialThread::timeUpdate()
    {
        time->stop();
        buffer = Serial->readAll();              //读数据
        emit dataSend(buffer);                   //数据发送至主函数
    
    #if 0  
        //以下代码为测试其他功能用的
        for (int i=0;i<(buffer.size()-10);i++)
        {
    
            if(buffer.at(i)==0x55)
            {
                switch (buffer.at(i+1))
                {
                case 0x51:{}break;
                case 0x52:{}break;
                case 0x53:{}break;
                case 0x54:{}break;
                case 0x56:{}break;
                case 0x57:{}break;
                case 0x58:{}break;
                case 0x59:{}break;
                case 0x5A:{}break;
                default:{}break;
                }
            }
        }
    #endif
        buffer.clear();
    }
    
    void serialThread::InitPortName(const QString &portName)
    {
        Serial->setPortName(portName);                          //设置串口名的方法,下同
    }
    
    void serialThread::InitPortBaudRate(qint32 baudRate)
    {
         Serial->setBaudRate(baudRate);
    }
    
    void serialThread::InitPortDataBits(QSerialPort::DataBits dataBits)
    {
        Serial->setDataBits(dataBits);
    }
    
    void serialThread::InitPortStopBits(QSerialPort::StopBits stopbits)
    {
        Serial->setStopBits(stopbits);
    }
    
    void serialThread::InitPortParity(QSerialPort::Parity parity)
    {
        Serial->setParity(parity);
    }
    
    void serialThread::InitFlowControl(QSerialPort::FlowControl flowcontrol)
    {
        Serial->setFlowControl(flowcontrol);
    }
    
    bool serialThread::OpenPort()
    {
        if(Serial->open(QIODevice::ReadWrite))
            return true;
        else
            return false;
    }
    
    void serialThread::ClosePort()
    {
        Serial->close();
    }
    

    mainwindow.cpp

    #include "gpsmap.h"
    #include "ui_gpsmap.h"
    
    gpsMap::gpsMap(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::gpsMap)
    {
        ui->setupUi(this);
        portThread = new serialThread();
    
        foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())     //搜索串口并在界面显示
        {
            ui->portBox->addItem(info.portName());
        }
        ui->baudBox->setCurrentIndex(0);                                           //设置波特率初始值
    
        QObject::connect(portThread, SIGNAL(dataSend(QByteArray)),this,SLOT(dataShow(QByteArray)));  //连接子线程发送数据与主线程接收数据的信号和槽
    }
    
    gpsMap::~gpsMap()
    {
        delete ui;
    }
    
    void gpsMap::dataShow(QByteArray buf)    //数据显示
    {
        QByteArray buffer = buf;
        QString recv=QString(buffer);
    
        ui->textEdit->insertPlainText(recv);
    }
    
    void gpsMap::on_searchBtn_clicked()    //搜索按钮的槽方法
    {
        ui->portBox->clear();
        foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
        {
            ui->portBox->addItem(info.portName());
        }
    }
    
    void gpsMap::on_openBtn_clicked()
    {
        if(ui->openBtn->text()==QString("打开"))
        {
            //串口相关参数设置
            portThread->InitPortName(ui->portBox->currentText());
            portThread->InitPortBaudRate(ui->baudBox->currentText().toInt());
            portThread->InitPortDataBits(QSerialPort::Data8);
            portThread->InitPortStopBits(QSerialPort::OneStop);
            portThread->InitPortParity(QSerialPort::NoParity);
            portThread->InitFlowControl(QSerialPort::NoFlowControl);
            
            //若打开失败则提示
            if(!portThread->OpenPort())
            {
                QMessageBox::about(NULL,"提示","无法打开串口!");
                return;
            }
            
            //串口打开后使相关控件失能
            ui->portBox->setEnabled(false);
            ui->baudBox->setEnabled(false);
            ui->searchBtn->setEnabled(false);
            ui->openBtn->setText(QString("关闭"));
            
            //启动子线程
            portThread->start();
        }
        else {
            portThread->quit();
            portThread->ClosePort();
            ui->portBox->setEnabled(true);
            ui->baudBox->setEnabled(true);
            ui->searchBtn->setEnabled(true);
    
            ui->openBtn->setText(QString("打开"));
        }
    }
    
    

    总结

    软件虽实现了串口接收功能,但是当数据量很大时会发生丢帧现象,搜索相关资料后采用定时器延时方法,虽有所改善但仍未解决,接收缓存区只能够存放99字节数据,不知道是自己检测的原因还是其他原因,留待以后解决。

    由于这是第一次独立编写Qt小软件,走了很多弯路,在此感谢CSDN博主分享的方法及代码,如有错误,望指正。

    附:十六进制显示程序(添加到显示程序)

    	QString recv=QString(buffer);
        if(ui->hexBox->isChecked())//添加QCheckBox控件,判断其状态
        {
            QString strDis;
            QString hexRecv=recv.toUtf8().toHex().toUpper();
            for (int i =0;i<hexRecv.length();i+=2) {
                QString st=hexRecv.mid(i,2);
                strDis+=st;
                strDis+=" ";
            }
            ui->receiveEdit->append(strDis);
        }
    
    展开全文
  • VC6-MFC-多线程串口通讯实例.zip

    热门讨论 2010-12-13 10:46:33
    VC6-MFC-多线程串口通讯实例.zip VC6-MFC-多线程串口通讯实例.zip VC6-MFC-多线程串口通讯实例.zip
  • 多线程串口通信技术在GPS导航中的应用多线程串口通信技术在GPS导航中的应用
  • 基于MFC开发的串口通信,技术用到API,和多线程开发串口通信
  • 多线程串口通信技术在DNC系统中的应用.pdf
  • 多线程串口通信技术在GPS导航中的应用.pdf
  • VC 多线程串口通讯源码,测试方法:选择本机可用的串口,可同进打开多个可用的串口,还可以设置数据位、停止位、校验、波特率,往指定端口发送接收数据等。在VC6.0环境下可顺利编译。
  • 基于多线程串口通信的生产数据实时采集系统.pdf
  • 多线程串口通信技术在北斗导航中的运用分析.pdf
  • 多线程串口通信技术及其在火灾监测中的应用.pdf
  • c#_多线程串口通讯_快速采集

    热门讨论 2010-06-06 13:54:37
    基于C# 2008的多线程串口通讯程序,实现多台设备的快速快速不间断数据采集
  • 多线程串口通讯实例

    2011-09-07 14:08:05
    多线程技术控制多个串口的网络通信,程序用VC实现。
  • 基于多线程串口通信的生产数据实时采集系统
  • 多线程串口通信技术在GPS导航中的应用 (2).pdf
  • 本次主要写点MFC环境下多线程串口通信相关的东西,这包括线程创建及控制、串口同步异步操作、内存非法访问(或者说是线程同步)、线程通信、Windows消息响应过程等。 遇到问题: 项目中IO传感器通信模块之前...

    写在前面:

             晚上应该继续完成未写完的代码,但Chrome上打开的标签实在太多了,约30个了,必须关掉一些,所以需要把自己看的整理一下然后关掉。本次主要写点MFC环境下多线程串口通信相关的东西,这包括线程创建及控制、串口同步异步操作、内存非法访问(或者说是线程同步)、线程通信、Windows消息响应过程等。

    遇到问题:

             项目中IO传感器通信模块之前直接写在了主线程中,UI代码和串口通信代码搅合在一起,不利于后期维护,而且有个非常严重的问题,IO通信太忙导致整个系统比较卡,特别是当系统接上超过3个摄像机之后,MFC模态对话框使用Domodal()直接无法打开,卡住了,然后用户就无法操作了,这个问题必须要解决。

    解决方案:

             单独开辟一个线程来处理所有的串口通信,该IO线程和主线程(负责UI部分)通信,从而更新状态,不能子线程中直接更新UI,参看《MFC最好不要在子线程中操控界面上的控件》。

    具体步骤:

    1.创立IO线程并完成消息响应

    HANDLE hThread1 = CreateThread( NULL,0,IOControlProc,(LPVOID)(m_pCOMSerialPort),0,&m_dwIOControlThreadId );//创建IO线程
    CloseHandle( hThread1 );//关闭线程句柄
    

      其中

    CSerialPort  *m_pCOMSerialPort;//通信串口
    DWORD m_dwIOControlThreadId;//线程ID
    

      IOControlProc线程函数

    DWORD WINAPI IOControlProc(LPVOID lpParameter)
    {
    	CSerialPort *pSerialPort = (CSerialPort*)lpParameter;
    	UINT_PTR nHUMITimer = 0;
    	UINT_PTR nIOTimer = 0;
    	//::SetTimer(NULL,NULL,200,(TIMERPROC)TimerProc);
    	nHUMITimer = ::SetTimer(NULL,TEMPHUMICOMM_TIMER,500,(TIMERPROC)OnIOTimer);//温湿度
    	nIOTimer =::SetTimer(NULL,IOCOMM_TIMER,100,(TIMERPROC)OnIOTimer);//IO
    	PIOTimerStru pHumiTimer= new IOTimerStru;
    	pHumiTimer->nIdEvent = TEMPHUMICOMM_TIMER;
    	pHumiTimer->pSerialPort = pSerialPort;
    	PIOTimerStru pIoTimer = new IOTimerStru;
    	pIoTimer->nIdEvent = IOCOMM_TIMER;
    	pIoTimer->pSerialPort = pSerialPort;
    	PIOTimerStru pIoControl = new IOTimerStru;
    	pIoControl->nIdEvent = TEMPHUMICOMM_TIMER + IOCOMM_TIMER;
    	pIoControl->pSerialPort = pSerialPort;
    	LPARAM   lParam;
    	MSG msg;
    	while(GetMessage(&msg,NULL,0,0))
    	{
    		TranslateMessage(&msg);
    		if (WM_TIMER == msg.message)
    		{
    			lParam = msg.lParam;//WM_TIMER回调函数的地址
    			if (nHUMITimer == msg.wParam)
    			{
    				msg.wParam = (WPARAM)pHumiTimer;
    			}
    			else if (nIOTimer == msg.wParam)
    			{
    				msg.wParam = (WPARAM)pIoTimer;
    			}			
    		}	
    		else if (WM_IOCOMMDATA == msg.message)
    		{
    			msg.message = WM_TIMER;
    			pIoControl->wParam = msg.wParam;
    			pIoControl->lParam = msg.lParam;
    			msg.wParam = (WPARAM)pIoControl;
    			msg.lParam = lParam;
    		}		
    		DispatchMessage(&msg);
    	}
    	delete pHumiTimer;
    	delete pIoTimer;
    	delete pIoControl;
    	return 0;
    }
    

      这里,IO线程有自己的消息循环队列(虽然没有窗口),参看:《子线程里如何使用定时器》,把这里的代码改成死循环的(参看《是否在子线程内使用SetTimer?》),如下

    VOID CALLBACK TimerProc(          HWND hwnd,
        UINT uMsg,
        UINT_PTR idEvent,
        DWORD dwTime
    ){
             //do some thing
             return;
    }
    
    DWORD WINAPI ThreadProc(LPVOID lpParameter)
    {
          
    	::SetTimer(NULL,NULL,200,(TIMERPROC)TimerProc);
    	MSG msg;
    	while(GetMessage(&msg,NULL,0,0))
    	{
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
    	return 0;
    	
    }
    

      我的消息响应函数写成如下

    VOID CALLBACK OnIOTimer(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime)
    {
    	PIOTimerStru pStru = (PIOTimerStru)idEvent;
    	if (pStru->nIdEvent == TEMPHUMICOMM_TIMER)//温湿度模块
    	{
    		static bool bFlag = true;
    		if (bFlag)
    		{
    			IOSendData(pStru->pSerialPort,2,0x0A,0,0x03);
    		}
    		else
    		{
    			IOSendData(pStru->pSerialPort,2,0x0A,0,0x04);
    		}
    		bFlag = !bFlag;
    	}
    	else if (pStru->nIdEvent == IOCOMM_TIMER)//IO控制模块
    	{
    		IOSendData(pStru->pSerialPort,1,0x10,0,0x03);
    	}
    	else if (pStru->nIdEvent ==  TEMPHUMICOMM_TIMER + IOCOMM_TIMER)//别的线程发送的指令
    	{		
    		WORD highDeviceIndex = HIWORD(pStru->wParam);//设备号
    		WORD lowPortIndex = LOWORD(pStru->wParam);//设备1端口号,设备2指定温度或湿度模块
    		WORD highParam = HIWORD(pStru->lParam);//设备1指定状态1或者0,设备2指定整数部分
    		WORD lowParam = LOWORD(pStru->lParam);//设备1为0,设备2指定小数部分
    
    		IOSendData(pStru->pSerialPort,(int)highDeviceIndex,(BYTE)highParam,(BYTE)lowParam,(BYTE)lowPortIndex);
    	}
    	return;
    }
    

      这里要注意一个问题,OnIOTimer中获得的idEvent并不是我们设置的IOCOMM_TIMER或者TEMPHUMICOMM_TIMER,究其原因,参看《SetTimer在无窗口和有窗口线程的使用》,文中关于原因的解释为“注:只有当hWnd参数为非空时,计时器的ID为设置的 nIDEvent, 系统为你自动生成一个计时器ID,可由返回时值获取.”,可由MSDN得知。

    那么我们的这个IOCOMM_TIMER或者TEMPHUMICOMM_TIMER,怎么传递过去呢?查看《怎么往SetTimer的回调函数传递参数》得知,我们可由msg.wParam传递。

    那么对于我们自定义的消息TEMPHUMICOMM_TIMER + IOCOMM_TIMER,我也想让OnIOTimer来处理怎么办?直接修改msg.message = WM_TIMER;就可以了嘛?答案是不行的!

    为什么呢?参看《消息循环中的TranslateMessage函数和DispatchMessage函数》,原来“如果参数lpmsg指向一个WM_TIMER消息,并且WM_TIMER消息的参数IParam不为NULL,则调用IParam指向的函数,而不是调用窗口程序。”,那么我们直接修改msg.lParam为OnIOTimer函数的地址就行了。这样,所有消息响应完成了。

    2.多线程访问冲突(线程冲突)
    遇到一个问题,系统有一个串口通信端口,IO线程直接使用了,然后我在主线程中也发送数据,然后问题出现了,有时候会出现非法访问,跟踪了一下,原来两个线程使用了同一个串口通信缓冲区,主线程往里面压入数据的时候,可能子线程已经释放了该缓冲区,查询文章《CSerialPort连续发送大量数据时出错原因分析》,而我使用的CSerialPort是同步的,我尝试修改类库代码,报错太多,此方法放弃。最终,我的解决方法是把所有的串口IO通信全部交给子线程来做,那么主线程要做的事,可以通过发送消息给子线程,再由子线程代劳,主线程怎么发送消息给子线程?使用API函数PostThreadMessage来完成,第一个参数就是子线程的Id。

    子线程收到数据后,进行验证,验证通过后,发消息给主线程,通知它更新界面。《主线程与子线程间通信解决办法 - VC/MFC

    3.主线程退出前,关闭子线程

    PostThreadMessage(m_dwIOControlThreadId,WM_QUIT,0,0);
    Sleep(100);//需要等待关闭掉
    

    GetMessage有消息时且消息不为WM_QUIT时返回TRUE,如果有消息且为WM_QUIT则返回FALSE,没有消息时不返回。  

    这里可参看《如何正确的关闭 MFC 线程》和《GetMessage和PeekMessage的联系与区别以及用法 TranslateMessage与DispatchMessage 

    至此,经测试问题全部解决,记录一下。

    转载于:https://www.cnblogs.com/xingrun/p/3587144.html

    展开全文
  • 多线程串口通讯实例,基于VC++开发 是学习串口通讯很好的范例! 可以设置串口的参数,比如端口号,比特率,错误校验算法等等 使用说明,打开程序后,使用vs打开即可,部分代码有注释。
  • 摘 要:GPS导航系统需要实时获取来自接收机串口的定位数据,在对串口实时监控的同时还可以在前台进行一些其他的操作,利用基于多线程串口通信编程思想方法可以很好地解决这一问题。介绍多线程的基本概念和串口通信...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,410
精华内容 5,764
关键字:

多线程串口通信