折腾这个折腾了两天,功夫不负有心人,终于还是折腾出来了。关于串口的实现,涉及的比较多,不过也没有想象中的那么难。之所以折腾那么就,主要还是犯了一个很低级的出错,就是在读数据的时候老出错(写数据老早就可以了,幸庆自己还有那么一点完美主义)。一开是使用的是网上广泛流传的那个文件包叫“qextserialport-1.2win-alpha”,用到了里面的几个文件。 posix_qextserialport.h qextserialbase.h qetserialport.h 以及其对应的.cpp文件。这些文件里面已经写好了对串口的初始化,打开,关闭,读写等等。可是我觉得内容太多,很多功能和我要实现的简单收发功能不相关。先给出我的实现函数

mainwindow.h文件,该文件主要定义一些Textbrowser之类的类和引用头文件“posix_qextserialport.h”,以及一些初始化串口,打开串口的槽函数。

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtGui>
#include <stdio.h>
#include <termios.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>#include "posix_qextserialport.h"namespace Ui {    class MainWindow;
}
class MainWindow : public QMainWindow
{    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private:
    Ui::MainWindow *ui;
public slots:
    void init_serial();
    void read_serial();
    void open_serial();
    void close_serial();
    void send_serial();
public:
    Posix_QextSerialPort *myCom;
    QSocketNotifier *notifier;
};
#endif // MAINWINDOW_Hmainwindow.cpp文件,该文件具体实现各个函数的功能以及信号与槽之间的关系。
#include "mainwindow.h"#include "ui_mainwindow.h"//static int serial_fd;struct PortSettings myComSetting={BAUD115200,DATA_8,PAR_NONE,STOP_1,FLOW_OFF,500};MainWindow::MainWindow(QWidget *parent) :    QMainWindow(parent),    ui(new Ui::MainWindow){       init_serial();//初始化串口    //开始时三个按钮的状态    ui->setupUi(this);    ui->closeButton->setEnabled(false);    ui->sendButton->setEnabled(false);    //各个信号与槽之间的关系    //notifier=new QSocketNotifier()    connect(myCom,SIGNAL(readyRead()),this,SLOT(read_serial()));//    connect(ui->openButton,SIGNAL(clicked()),this,SLOT(open_serial()));    connect(ui->closeButton,SIGNAL(clicked()),this,SLOT(close_serial()));    connect(ui->sendButton,SIGNAL(clicked()),this,SLOT(send_serial()));}MainWindow::~MainWindow(){    delete ui;}void MainWindow::init_serial(){    myCom=new Posix_QextSerialPort("/dev/ttyUSB1",myComSetting,QextSerialBase::EventDriven);    //如果在电脑端则选择ttyUSB0,如果在开发板端则选择ttySAC0}void MainWindow::read_serial(){           QByteArray temp=myCom->readAll();//全部读取    ui->textEdit->insertPlainText(temp);//显示读取到的数据}void MainWindow::open_serial(){    myCom->open(QIODevice::ReadWrite);//打开串口    ui->openButton->setEnabled(false);    ui->closeButton->setEnabled(true);    ui->sendButton->setEnabled(true);}void MainWindow::close_serial(){    myCom->close();//关闭串口    ui->openButton->setEnabled(true);    ui->sendButton->setEnabled(false);    ui->closeButton->setEnabled(false);}void MainWindow::send_serial(){    myCom->write(ui->sendlineEdit->text().toAscii());//转化为ASCII码}至此总结:该工程可以实现,串口的发送,可是接收老出现问题,我还尝试这像前面一样加入QSocketNotifier,在PC端可以接收,可是很容易出现乱码,可能是跟终端共有一个串口的原因,于是我又两边都换了串口2,可是问题就来了,在PC端的软件打不开了。可是一旦设置minicom为串口2软件又可以打开,不知道什么原因。于是干脆狠下心来自己写串口的应用程序,具体内容见下面。

在这里有必要先了解一下底层串口的知识,在这里用到的关于串口的分别是:termios,tcgetattr,tcsetattr,tcsendbreak,tcdrain,tcflush,tcflow,cfmakeraw,cfgetospeed,cfgetispeed,cfsetispeed,cfsetospeed。分别对其进行分析:其原型为:

int tcgetattr(int fd, struct termios *termios_p);

int tcsetattr(int fd, int optional_actions, struct termios *termios_p);

int tcsendbreak(int fd, int duration);

int tcdrain(int fd);

int tcflush(int fd, int queue_selector);

int tcflow(int fd, int action);

int cfmakeraw(struct termios *termios_p);

speed_t cfgetispeed(struct termios *termios_p);

speed_t cfgetospeed(struct termios *termios_p);

int cfsetispeed(struct termios *termios_p, speed_t speed);

int cfsetospeed(struct termios *termios_p, speed_t speed);

作用:

tcgetattr() 得到与 fd 指向的对象相关的参数,将它们保存于 termios_p 引用的 termios结构中。函数可以从后台进程中调用;但是,终端属性可能被后来的前台进程所改变。

tcsetattr() 设置与终端相关的参数 (除非需要底层支持却无法满足)。

tcsendbreak() 传送连续的 0 值比特流,持续一段时间,如果终端使用异步串行数据传输的话。如果 duration 是 0,它至少传输 0.25 秒,不会超过 0.5 秒。如果 duration 非零,它发送的时间长度由实现定义。

如果终端并非使用异步串行数据传输,tcsendbreak() 什么都不做。

tcdrain() 等待直到所有写入 fd 引用的对象的输出都被传输。

tcflush() 丢弃要写入 引用的对象,但是尚未传输的数据,或者收到但是尚未读取的数据,取决于 queue_selector 的值:

刷新收到的数据但是不读 刷新写入的数据但是不传送 同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送。

tcflow() 挂起 fd 引用的对象上的数据传输或接收,取决于 action 的值:

挂起输出 重新开始被挂起的输出 发送一个 STOP 字符,停止终端设备向系统传送数据 发送一个 START 字符,使终端设备向系统传输数据 。
cfmakeraw ()设置终端属性,就是设置termios结构中的各个参数。
cfgetospeed()  返回  termios  结构中存储的输出波特率。
cfsetospeed()  设置   termios  结构中存储的输出波特率为 speed,必须是这样的格式“B115200”。
cfsetispeed()  设置  termios  结构中存储的输入波特率为 speed。如果输入波特率被设为0,实际输入波特率将等于输出波特率。

其实就是围绕着termios这个结构捣鼓来捣鼓去,把它的数据写到寄存器中去(当然得结合硬件底层驱动)。mycom.h头文件,声明各个函数,以及加入需要的头文件

