2015-02-07 15:42:08 encourage2011 阅读数 20827
  • OpenSceneGraph与qt结合视频教程

    Qt中嵌入OSG控件教程,教大家.认识并简单的应用qt,达到可以做一些自己的小例子;qt与osg是如何传递消息的,如何进行通信;了解三维是如何显示在里。有问题咨询老师微信,微信号:mikeshizhanbiao

    22870 人正在学习 去看看 师占标

前面提到过Qt USB通信四种方案,这里详细介绍我使用的hidapi第三方库。
从官网上下载到最新的压缩包hidapi-0.7.0.zip,解压后查看README.txt,里面介绍了三种Windows、Linux、MacOS三种平台下的编译方式:
------
It can be downloaded from github
	git clone git://github.com/signal11/hidapi.git

Build Instructions
-------------------
To build the console test program:
  Windows:
    Build the .sln file in the windows/ directory.
  Linux:
    cd to the linux/ directory and run make.
  Mac OS X:
    cd to the mac/ directory and run make.

1、使用Visual Studio打开hidapi.vcproj,然后编译之。注:因为我使用的是VS2005,由于版本不对应,无法转换hidapi.vcproj到我当前的版本,此时用编辑器打开文件hidapi.vcproj将原本的:

Version="9.00"

改成8.00.之后就可以打开工程。

2、编译完成之后,在该目录下会生成一个Debug目录,里面有很多文件,其中我们主要用到hidapi.dll和hidapi.lib两个文件。将hidapi.dll拷贝到C:\Windows\system下(至于拷贝到哪个目录,要根据系统是32位还是64位选择不同的路径。)

之后将hidapi.lib文件拷贝到你的工程目录下,这里我当然是拷贝到我的Qt 工程目录下。当然,也要把hidapi.h文件拷贝到Qt工程目录下,因为hidapi.h包含hidapi这个库中所有函数接口的声明,这样在Qt项目中对设备进行操作才不会调试说找不到hid_xxx()某某个函数。

3、在Qt工程中要指定lib文件和header文件。修改Qt的工程文件.pro如下:

HEADERS += hidapi.h

LIBS += -L$$_PRO_FILE_PWD_/LIB/ \
            -lhidapi
-L指定当前的路径;_PRO_FILE_PWD_指当前.pro文件所在的目录;-l指定.dll文件,这里是指定名字为hidapi的dll文件。

上述配置完成之后就可以对USB设备进行操作。具体如何操作可以参见README里面的用例以及hidapi.h的函数说明。

README里的用例:
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "hidapi.h"

#define MAX_STR 255

int main(int argc, char* argv[])
{
	int res;
	unsigned char buf[65];
	wchar_t wstr[MAX_STR];
	hid_device *handle;
	int i;

	// Open the device using the VID, PID,
	// and optionally the Serial number.
	handle = hid_open(0x4d8, 0x3f, NULL);

	// Read the Manufacturer String
	res = hid_get_manufacturer_string(handle, wstr, MAX_STR);
	wprintf(L"Manufacturer String: %s\n", wstr);

	// Read the Product String
	res = hid_get_product_string(handle, wstr, MAX_STR);
	wprintf(L"Product String: %s\n", wstr);

	// Read the Serial Number String
	res = hid_get_serial_number_string(handle, wstr, MAX_STR);
	wprintf(L"Serial Number String: (%d) %s\n", wstr[0], wstr);

	// Read Indexed String 1
	res = hid_get_indexed_string(handle, 1, wstr, MAX_STR);
	wprintf(L"Indexed String 1: %s\n", wstr);

	// Toggle LED (cmd 0x80). The first byte is the report number (0x0).
	buf[0] = 0x0;
	buf[1] = 0x80;
	res = hid_write(handle, buf, 65);

	// Request state (cmd 0x81). The first byte is the report number (0x0).
	buf[0] = 0x0;
	buf[1] = 0x81;
	res = hid_write(handle, buf, 65);

	// Read requested state
	hid_read(handle, buf, 65);

	// Print out the returned buffer.
	for (i = 0; i < 4; i++)
		printf("buf[%d]: %d\n", i, buf[i]);

	return 0;
}



