zoukankan      html  css  js  c++  java
  • 北京迅为IMX6ULL开发板 DHT11&网络编程实战练习

    转自:【北京迅为i.mx6ull终结者开发板使用手册第六十三章 QT 实战项目

    硬件平台:IMX6ULL开发板

     

    63.1 DHT11&网络编程实战练习

    本项目为阶段性练习,内容简洁实用,目的在于让初学者能够巩固前面知识,学以致用,逐步提升 C++ Qt 水平,为学习下面的教程做铺垫。本章节使用的资料已经放到了开发板网盘资料中,路径为“11_Linux 系统开发进阶Qt 开发_章节使用资料”

    63.1.1 项目前准备

    工具及环境:  

    1. 开发环境:Ubuntu16.04

    2. 工具:Qt creator

    3. 迅为电子 i.MX6ULL 终结者开发板

    MX6ULL 终结者开发板已板载了 DHT11 传感器,且提供的 Linux 镜像和设备树已配置好了 dht11 接口, dht11 驱动程序使用高版本 Linux 内核自带的稳定驱动程序,根文件系统使用网盘资料里的 Yocto 镜像,使用手册有详细的系统移植和 Qt5 移植步骤。开发板要保证 iio 接口正常,如图 63.1.1.1

    cd /sys/bus/iio/devices/iio:device1

     

    cat 几次, cat in_temp_input ,出现 00 为结尾的数字为正常

     

    63.1.2 软件流程图

    本实验目的是练习 Qt 的使用。把 dht11 采集的温度湿度显示在触摸屏的 Qt 上,并通过 TCP 传输到 PC 机的 Qt 界面上。应用程序将采集到的数据利用 UDP 网络套接字传输给终结者的 Qt 进程,终结者的 Qt 将数据转发给 PC 端的 Qt 显示界面。流程图如图 63.1.2.1:

     

    63.1.3 Linux 应用程序

    功能描述:

    1. 获取温湿度数据。

    2. 将温湿度封装成消息通过 UDP 发送到 i.MX6ULL 服务器。

    高版本 Linux 内核自带了 dht11 的驱动,使用者不用再去关心它的时序问题,可以用标准 IO 读取 sysfs

    的/sys/bus/iio/devices/iio:device1/下的温湿度端口,测试读取成功后将数据发送到 Qt 进程。

    为了让读者更好地理解 Qt UDP,所以此处没有用到操作系统进程间通信机制,直接使用 UDP 网络

    套接字,代码在 readDHT11.c

    #include <stdio.h>

    #include <stdlib.h>

    #include <fcntl.h>

    #include <unistd.h>

    #include <math.h>

    #include <sys/socket.h>

    #include <netinet/in.h>

    #include <arpa/inet.h>

    #include <netinet/in.h>

    #include <string.h>

    struct sockaddr_in serveraddr;

    63.1.3 Linux 应用程序

    功能描述:

    1. 获取温湿度数据。

    2. 将温湿度封装成消息通过 UDP 发送到 i.MX6ULL 服务器。

    高版本 Linux 内核自带了 dht11 的驱动,使用者不用再去关心它的时序问题,可以用标准 IO 读取 sysfs

    的/sys/bus/iio/devices/iio:device1/下的温湿度端口,测试读取成功后将数据发送到 Qt 进程。

    为了让读者更好地理解 Qt UDP,所以此处没有用到操作系统进程间通信机制,直接使用 UDP 网络

    套接字,代码在 readDHT11.c

    #include <stdio.h>

    #include <stdlib.h>

    #include <fcntl.h>

    #include <unistd.h>

    #include <math.h>

    #include <sys/socket.h>

    #include <netinet/in.h>

    #include <arpa/inet.h>

    #include <netinet/in.h>

    #include <string.h>

    struct sockaddr_in serveraddr;

    63.1.3 Linux 应用程序

    功能描述:

    1. 获取温湿度数据。

    2. 将温湿度封装成消息通过 UDP 发送到 i.MX6ULL 服务器。

    高版本 Linux 内核自带了 dht11 的驱动,使用者不用再去关心它的时序问题,可以用标准 IO 读取 sysfs

    的/sys/bus/iio/devices/iio:device1/下的温湿度端口,测试读取成功后将数据发送到 Qt 进程。

    为了让读者更好地理解 Qt UDP,所以此处没有用到操作系统进程间通信机制,直接使用 UDP 网络

    套接字,代码在 readDHT11.c

    #include <stdio.h>

    #include <stdlib.h>

    #include <fcntl.h>

    #include <unistd.h>

    #include <math.h>

    #include <sys/socket.h>

    #include <netinet/in.h>

    #include <arpa/inet.h>

    #include <netinet/in.h>

    #include <string.h>

    struct sockaddr_in serveraddr;

    fread( buf, 1, sizeof(buf), fp );

    fclose(fp);

    sscanf( buf, "%d", &value );

    *tem_Value = value;

    return 0;

    }

    int mathDHT(int value)

    {

    return (value/1000);

    }

    /*

    * 获取 UDP socket

    */

    int udpNet(void)

    {

    int sockfd;

    sockfd = socket(AF_INET,SOCK_DGRAM,0);

    if(sockfd <0){

    perror("socket");

    return -1;

    }

    return sockfd;

    }

    int main(int argc, const char *argv[])

    {

    int hum,tem,temNew,humiNew;

    int temOld=0,humOld=-10;

    int fdSocket = udpNet();//获取 UDP 套接字

    char ts[6];

    serveraddr.sin_family = AF_INET;

    serveraddr.sin_port = htons(atoi("7089")); //目标端口号

    serveraddr.sin_addr.s_addr = 0; //本机 IP

    while(1){

    sleep(1);

    read_Temp(&tem);//获取温度

    fread( buf, 1, sizeof(buf), fp );

    fclose(fp);

    sscanf( buf, "%d", &value );

    *tem_Value = value;

    return 0;

    }

    int mathDHT(int value)

    {

    return (value/1000);

    }

    /*

    * 获取 UDP socket

    */

    int udpNet(void)

    {

    int sockfd;

    sockfd = socket(AF_INET,SOCK_DGRAM,0);

    if(sockfd <0){

    perror("socket");

    return -1;

    }

    return sockfd;

    }

    int main(int argc, const char *argv[])

    {

    int hum,tem,temNew,humiNew;

    int temOld=0,humOld=-10;

    int fdSocket = udpNet();//获取 UDP 套接字

    char ts[6];

    serveraddr.sin_family = AF_INET;

    serveraddr.sin_port = htons(atoi("7089")); //目标端口号

    serveraddr.sin_addr.s_addr = 0; //本机 IP

    while(1){

    sleep(1);

    read_Temp(&tem);//获取温度

    fread( buf, 1, sizeof(buf), fp );

    fclose(fp);

    sscanf( buf, "%d", &value );

    *tem_Value = value;

    return 0;

    }

    int mathDHT(int value)

    {

    return (value/1000);

    }

    /*

    * 获取 UDP socket

    */

    int udpNet(void)

    {

    int sockfd;

    sockfd = socket(AF_INET,SOCK_DGRAM,0);

    if(sockfd <0){

    perror("socket");

    return -1;

    }

    return sockfd;

    }

    int main(int argc, const char *argv[])

    {

    int hum,tem,temNew,humiNew;

    int temOld=0,humOld=-10;

    int fdSocket = udpNet();//获取 UDP 套接字

    char ts[6];

    serveraddr.sin_family = AF_INET;

    serveraddr.sin_port = htons(atoi("7089")); //目标端口号

    serveraddr.sin_addr.s_addr = 0; //本机 IP

    while(1){

    sleep(1);

    read_Temp(&tem);//获取温度

    63.1.4 终结者 Qt 服务器

    Qt 服务器功能描述:

    1.接收应用程序发来的数据并解析;

    2.界面显示出:温湿度,PC 客户端的连接状态,系统时间;

    3.通过 TCP PC 客户端发送数据包。

    63.1.4.1 界面布局

    温度显示:LCD Number

    湿度显示:LCD Number

    系统时间,连接状态提示: Label

    关闭按钮:push Button

    Mainwindow.ui :

     

    在属性栏设置主窗口尺寸,宽度为 1024,高度为 600,添加两个 LCD Number 组件,设置最小宽度 500,最小高度为 290,然后垂直布局两个 LCD Number,如:图 63.1.4.1.2

     

    LCD Number 添加颜色,右击此组件,选择“改变样式表”,

     

    在弹出的界面选择“添加颜色”,点击“color”,

     

    在弹出的颜色选择框中选择想要添加的颜色,然后点击“OK”。




    自动回到样式表编辑器,可以看到添加的 color,点击”apply”,然后点击”OK”,发现 LCD Number 的颜色已经改变,另外一个 LCD Number 的操作方法不再赘述。

     

    在主界面右上角添加两个 Label,一个用来显示时间,一个显示 TCP 连接状态,宽度 500,高度 130,垂直布局,如图 63.1.4.1.7:

     

    添加退出按钮,设置最小高度 80,最小宽度 100,修改字体大小:

     

    在按钮左侧添加 Label,最小宽度 300,最小高度 290,在按钮和 Label 间添加弹簧,然后水平布局,效果如图 63.1.4.1.9:

     

    点击主窗口,然后点击栅格布局,效果如图 63.1.4.1.10:

     

    最后改变各控件的名称,方便在代码中调用。

    到此,服务器端基本 ui 界面组装完成,读者可以在此基础上美化。

    63.1.4.2 UDP 服务器端

    步骤一:在工程下创建设计师界面类 datafrom,自动生成 .h .cpp .ui 文件。Ui 界面 Label 显示连接状态,close 按钮自动关联槽函数(右键转到槽),槽函数内关闭此界面。

    void datafrom::on_pushButton_clicked()

    {

    this->close();

    }

    步骤二:创建 UDP socket 套接字,绑定数据信号和读取数据槽函数。

    步骤三:读取数据槽函数内读取解析数据。

    datafrom.h:

    class datafrom : public QWidget

    {

    Q_OBJECT

    public:

    explicit datafrom(QWidget *parent = nullptr);

    ~datafrom();

    QUdpSocket * udpSocket;

    QString tempt;//保存温度值

    QString humid;//保存湿度值

    private slots:

    void readyRead_Slot(void);

    void on_pushButton_clicked();

    private:

    Ui::datafrom *ui;

    };

    datafrom.cpp :

    #include <QDebug>

    #include <QUdpSocket>

    datafrom::datafrom(QWidget *parent) :

    QWidget(parent),

    ui(new Ui::datafrom)

    {

    ui->setupUi(this);

    udpSocket = new QUdpSocket(this);

    //绑定本端口的端口号

    if(udpSocket->bind(7089) == true){

    ui->message->setText("Udp create successful!");

    }else{

    ui->message->setText("Udp create failed");

    }

    //绑定数据信号和槽函数

    connect(udpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Slot()));

    }

    datafrom::~datafrom()

    {

    delete ui;

    }

    /*

    *读取数据槽函数

    */

    void datafrom::readyRead_Slot()

    {

    QString buf;

    QByteArray array;

    //hasPendingDatagrams()返回 true 时表示至少有一个数据报在等待被读取

    while(udpSocket->hasPendingDatagrams()){

    //获取数据

    array.resize(udpSocket->pendingDatagramSize());

    udpSocket->readDatagram(array.data(),array.size());

    buf = array.data();

    QString t = buf.mid(0,2);

    QString h = buf.mid(3,4);

    tempt = t;

    humid = h;

    qDebug()<<tempt << " udp "<< humid <<endl;

    }

    }

    //关闭此窗口

    void datafrom::on_pushButton_clicked()

    {

    this->close();

    }

    Mainwindow.cpp

    udpcli = new datafrom(this);

    //获取 UDP 对象的温湿度成员

    temp = udpcli->tempt;

    humid = udpcli->humid;

     

    在开发板终端可看到对应的打印信息。

    63.1.4.3 TCP 服务器端

    步骤一:创建 TCP server socket 套接字对象,绑定端口号,开始监听,等待客户端连接,绑定newConnection() newConnection_Slot()槽函数。

    步骤二:新连接 newConnection_Slot()槽函数内开启定时器,定时时间(刷新时间)到后向 TCP 客户端发送消息,

    void MainWindow::newConnection_Slot(void)

    {

    tcpSocket = tcpServer->nextPendingConnection();

    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Solt()));

    ui->messageLb->setText("连接成功");

    timer.start(1000);

    connect(&timer,SIGNAL(timeout()),this,SLOT(send_Solt()));//定时

    //将客户端连接异常信号与槽函数绑定。

    connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),this,

    SLOT(clientError_Solt(QAbstractSocket::SocketError)));//客户端状态异常

    }

    //发送数据

    void MainWindow::send_Solt()

    {

    //显示时间

    ui->timeLb->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz"));

    // UDP 对象获取数据

    temp = udpcli->tempt;

    humid = udpcli->humid;

    //显示到 Qt LCDNumber 界面

    ui->tempLcd->display(temp);

    ui->humidLcd->display(humid);

    //消息封装,将消息推送到客户端

    QString post = "Post::" +temp + "," + humid;

    tcpSocket->write(post.toUtf8());

    }

    步骤三:将客户端连接状态显示到界面上。

    //连接异常处理

    void MainWindow::clientError_Solt(QAbstractSocket::SocketError)

    {

    int error = tcpSocket->error();

    switch(error)

    {

    case QAbstractSocket::RemoteHostClosedError://客户端断开

    {

    //获取客户端的信息

    QString hostAddress=tcpSocket->QAbstractSocket::peerAddress().toString();

    quint16 hostPort = tcpSocket->QAbstractSocket::peerPort();

    ui->messageLb->setText(tr("客户端 %2 断开连接 ").arg(hostAddress));

    ui->zeroLb->setText(tr("

    %2 断开连接 ").arg(hostPort));

    break;

    }

    default:

    {

    QString hostAddress=tcpSocket->QAbstractSocket::peerAddress().toString();

    quint16 hostPort = tcpSocket->QAbstractSocket::peerPort();

    error = -1;

    ui->messageLb->setText(tr("客户端[%1] [%1]连接错误 ").arg(hostAddress,hostPort));

    break;

    }

    }

    }

    至此终结者的 Qt 服务器端编程基本结束,可以联网使用 windows 的一些小工具来调试服务器的收发功能。

     

    http://topeetboard.com

  • 相关阅读:
    学习ios键盘和textfield之间操作体会
    关于Cannot assign to 'self' outside of a method in the init family解决方法
    "this class is not key value coding-compliant for the key ..."问题的解决
    在编译oc中protocol时出现的错误
    关于oc中出现的typedef的用法/定义函数指针
    VC++、MFC、COM和ATL的区别
    leetcode : Spiral Matrix II
    leetcode : Length of Last Word [基本功]
    leetcode : triangle
    leetcode : Insert Interval
  • 原文地址:https://www.cnblogs.com/topeet/p/13930688.html
Copyright © 2011-2022 走看看