#ifndef MYCOM_H
#define MYCOM_H
#include <stdio.h> //printf等用到
#include <fcntl.h> //file control
#include <string.h> //bzero等用到
#include <stdlib.h> //exit(0)等用到
#include <sys/times.h>//sleep等用到
#include <termios.h>//串口应用程序必须添加的头文件
#include <sys/types.h>//定义pid_t,size等
#include <unistd.h>//read,write,getpid等等
#include <sys/ioctl.h>//ioctl
typedef struct //define the uart value struct
{        char    prompt;         //prompt after reciving data
        int     baudrate;       //baudrate
        char    databit;        //data bits, 5, 6, 7, 8
        char    debug;          //debug mode, 0: none, 1: debug
        char    echo;           //echo mode, 0: none, 1: echo
        char    fctl;           //flow control, 0: none, 1: hardware, 2: software
        char    tty;            //tty: 0, 1, 2, 3, 4, 5, 6, 7
        char    parity;         //parity 0: none, 1: odd, 2: even
        char    stopbit;        //stop bits, 1, 2
        //const int reserved;   //reserved, must be zero
        int reserved;           //reserved, must be zero
}portinfo_t;
typedef portinfo_t *pportinfo_t; //redefine the portinfo_t
/**************** declaration the fuction to set the  uart *******************/
int PortOpen(pportinfo_t pportinfo);                   //open the uart
int PortSet(int fdcom, const pportinfo_t pportinfo);   //set the uart
void PortClose(int fdcom);                             //close the uart
int PortSend(int fdcom, char *data, int datalen);      //send the datas
int PortRecv(int fdcom, char *data, int datalen, int baudrate);//receive the datas
#endif // MYCOM_Hmycom.h的具体.cpp文件,具体去实现各个函数的功能。需要注意的地方是,对应不同的平台TTY_DEV的定义是不同的。
#include "mycom.h"#define TTY_DEV "/dev/ttyUSB" //端口路径 如果是在电脑端选择ttyUSB,在mini2440端则选择ttySAC#define TIMEOUT_SEC(buflen,baud) (buflen*20/baud+2)//接收超时#define TIMEOUT_USEC 0/*************************************************fuction:     char *get_ptty(pportinfo_t pportinfo)description: get thd uart namereturn:     ptty**************************************************/static char *get_ptty(pportinfo_t pportinfo){    char *ptty=NULL;    switch(pportinfo->tty)    {    case '0':        ptty=TTY_DEV"0";        break;    case '1':        ptty=TTY_DEV"1";        break;    case '2':        ptty=TTY_DEV"2";        break;    }    return ptty;}/*************************************************fuction:     convbaud(unsigned long int baudrate)description: baud changereturn:     ptty**************************************************/static int convbaud(unsigned long int baudrate){        switch(baudrate){                case 2400:                        return B2400;                case 4800:                        return B4800;                case 9600:                        return B9600;                case 19200:                        return B19200;                case 38400:                        return B38400;                case 57600:                        return B57600;                case 115200:                        return B115200;                default:                        return B9600;        }}/****************************************************************fuction:     convbaud(unsigned long int baudrate)description: set the uartparameters:  fdcom: 串口文件描述符,             pportinfo: 待设置的串口信息return:     tmp******************************************************************/int PortSet(int fdcom, const pportinfo_t pportinfo){    struct termios termios_old, termios_new;            int         baudrate, tmp;            char        databit, stopbit, parity, fctl;            bzero(&termios_old, sizeof(termios_old));//置字符串前sizeof个字节为零            bzero(&termios_new, sizeof(termios_new));            cfmakeraw(&termios_new);//设置终端属性            tcgetattr(fdcom, &termios_old);//get the serial port attributions            /*------------设置端口属性----------------*/            //baudrates            baudrate = convbaud(pportinfo -> baudrate);//得到波特率            cfsetospeed(&termios_new, baudrate);//填入串口输出端的波特率            termios_new.c_cflag |= CLOCAL;//控制模式,保证程序不会成为端口的占有者            // 控制模式,flow control            fctl = pportinfo-> fctl;            switch(fctl){                    case '0':{                            termios_new.c_cflag &= ~CRTSCTS;//no flow control                    }break;                    case '1':{                            termios_new.c_cflag |= CRTSCTS;//hardware flow control                    }break;                    case '2':{                            termios_new.c_iflag |= IXON | IXOFF |IXANY; //software flow control                    }break;            }            //控制模式,data bits            termios_new.c_cflag &= ~CSIZE;//控制模式,屏蔽字符大小位            databit = pportinfo -> databit;            switch(databit){                    case '5':                            termios_new.c_cflag |= CS5;                    case '6':                            termios_new.c_cflag |= CS6;                    case '7':                            termios_new.c_cflag |= CS7;                    default:                            termios_new.c_cflag |= CS8;            }            //控制模式 parity check            parity = pportinfo -> parity;            switch(parity){                    case '0':{                            termios_new.c_cflag &= ~PARENB;//no parity check                    }break;                    case '1':{                            termios_new.c_cflag |= PARENB;//odd check                            termios_new.c_cflag &= ~PARODD;                    }break;                    case '2':{                            termios_new.c_cflag |= PARENB;//even check                            termios_new.c_cflag |= PARODD;                    }break;            }            //控制模式,stop bits            stopbit = pportinfo -> stopbit;            if(stopbit == '2'){                    termios_new.c_cflag |= CSTOPB;//2 stop bits            }            else{                    termios_new.c_cflag &= ~CSTOPB;//1 stop bits            }            //other attributions default            termios_new.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);//输入模式,原始数据输入            tcflush(fdcom, TCIFLUSH);//溢出的数据可以接收,但不读            tmp = tcsetattr(fdcom, TCSANOW, &termios_new);//设置新属性,TCSANOW:所有改变立即生效      tcgetattr(fdcom, &termios_old);            return(tmp);}/****************************************************************fuction:     PortOpen(pportinfo_t pportinfo)description: open serial portparameters:  pportinfo: 待设置的串口信息return:     fdcom:文件描述符******************************************************************/int PortOpen(pportinfo_t pportinfo){        int fdcom;      //串口文件描述符        char *ptty;        ptty = get_ptty(pportinfo);        //fdcom = open(ptty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);        fdcom = open(ptty, O_RDWR | O_NOCTTY | O_NONBLOCK);        return (fdcom);}/****************************************************************fuction:     PortClose(int fdcom)description: close serial portparameters:  fdcom:文件描述符return:      NONE******************************************************************/void PortClose(int fdcom){        close(fdcom);}/****************************************************************fuction:     PortSend(int fdcom, char *data, int datalen)description: close serial portparameters:  fdcom: 串口描述符,data: 待发送数据,datalen: 数据长度return:     len:实际长度******************************************************************/int PortSend(int fdcom, char *data, int datalen){        int len = 0;        len = write(fdcom, data, datalen);//实际写入的长度        if(len == datalen){                return (len);        }        else{                tcflush(fdcom, TCOFLUSH);                return -1;        }}/****************************************************************fuction:     PortRecv(int fdcom, char *data, int datalen, int baudrate)description: receive the datasparameters:  fdcom:串口描述符, data:接收缓冲区, datalen:接收长度,             baudrate:波特率return:     readlen:实际读入的字节数******************************************************************/int PortRecv(int fdcom, char *data, int datalen, int baudrate){    int readlen, fs_sel;            fd_set      fs_read;            struct timeval tv_timeout;            FD_ZERO(&fs_read);            FD_SET(fdcom, &fs_read);            tv_timeout.tv_sec = TIMEOUT_SEC(datalen, baudrate);            tv_timeout.tv_usec = TIMEOUT_USEC;            fs_sel = select(fdcom+1, &fs_read, NULL, NULL, &tv_timeout);            if(fs_sel){                    readlen = read(fdcom, data, datalen);                    return(readlen);            }            else{                    return(-1);            }            return (readlen);}