2019-01-21 16:49:29 jiguangfan 阅读数 2216
  • OpenSceneGraph与qt结合视频教程

    Qt中嵌入OSG控件教程,教大家.认识并简单的应用qt,达到可以做一些自己的小例子;qt与osg是如何传递消息的,如何进行通信;了解三维是如何显示在里。有问题咨询老师微信,微信号:mikeshizhanbiao

    22870 人正在学习 去看看 师占标

一、具体流程

用libusb函数库来完成电脑与USB设备的数据交互功能,主要有以下步骤:

1)初始化libusb函数库

2)根据vid和pid查找某一具体设备,并获取设备描述符(vid和pid为设备的id,且每台设备的都vid和pid是唯一的)

3)根据设备描述符打开相应设备,获取设备操作符

4)用设备操作符配置usb设备的配置模式和接口

5)调用相应传输函数向usb设备发送数据,本项目中用的是块传输方式

6)调用相应传输函数读取usb设备的反馈数据,本项目中用的是块传输方式

7)释放usb设备接口,关闭设备。

综上,步骤1、2为初始化操作,步骤3、4为usb设备打开和配置操作,步骤5、6为电脑与usb设备数据传输操作,步骤7为usb设备关闭和释放系统资源操作。

二、代码展示

本例程是在Linux环境下 用QT框架 C++实现PC与USB设备的交互通信 ,代码中有详细注释,如下所示:

//打开usb设备
void MainWindow::on_pushButton_clicked()
{
    int r;
    ssize_t cnt;
    //libusb_context *ctx=nullptr; //context 上下文
    libusb_device **devs; //devices
    int i=0;

    if("open"==ui->pushButton->text())
    {
        ui->pushButton->setText("close");

        r=libusb_init(&ctx); //init 初始化libusb
        if(r<0) {
            qDebug()<<"failed to init libusb";  //fail to init libusb
            return;
        }

        cnt = libusb_get_device_list(nullptr, &devs); //获取设备列表
        if (cnt < 0) {
            qDebug()<<"failed to get device list";  //fail to get device_list
            return;
        }

        //遍历查找你要的设备
        while ((dev = devs[i++]) != nullptr) {
                struct libusb_device_descriptor desc;  //设备信息描述符

                r= libusb_get_device_descriptor(dev, &desc); //获取设备信息描述符
                if (r < 0) {
                    qDebug()<<"failed to get device descriptor";  //fail to get device descriptor
                    return;
                }

                if(desc.idVendor==0x0472 && desc.idProduct==0xA181) //根据vid和pid查找某一具体设备
                {
                    r=libusb_open(dev,&udev); //打开设备,获取设备操作符
                    if(r<0) {
                        qDebug()<<"failed to open device";  //fail to open device
                        qDebug()<<libusb_error_name(r)<<" "<<r;
                        qDebug()<<"udev:"<<udev;
                        return;
                    } else {
                        qDebug()<<"open device successfully";  //success to open device
                        qDebug()<<"udev:"<<udev;
                    }
                    break;
                }
            }

        //libusb规定在用设备操作符发送数据前,需设置usb设备的配置模式和接口
        if ((r=libusb_set_configuration(udev, 1)) < 0) {  //设置usb设备配置模式为1
            qDebug("error setting config #1: %s",  libusb_error_name(r));
            exit(1);
        }
        if ((r=libusb_claim_interface(udev, 0)) < 0) {   //设置usb设备接口为0
            qDebug("error claiming interface #0:\n%s", libusb_error_name(r));
            exit(1);
        }
    }
    else
    {
        ui->pushButton->setText("open");
        libusb_release_interface(udev, 0); //释放接口
        libusb_close(udev);  //关闭设备
        libusb_exit(ctx);  //退出libusb上下文

        udev=nullptr;

        qDebug()<<"close usb";
    }
}
//发送指令
void MainWindow::on_pushButton_2_clicked()
{
    int r = 0;
    int outsize=0;


    unsigned char a[10] = {0x3A, 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0D};

    outsize=sizeof(a);

    r=libusb_bulk_transfer(udev,0x01,a,outsize,&outsize,5000);  //以块传输方式发送16进制数据 选择端口号为0x01
    //libusb_bulk_transfer函数参数解释:设备操作符 端口地址 要发送的数据 预计发送的字节数 实际发送的字节数 超时时间

    if (r < 0)
    {
        qDebug() << "error writing:";
        qDebug() << libusb_error_name(r);
    }
    else
    {
        qDebug() << "success: bulk write " << outsize <<  " bytes";
        qDebug() << "3A 01 00 00 00 00 00 00 01 0D";
        this->read_usb();  //读取usb设备的反馈结果
    }
}
//读取usb设备的反馈结果
void MainWindow::read_usb()
{
    unsigned char tmps[50]={0};
    int i=0;
    int read_size_t=25;

    while(i<2)
    {
        int ret=0;
        ret = libusb_bulk_transfer(udev, 0x82, tmps, read_size_t, &read_size_t,5000);  //以块传输方式接收16进制数据 选择端口号为0x84
        //libusb_bulk_transfer函数参数解释:设备操作符 端口地址 要接受的数据 预计接受的字节数 实际接受的字节数 超时时间
        //libusb_bulk_transfer根据端口决定此时函数是接收还是发送数据

        if(ret >= 0)
        {
            qDebug() << "success: bulk read " << read_size_t << " bytes";
            QString strTmp;
            QString strOut;
            for(int i = 0; i < read_size_t; i++)
            {
                strTmp.sprintf("%02X ", tmps[i]);
                strOut.append(strTmp);
            }
            qDebug() << strOut;
            qDebug() << "success";
            break;
        }
        else
        {
            qDebug() << "fail to read"<<ret;
            qDebug() << "error reading:";
            qDebug() << libusb_error_name(ret);
        }
        i++;
    }
    qDebug() << "finish2";
}

三、运行结果

运行结果如下所示:

 

参考链接

https://blog.csdn.net/gd6321374/article/details/79935186

https://blog.csdn.net/a7082633/article/details/50802909

2018-04-26 17:34:52 sz76211822 阅读数 370
  • OpenSceneGraph与qt结合视频教程

    Qt中嵌入OSG控件教程,教大家.认识并简单的应用qt,达到可以做一些自己的小例子;qt与osg是如何传递消息的,如何进行通信;了解三维是如何显示在里。有问题咨询老师微信,微信号:mikeshizhanbiao

    22870 人正在学习 去看看 师占标
#include <QCoreApplication>

#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QSerialPort serial;
    serial.setPortName("/dev/ttyUSB0");

    //设置波特率
    serial.setBaudRate(QSerialPort::Baud9600);

    //设置数据位数
    serial.setDataBits(QSerialPort::Data8);

     //设置奇偶校验
     serial.setParity(QSerialPort::NoParity);

    //设置停止位
    serial.setStopBits(QSerialPort::OneStop);

    //设置流控制
    serial.setFlowControl(QSerialPort::NoFlowControl);

    //打开串口
    bool bRet = serial.open(QIODevice::ReadWrite);
    if(bRet){
        printf("open success");
        serial.clear();
        serial.flush();

        bool bClosed = true;
        bool m_bDistinguish = true;
        time_t startTime = time(NULL);
        unsigned char btCMD_OpenDoor[4] = {0xa0, 0x01, 0x01, 0xa2};
        unsigned char btCMD_CloseDoor[4] = {0xa0, 0x01, 0x00, 0xa1};
        while(true){
            if(m_bDistinguish && bClosed){
                bool bRet = serial.waitForBytesWritten(5000);
                long nRet = serial.write((char*)btCMD_OpenDoor, 4);
                printf("open:%d %d\n", bRet, nRet);
                startTime = time(NULL);
                bClosed = false;
                m_bDistinguish = false;
            }
            if(!m_bDistinguish && !bClosed){
                long fDuration = time(NULL) - startTime;
                if(fDuration >= 5){
                    bool bRet = serial.waitForBytesWritten(5000);
                    long nRet = serial.write((char*)btCMD_CloseDoor, 4);
                    printf("close:%d %d\n", bRet, nRet);
                    bClosed = true;
                    m_bDistinguish = true;
                }
            }
        }
        serial.close();
    }
    else{
        printf("open fail\n");
    }
    return a.exec();
}