总算到Qt端了:serial.h头文件,声明各个控件以及引用mycom.h,定义关于串口的各个槽函数#ifndef SERIAL_H
#define SERIAL_H
#include <QtGui>
#include "mycom.h"
class serial : public QWidget
{    Q_OBJECT
public:
    serial(QWidget *parent = 0);
    ~serial();
    void layout();
    void init_serial();
public:
    QTextBrowser *textbrowser;
    QLineEdit *lineedit;
    QPushButton *open_button;
    QPushButton *close_button;
    QPushButton *send_button;
    QLabel *label1;
    QLabel *label2;
public slots:
    void open_serial();
    void close_serial();
    void read_serial();
    void send_setial();
};
#endif // SERIAL_Hserial.h的具体实现,要注意的地方是数据类型的转换,QLineEdit的text().toASCII返回的是QByteArray,而PortSend要发送的是
char类型的数据,所以就需要转换,在Qt中使用.data()就可以实现转换。还有要注意的地方就是QSocketNotifier不要忘记添加了。
#include "serial.h"
portinfo_t portinfo = {    '0',      // print prompt after receiving    115200,   // baudrate: 115200    '8',      // databit 8    '0',      // debug: off    '0',      // echo off    '2',      // flow control: software    '0',      // default tt: SAC0    '0',      // parity: none    '1',      // stopbit: 1     0       // reserved};static int serial_fd;char databuffer[20];int datalen;serial::serial(QWidget *parent)    : QWidget(parent){    layout();//lay out    open_button->setEnabled(true);    close_button->setEnabled(false);    send_button->setEnabled(false);    connect(open_button,SIGNAL(clicked()),this,SLOT(open_serial()));    connect(close_button,SIGNAL(clicked()),this,SLOT(close_serial()));    connect(send_button,SIGNAL(clicked()),this,SLOT(send_setial()));    QSocketNotifier *notifier=new QSocketNotifier(serial_fd,QSocketNotifier::Read,this);    connect(notifier,SIGNAL(activated(int)),this,SLOT(read_serial()));    read_serial();}serial::~serial(){}void serial::init_serial(){}void serial::open_serial(){    serial_fd=PortOpen(&portinfo);    if(serial_fd<0)    {        perror("Error:open serial port error");        //exit(1);    }    PortSet(serial_fd,&portinfo);    open_button->setEnabled(false);    close_button->setEnabled(true);    send_button->setEnabled(true);}void serial::close_serial(){    PortClose(serial_fd);    open_button->setEnabled(true);    close_button->setEnabled(false);    send_button->setEnabled(false);}void serial::read_serial(){    datalen=PortRecv(serial_fd,databuffer,10,115200);    textbrowser->insertPlainText(databuffer);}void serial::send_setial(){    QByteArray temp=lineedit->text().toAscii();    PortSend(serial_fd,temp.data(),10);}void serial::layout(){    label1=new QLabel("Receive:");    label2=new QLabel("Send:");    open_button=new QPushButton("Open");    close_button=new QPushButton("Close");    send_button=new QPushButton("Send");    textbrowser=new QTextBrowser(this);    lineedit=new QLineEdit;    lineedit->setText("123489");    QVBoxLayout *vlayout1=new QVBoxLayout;    vlayout1->addWidget(label1);    vlayout1->addWidget(textbrowser);    vlayout1->addWidget(label2);    QVBoxLayout *vlayout3=new QVBoxLayout;    vlayout3->addWidget(open_button);    vlayout3->addWidget(close_button);    QHBoxLayout *hlayout2=new QHBoxLayout;    hlayout2->addLayout(vlayout1);    hlayout2->addLayout(vlayout3);    QHBoxLayout *hlayout1=new QHBoxLayout;    hlayout1->addWidget(lineedit);    hlayout1->addWidget(send_button);    QVBoxLayout *vlayout2=new QVBoxLayout;    vlayout2->addLayout(hlayout2);    vlayout2->addLayout(hlayout1);    setLayout(vlayout2);}总结:总算完成了,前后花了两天的时候,很高兴的是自己没有放弃。至于这个串口的QT有什么用,那作用老大了,以前我用VB写过环境监控系统,在PC端实现的,低下用的是ADUC824,那代码,叫宏伟啊。Qt就简单多了(站在巨人的肩膀上)。有了UART的通信,一些控制类的东西都可以实现了,而且界面还可以做得要多漂亮就有多漂亮(看个人的了)。

文章转载自:http://suyuxuan0412.blog.163.com/blog/static/173898128201010270631709/

mini2440的串口在Qt上实现相关推荐

  1. 嵌入式学习之QT学习---5 QT上位机开发之串口助手(上)

    1.qt的三驾马车 qt下的串口编程 qt下的网络编程 qt下操作GPIO 2.设计ui界面 设计ui界面之前,需要新建一个QT工程,简要再回顾一下创建QT工程的步骤:new project-> ...

  2. qt服务器获取formdata文件,QT上传(PUT)文件

    我正在使用QT将文件上传到Web服务器.QT上传(PUT)文件 curl -X POST -H 'Content-Type:multipart/form-data' -H 'Authorization ...

  3. 为MCU在Qt上运行Doom

    Running Doom on Qt for MCUs 为MCU在Qt上运行Doom Thursday April 28, 2022 by Åsa Forsell | Comments ​2022年4 ...

  4. 利用串口网络助手上传数据、图片到OneNet平台以及获取数据(HTTP)

    利用串口网络助手上传数据.图片到OneNet平台以及获取数据(HTTP) 使用网络助手连接OneNet服务器 HTTP上传数据至OneNet 获取数据 上传图片至OneNet 使用网络助手连接OneN ...

  5. 「seetaface2」中科院人脸识别引擎seetaface2在Linux Qt上的配置教程

    笔者的最新私人博客网站经过一段时间的努力,已经初期建设完毕,csdn上的博文会逐渐转移过去-- 欢迎访问呀- |=传=送=门=> 多多洛的博客 2016年,中科院山世光老师开源了其研发的seet ...

  6. QT上实现FTP传输

    QT上实现FTP传输 项目开发中,需要使用到FTP协议进行文件传输,现有QT自带的库中支持FTP传输的为 QNetworkAccessManager,虽然此类可以实现 Ftp 的上传/下载功能,但有的 ...

  7. QT上实现文件拖拽功能

    转自于QT上实现文件拖拽功能 声明dragEnterEvent和dropEvent事件函数,对窗口的拖拽行为进行处理 // 由MainWindow来截取拖拽事件 ①ui->lineEdit-&g ...

  8. 【记录】将QT上绘制的PRPD图谱转为vs+DUILIB绘制中遇到的问题

    这里写自定义目录标题 QT绘制PRPD 图谱转为vs+DUILIB绘制 总结 QT绘制PRPD 在Qt上先将图谱绘制到位图中,然后再将位图绘制到QWidget上,这样外部窗口变换大小都不会影响到图谱的 ...

  9. STM32MP157实现串口接收数据上云-MP157连接4G模块和电脑

    文章目录 前言 一.打开设备文件 二.串口初始化 三.多线程 四.程序的移植和执行 五.源码(转载请注明出处) 结语 前言 本篇分享: 这次将会用几篇博客分享STM32MP157实现串口接收数据上云的 ...

  10. 使用Arduino开发ESP32-CAM系列1——连接ESP32-CAM,esp32-cam串口连接不上

    注:我买的开发板有大坑!如果有遇到esp32-cam串口连接不上或者esp32-cam串口不显示的童鞋可以参考参考. 开发环境:Arduino + ESP32库 附加开发板管理网址:https://d ...

最新文章

  1. [MySql] - 开启外部访问
  2. 关于myBatis的问题There is no getter for property named 'USER_NAME' in 'class com.bky.model.实例类'...
  3. JDK10的新特性:var和匿名类
  4. php下载文件代码 数据库,PHP备份数据库生成SQL文件并下载的函数代码
  5. Linux时间date与timedatectl
  6. mysql20170410练习代码+笔记
  7. 【华为大咖分享】6.华为专家揭秘研发效能提升之道(后附PPT下载地址)
  8. 2020年Q3笔记本电脑出货量:惠普反超联想居首位 苹果第四
  9. python图形绘制含注释
  10. KMP算法 --- 深入理解next数组
  11. Android 和iOS 比较
  12. Vue3中Compositions API的使用(二)
  13. random和stochastic的区别
  14. 住房公积金联名卡密码修改步骤
  15. 列表(list)使用方法详解
  16. 爱情十三课,爱人的五功能
  17. 黄淮学院CSDN高校俱乐部把梳子卖给和尚话剧表演活动
  18. OGRE 1.8 Animation ,动画部分
  19. android 语音交互动画,Android实现客户端语音动弹界面实例代码
  20. 移动端上下拖动调整顺序效果_vue实现移动端拖动排序

热门文章

  1. 51单片机之继电器实验
  2. si24r1程序_SI24R1技术支持--程序 射频识别(radio frequency indentificationx) - 下载 - 搜珍网...
  3. Lamda表达式-入门篇
  4. 怎样把自己喜欢的微信表情包(动态)导出来,我三岁半的表弟都会...
  5. js距离米转换为千米_千米换算(千米与米之间的换算题)
  6. ai的预览模式切换_ai模式切换快捷键是什么,Adobe Illustrator模式切换快捷键是什么?...
  7. 教你玩转私域流量+会员运营体系
  8. dota2国服服务器延迟高,为何dota2国服经常崩溃 竟然是良心不分区的原因
  9. 2022-2028年中国饮用水市场投资分析及前景预测报告(全卷)
  10. 公式、图片、表格等转latex