QT += serialport

2012-02-22 09:50:16 qimo601 阅读数 114
  • OpenSceneGraph与qt结合视频教程

    Qt中嵌入OSG控件教程,教大家.认识并简单的应用qt,达到可以做一些自己的小例子;qt与osg是如何传递消息的,如何进行通信;了解三维是如何显示在里。有问题咨询老师微信,微信号:mikeshizhanbiao

    22870 人正在学习 去看看 师占标

 

查看以前的教程:Qt编写串口通信程序全程图文讲解

查看Wincom和Lincom介绍:Qt跨平台串口通信软件Wincom与Lincom

下载软件,文档和源码:资源下载

——————————————2010年7月8日更新——————————————–

网友 赵文杰 使用多线程完成的linux下的串口通信。

下载源码:下载

—————————————————————————————————————

以下是正文:

前言

去年我使用Qt编写串口通信程序时,将自己的学习过程写成了教程(Qt编写串口通信程序全程图文讲解),但是由于时间等原因,我只实现了Windows下的串口通信,并没有去做Linux下的。自从教程发布到网上后,就不断有人提出相关的问题,而其中问的最多的就是,怎样在Linux下实现串口通信。因为有计划安排,而且没有开发板,所以一直没能去研究,也就没能给出很好的解决办法。前些天,网友hqwfreefly 用Qt写了一个叫linucom的Linux下串口调试程序,实现了Linux的串口通信。而且,正好现在我有几天假期,所以就和hqwfreefly合作,将linucom更新为Lincom,并且推出了Windows下的Wincom,然后完成了这篇Qt编写串口通信程序的专题教程,也算完成了我的一个心愿。

 

教程概述

       该教程分三部分讲述,第一部分讲解qextserialport类的一些东东;第二部分讲解在Windows下使用qextserialport类实现串口通信的方法,这里将讲述两种不同的方法;第三部分讲解在Linux下利用qextserialport类实现串口通信的方法。

       在这个教程中我们更注重知识的讲解,而不是界面的设计。关于界面和其他应用问题,你可以查看以前的串口通信教程或者查看一下Wincom软件的源码。

第一部分 Qextserialport类介绍 

在Qt中并没有特定的串口控制类,现在大部分人使用的是第三方写的qextserialport类,我们这里也使用了该类。

一、文件下载

文件下载地址:

http://sourceforge.net/projects/qextserialport/files/

也可以下载我上传到网盘上的:

http://good.gd/494307.htm

二、文件内容介绍

 

1.下载到的文件为qextserialport-1.2win-alpha ,解压并打开后其内容如下。

(点击图片可以查看清晰大图)

 Hosted by ImageHost.org

下面分别介绍:

(1)doc文件夹中的文件内容是QextSerialPort类和QextBaseType的简单的说明,我们可以使用记事本程序将它们打开。

(2)examples文件夹中是几个例子程序,可以看一下它的源码,不过想运行它们好像会出很多问题啊。

(3)html文件夹中是QextSerialPort类的使用文档。

(4)然后就是剩下的几个文件了。其中qextserialenumerator.cpp及qextserialenumerator.h文件中定义的QextSerialEnumerator类是用来获取平台上可用的串口信息的。不过,这个类好像并不怎么好用,而且它不是我们关注的重点,所以下面就不再介绍它了。

 (5)qextserialbase.cpp和qextserialbase.h文件定义了一个QextSerialBase类,win_qextserialport.cpp和win_qextserialport.h文件定义了一个Win_QextSerialPort类,posix_qextserialport.cpp和posix_qextserialport.h文件定义了一个Posix_QextSerialPort类,qextserialport.cpp和qextserialport.h文件定义了一个QextSerialPort类。这个QextSerialPort类就是我们上面所说的那个,它是所有这些类的子类,是最高的抽象,它屏蔽了平台特征,使得在任何平台上都可以使用它。

2.几个类的简单介绍。

下面是这几个类的关系图。

 Hosted by ImageHost.org

可以看到它们都继承自QIODevice类,所以该类的一些函数我们也可以直接来使用。图中还有一个QextBaseType类,其实它只是一个标识,没有具体的内容,它用来表示Win_QextSerialPort或Posix_QextSerialPort 中的一个类,因为在QextSerialPort类中使用了条件编译,所以QextSerialPort类既可以继承自Win_QextSerialPort类,也可以继承自Posix_QextSerialPort类,所以使用了QextBaseType来表示。这一点我们可以在qextserialport.h文件中看到。再说QextSerialPort类,其实它只是为了方便程序的跨平台编译,使用它可以在不同的平台上,根据不同的条件编译继承不同的类。所以它只是一个抽象,提供了几个构造函数而已,并没有具体的内容。在qextserialport.h文件中的条件编译内容如下:

/*POSIX CODE*/

#ifdef _TTY_POSIX_

#include “posix_qextserialport.h”

#define QextBaseType Posix_QextSerialPort

 

/*MS WINDOWS CODE*/

#else

#include “win_qextserialport.h”

#define QextBaseType Win_QextSerialPort

#endif

所以,其实我们没有必要使用这个类,直接使用Win_QextSerialPort或Posix_QextSerialPort就可以了。当然如果你想使用这个类,实现同样的源程序可以直接在Windows和Linux下编译运行,那么一定要注意在Linux下这里需要添加 #define _TTY_POSIX_ 。而我们这里为了使得程序更明了,所以没有使用该类,下面也就不再介绍它了。

       QextSerialBase类继承自QIODevice类,它提供了操作串口所必需的一些变量和函数等,而Win_QextSerialPort和Posix_QextSerialPort均继承自QextSerialBase类,Win_QextSerialPort类添加了Windows平台下操作串口的一些功能,Posix_QextSerialPort类添加了Linux平台下操作串口的一些功能。所以说,在Windows下我们使用Win_QextSerialPort类,在Linux下我们使用Posix_QextSerialPort类。

3.在QextSerialBase类中还涉及到了一个枚举变量QueryMode

它有两个值Polling和EventDriven 。QueryMode指的是读取串口的方式,下面我们称为查询模式,我们将Polling称为查询方式Polling,将EventDriven称为事件驱动方式。

       事件驱动方式EventDriven就是使用事件处理串口的读取,一旦有数据到来,就会发出readyRead()信号,我们可以关联该信号来读取串口的数据。在事件驱动的方式下,串口的读写是异步的,调用读写函数会立即返回,它们不会冻结调用线程。

而查询方式Polling则不同,读写函数是同步执行的,信号不能工作在这种模式下,而且有些功能也无法实现。但是这种模式下的开销较小。我们需要自己建立定时器来读取串口的数据。

在Windows下支持以上两种模式,而在Linux下只支持Polling模式。

三、小结。

       这里讲了这么多,最后要说的只是,我们在Qt中使用这个类编写串口程序,根据平台的不同只需要分别使用四个文件。

在Windows下是:

qextserialbase.cpp和qextserialbase.h 以及win_qextserialport.cpp和win_qextserialport.h

在Linux下是:

qextserialbase.cpp和qextserialbase.h 以及posix_qextserialport.cpp和posix_qextserialport.h

而在Windows下我们可以使用事件驱动EventDriven方式,也可以使用查询Polling方式,但是在Linux下我们只能使用查询Polling方式。

第二部分 Windows下编写串口通信程序 

我们的环境是Windows xp,Qt4.6.3及Qt Creator2.0。

第一,下面我们首先使用事件驱动来实现串口通信。

1.新建工程。

我们在Qt Creator中新建Qt Gui工程,命名为myCom,Base Class选择QWidget。

2.添加文件。

  我们将那四个文件添加到工程文件夹中。如下图。

 Hosted by ImageHost.org

然后我们将这四个文件添加到工程中,在Qt Creator的工程列表中的工程文件夹上点击鼠标右键,在弹出的菜单中选择“Add Existing Files”菜单。如下图。

 Hosted by ImageHost.org

我们在弹出的对话框中选中四个文件,按下“打开”按钮即可,如下图。

 Hosted by ImageHost.org

最终工程文件列表如下图。

 Hosted by ImageHost.org

3.更改界面。

我们将界面设计如下。

 Hosted by ImageHost.org

其中的Text Browser 部件用来显示接收到的数据,Line Edit部件用来输入要发送的数据,Push Button按钮用来发送数据。我们保持各部件的属性为默认值即可。

4. 我们在widget.h文件中进行对象及函数声明。

添加头文件包含:#include “win_qextserialport.h”

然后在private中声明对象:Win_QextSerialPort *myCom;

声明私有槽函数:

private slots:

    void on_pushButton_clicked(); //”发送数据”按钮槽函数

void readMyCom();  //读取串口

5.在widget.cpp文件中进行更改。

在构造函数中添加代码,完成后,构造函数内容如下:

Widget::Widget(QWidget *parent) :

    QWidget(parent),

    ui(new Ui::Widget)

{

    ui->setupUi(this);

    myCom = new Win_QextSerialPort(“COM1″,QextSerialBase::EventDriven);

    //定义串口对象,指定串口名和查询模式,这里使用事件驱动EventDriven

    myCom ->open(QIODevice::ReadWrite);

    //以读写方式打开串口

    myCom->setBaudRate(BAUD9600);

    //波特率设置,我们设置为9600

    myCom->setDataBits(DATA_8);

    //数据位设置,我们设置为8位数据位

    myCom->setParity(PAR_NONE);

    //奇偶校验设置,我们设置为无校验

    myCom->setStopBits(STOP_1);

    //停止位设置,我们设置为1位停止位

    myCom->setFlowControl(FLOW_OFF);

    //数据流控制设置,我们设置为无数据流控制

    myCom->setTimeout(500);

    //延时设置,我们设置为延时500ms,这个在Windows下好像不起作用

    connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom()));

    //信号和槽函数关联,当串口缓冲区有数据时,进行读串口操作

}

实现槽函数:

void Widget::readMyCom() //读取串口数据并显示出来

{

    QByteArray temp = myCom->readAll();

    //读取串口缓冲区的所有数据给临时变量temp

    ui->textBrowser->insertPlainText(temp);

    //将串口的数据显示在窗口的文本浏览器中

}

void Widget::on_pushButton_clicked()  //发送数据

{

    myCom->write(ui->lineEdit->text().toAscii());

    //以ASCII码形式将数据写入串口

}

6.此时,我们运行程序,效果如下。

 Hosted by ImageHost.org

可以看到,已经成功完成通信了。

(注:我们这里下位机使用的是单片机,它使用串口与计算机的COM1相连。单片机上运行的程序的功能是,接收到一个字符便向上位机发送一个字符串然后发送接收到的字符。)

两个重要问题的讲解:

 

一、关于数据接收。

我们想在程序中对接收的数据进行控制,但是readyRead()信号是一旦有数据到来就发射的,不过我们可以使用bytesAvailable()函数来检查已经获得的字节数,从而对数据接收进行控制。

(1)我们在widget.cpp中添加头文件包含:#include <QDebug>

       然后在读串口函数中添加一行代码,如下:

void Widget::readMyCom() //读取串口数据并显示出来

{

    qDebug() << “read: “<<myCom->bytesAvailable()<<”bytes”;

    //我们输出每次获得的字节数

    QByteArray temp = myCom->readAll();

    ui->textBrowser->insertPlainText(temp);

}

运行程序,效果如下:

 Hosted by ImageHost.org

可以看到,我们获取的数据并不是一次获得的。

(2)利用上面的结论,我们可以让串口缓冲区拥有了一定的数据后再读取。

void Widget::readMyCom()

{

if(myCom->bytesAvailable() >=8 )

//如果可用数据大于或等于8字节再读取

    {

        qDebug() << “read: “<<myCom->bytesAvailable()<<”bytes”;

        QByteArray temp = myCom->readAll();

        ui->textBrowser->insertPlainText(temp);

   }

}

运行程序,效果如下:

 Hosted by ImageHost.org

我们发送了两次数据,可以看到,这样实现了每8个字节读取一次,而最后剩余的不够8个字节的数据将会和后面的数据一起读出。

然后我们将8改为3,发送一次数据,效果如下:

 Hosted by ImageHost.org

改为7,发送两次数据,效果如下:

 Hosted by ImageHost.org

改为11,发送两次数据,效果如下:

 Hosted by ImageHost.org

改为17,发送三次数据,效果如下:

 Hosted by ImageHost.org

重要结论:我们发送一次数据,应该获得37字节的数据,然后我们对比上面的结果,发现了什么?是的,其实串口每次读取8字节的数据放到缓冲区,只有数据总数小于8字节时,才会读取小于8字节的数据。为了再次验证我们的结论,我们可以将上面程序中的“>=”改为“==”,那么只有8的倍数才能读取数据(当然这里37也可以),你可以测试一下。

       关于接收数据方面,可以根据你自己的需要再去进行研究和改进,这里只是抛砖引玉。

二、关于发送数据。

我们也可以使用函数获取要发送的数据的大小,这里有个bytesToWrite()可以获取要发送的字节数。例如将发送数据更改如下:

void Widget::on_pushButton_clicked()  //发送数据

{

    myCom->write(ui->lineEdit->text().toAscii());

    qDebug() << “write: “<<myCom->bytesToWrite()<<”bytes”;

    //输出要发送的字节数

}

运行后效果如下:

 Hosted by ImageHost.org

当然,对于要发送的数据的大小我们不是很关心,而且它还有很多方法可以实现,这个还有个bytesWritten()信号函数来获取已经发送的数据的大小,不过好像它不是很好用。这里将它们提出来,只是供大家参考而已。

第二,使用查询方式Polling来实现串口通信。

 

这里再次说明,Polling方式是不能使用readyRead()信号的,所以我们需要自己设置定时器,来不断地读取缓冲区的数据。

1.我们在widget.h中声明一个定时器对象。

添加头文件包含:#include <QTimer>

添加private变量:QTimer *readTimer;

2.我们在widget.cpp文件中的构造函数中更改。

(1)将串口定义更改为:

myCom = new Win_QextSerialPort(“COM1″,QextSerialBase::Polling);

//定义串口对象,指定串口名和查询模式,这里使用Polling

(2)定义定时器,并将以前的关联更改为定时器的关联。

readTimer = new QTimer(this);

    readTimer->start(100);

    //设置延时为100ms

    connect(readTimer,SIGNAL(timeout()),this,SLOT(readMyCom()));

//信号和槽函数关联,延时一段时间,进行读串口操作

3.此时运行程序,便可以正常收发数据了。 

重点:关于延时问题。

上面的程序中可以进行数据的接收了,但是好像中间的延时有点长,要等一会儿才能收到数据,而且即便我们将定时器改为10ms 也不行。问题在哪里呢?其实真正控制串口读写时间的不是我们的定时器,而是延时timeout。我们在构造函数中设置了延时:

myCom->setTimeout(500);

//延时设置,我们设置为延时500ms

我们前面说延时并不起作用,那是因为是在事件驱动的情况下,一旦有数据到来就会触发readyRead()信号,所以延时不起作用。但是现在,真正控制串口读写数据间隔的就是这个函数。这里值得注意,我们现在所说的串口读写是指底层的串口读写,从上面的程序中我们也可以看到,我们每隔100ms去读串口,确切地说,应该是去读串口缓冲区。而timeout才是正真的读取串口数据,将读到的数据放入串口缓冲区。所以如果timeout时间很长,即便我们的定时器时间再短,也是读不到数据的。所以我们这里需要将timeout设置为较小的值,比如10。我们更改代码:

myCom->setTimeout(10);

这样再运行程序,我们就可以很快地获得数据了。

关于数据接收:事件驱动那里的结论依然有用,不过这里更多的是靠读取的时间间隔来控制。

关于发送数据:这时bytesToWrite()函数就不再那么好用了。

 

第三部分 Linux下编写串口通信程序

我这里的环境是Ubuntu 10.04,Qt 4.6.3和Qt Creator2.0 。上面已经提到,在Linux下只能使用Polling的方式读取串口数据,所以我们将上面Windows下的应用Polling的程序在Linux下重新编译。我们使用Qt Creator打开该工程,然后进行下面的操作。

1.文件替换。

将工程中的win_qextserialport.cpp和win_qextserialport.h文件替换成posix_qextserialport.cpp和posix_qextserialport.h文件。

(1)我们先删除工程中的win_qextserialport.cpp和win_qextserialport.h文件。

在工程列表中用鼠标右击win_qextserialport.h,然后选择“Remove File”选项。如下图。

 Hosted by ImageHost.org

在弹出的对话框中我们选中“Delete file permanently”选项,确保删除了工程文件夹中的文件。如下图。

 Hosted by ImageHost.org

然后我们使用同样的方法删除win_qextserialport.cpp文件。

(2)我们按照Windows下添加文件的方法,向工程中添加posix_qextserialport.cpp和posix_qextserialport.h文件。最终工程文件列表如下。

 Hosted by ImageHost.org

2.设置编码。

(这是因为两个系统使用的默认编码不同造成的,如果你那里没有该问题,可以跳过这一步)

现在我们打开widget.cpp文件,发现中文出现乱码,而且无法编辑。在编辑器最上面有一个黄色提示条和一个“Select Encoding”按钮,我们点击该按钮。如下图。

 Hosted by ImageHost.org

在弹出的对话框中我们选择“GB2312”。按下“Reload with Encoding”按钮,中文就可以正常显示了。

 Hosted by ImageHost.org

3.更改程序。

在widget.h 文件中:

将以前的#include “win_qextserialport.h”更改为#include “posix_qextserialport.h”

将以前的Win_QextSerialPort *myCom;更改为Posix_QextSerialPort *myCom;

在widget.cpp文件中:

将以前的myCom = new Win_QextSerialPort(“COM1″,QextSerialBase::Polling);

更改为:myCom = new Posix_QextSerialPort(“/dev/ttyS0″,QextSerialBase::Polling);

(这里一定要注意串口名称的写法。)

4.下面我们运行程序。

这时可能会出现以下提示。

 Hosted by ImageHost.org

错误是说一个函数的调用出现了问题。我们点击该错误,定位到出错的位置,然后将那个函数中的第一个参数删除即可。如下图。

 Hosted by ImageHost.org

5.再次运行程序,这时已经可以正常运行了。

 Hosted by ImageHost.org

6.小结

可以看到将Windows下的串口程序在Linux下重新编译是很简单的,我们只需要替换那两个文件,然后更改一下头文件包含,对象定义和串口名即可。

结尾

 

       本教程比较详细的讲述了使用Qt在Windows下和Linux下编写串口通信程序的方法,但是对于串口通信的内容还有很多,我们现在还无法全部涵盖。希望广大网友可以提出宝贵建议,将Wincom软件进行功能扩展,或者将本教程继续更新下去。

       如果你喜欢本教程的写作风格,而且您也是Qt爱好者,您可以访问我们的网站,这里有一系列教程和软件供您参考学习,当然也希望您能为我们的网站添砖加瓦,让我们一起为Qt 及Qt Creator的普及贡献自己的力量。

2018-07-25 16:37:00 weixin_30425949 阅读数 2
  • OpenSceneGraph与qt结合视频教程

    Qt中嵌入OSG控件教程,教大家.认识并简单的应用qt,达到可以做一些自己的小例子;qt与osg是如何传递消息的,如何进行通信;了解三维是如何显示在里。有问题咨询老师微信,微信号:mikeshizhanbiao

    22870 人正在学习 去看看 师占标

1、linux下的qt串口通信跟windows唯一的差别就是端口号的名字,windows下面是COM,而linux是ttyUSB0的路径

2、一般情况下linux插上USB转串口线就可以在/dev/目录下看到类似ttyUSB0之类的串口号

3、初始化

  my_serialPort = new QSerialPort(this);

  my_serialPort->setPortName("/dev/ttyUSB0");//端口号

4、如果运行程序,出现串口打不开的错误情况的话,可能是权限问题

5、cd /dev

6、ls查看ttyUSB0是否在

7、添加权限chmod 777 ttyUSB0

转载于:https://www.cnblogs.com/xupeidong/p/9366742.html

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