【飛凌嵌入式 OK3399-C+開(kāi)發(fā)板試用體驗(yàn)】使用QT工程讀取DHT11模塊的波折經(jīng)歷

原創(chuàng) 2020-09-30 12:28:00 RK3399 RK3399開(kāi)發(fā)板

作者:donatello1996

上一帖中已經(jīng)成功使用一個(gè)簡(jiǎn)單的main函數(shù)成功讀取到DHT11的溫濕度數(shù)據(jù)了,雖然讀取溫濕度數(shù)據(jù)響應(yīng)時(shí)間很慢,但至少算是成功讀取了,這次我就想在QT環(huán)境下進(jìn)行溫濕度的讀取,結(jié)合美觀的圖形界面呈現(xiàn)出來(lái),同時(shí),還可以以文件形式讀取ADC_IN4接口 CPU0溫度以及CPU1溫度,使用到的QT類為QThread,還有Linux系統(tǒng)自帶的pthread。為什么說(shuō)是波折經(jīng)歷呢,因?yàn)镈HT11這個(gè)器件對(duì)主控和系統(tǒng)的實(shí)時(shí)性要求實(shí)在是太高了,如果是直接用單片機(jī)主控來(lái)讀取,那就沒(méi)任何問(wèn)題,但是要用到微處理器,哪怕是RK3399這種主頻那么高的CPU,讀取DHT11依然會(huì)出現(xiàn)實(shí)時(shí)性問(wèn)題,這就很煩,由于QT的圖形化界面用到了QMainWindow類,會(huì)占用一定的CPU實(shí)時(shí)資源,在這一兩天的探索過(guò)程中,我先后用了QThread pthread QTimer三種方式讀取DHT11數(shù)據(jù),結(jié)果表明,要想穩(wěn)定讀取,只能用pthread進(jìn)行,QThread這種QT內(nèi)建的多線程實(shí)現(xiàn)類完全無(wú)法讀取,頂多只能讀取已經(jīng)存在/sys中的實(shí)時(shí)CPU溫度數(shù)據(jù)和ADC接口數(shù)據(jù),而QTimer這種定時(shí)器中斷類就更不用說(shuō)了,實(shí)時(shí)性比QThread還低得多,跟pthread的效率比起來(lái)就沒(méi)法比。我不知道QThread的實(shí)現(xiàn)代碼是怎么寫的,按我理解來(lái)說(shuō)應(yīng)該也只是對(duì)pthread做一定的封裝,也沒(méi)想到實(shí)時(shí)性/效率差這么遠(yuǎn)。 


首先是讀寫兩個(gè)CPUzone的溫度,需要讀取/sys/class/thermal/thermal_zone0/temp和/sys/class/thermal/thermal_zone1/temp:
int fd_cputemp0,fd_cputemp1;
unsigned char buf_cpu_temp0[5];
unsigned char buf_cpu_temp1[5];
fd_cputemp0 = open("/sys/class/thermal/thermal_zone0/temp", O_RDONLY);
fd_cputemp1 = open("/sys/class/thermal/thermal_zone1/temp", O_RDONLY);
read(fd_adc4 , buf_adc4 ,5);
read(fd_cputemp0 , buf_cpu_temp0 ,5);
read(fd_cputemp1 , buf_cpu_temp1 ,5);
 

而ADC_IN4則是用同樣的方法讀取/sys/bus/iio/devices/iio:device0/in_voltage4_raw:
int fd_adc4;
unsigned char buf_adc4[5];
fd_adc4 = open("/sys/bus/iio/devices/iio:device0/in_voltage4_raw", O_RDONLY);
read(fd_adc4 , buf_adc4 ,5);
 

然后是對(duì)于DHT11的讀取,原本我是打算使用QThread來(lái)進(jìn)行讀取了,也寫好了QThread類:

#ifndef MY_THREAD_H
#define MY_THREAD_H
#include <QThread>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "mainwindow.h"
class MainWindow;
class mythread : public QThread
{
public:
    mythread(QObject *parent);
    void closeThread();
    struct timeval tv1;
protected:
    virtual void run();
private:
    volatile bool isStop;
    MainWindow *m_pMainWindow;
    int fd_cputemp0,fd_cputemp1,fd_adc4;
};
#endif // DHT11_THREAD_H


#include "mythread.h"
#include "mainwindow.h"
#include <ui_mainwindow.h>
mythread::mythread(QObject *parent)
{
    isStop = false;
    m_pMainWindow = qobject_cast<MainWindow*>(parent);
}
void mythread::closeThread()
{
    isStop = true;
}
extern float dht11_temp,dht11_humi;
void mythread::run()
{
    int i=0;
    unsigned char buf_adc4[5];
    unsigned char buf_cpu_temp0[5];
    unsigned char buf_cpu_temp1[5];
    while (1)
    {
        if(isStop)
            return;
        //gettimeofday(&tv1, NULL);
        //qDebug("tv1=%d\n",tv1.tv_usec);
        fd_adc4 = open("/sys/bus/iio/devices/iio:device0/in_voltage4_raw", O_RDONLY);
        fd_cputemp0 = open("/sys/class/thermal/thermal_zone0/temp", O_RDONLY);
        fd_cputemp1 = open("/sys/class/thermal/thermal_zone1/temp", O_RDONLY);
        read(fd_adc4 , buf_adc4 ,5);
        read(fd_cputemp0 , buf_cpu_temp0 ,5);
        read(fd_cputemp1 , buf_cpu_temp1 ,5);
        buf_adc4[4]=0;
        m_pMainWindow->ui->L1->setText(QString("%1").arg(dht11_temp));
        m_pMainWindow->ui->L2->setText(QString("%1").arg(dht11_humi));
        m_pMainWindow->ui->L3->setText(QString((char*)buf_adc4));
        m_pMainWindow->ui->L4->setText(QString((char*)buf_cpu_temp0));
        m_pMainWindow->ui->L5->setText(QString((char*)buf_cpu_temp1));
        sleep(1);
    }
}
誰(shuí)知道讀取不成功,估計(jì)是read函數(shù)所在線程被CPU打斷了,無(wú)奈之下只能換成Linux最基本的pthread實(shí)現(xiàn)方式:
struct dht11_data
{
    unsigned short temp;
    unsigned short hum;
}curdht11_data;
float dht11_temp,dht11_humi;
pthread_t id;
int fd_dht11;
void *Thread_CPU_Temp(void *arg)
{
    int retval;
    while(1)
    {
        retval = read ( fd_dht11 , &curdht11_data , sizeof(curdht11_data) );
        if ( retval == -1 )
        {
            printf ( "read dht11 error" ) ;
        }
        if(curdht11_data.temp != 0xffff)
        {
            if(0 < (curdht11_data.temp>>8) && (curdht11_data.temp>>8) < 85)
            {
                dht11_temp = (curdht11_data.temp >> 8) + (curdht11_data.temp & 0xff) * 0.01;
                dht11_humi = (curdht11_data.hum >> 8) + (curdht11_data.hum & 0xff) * 0.01;
                printf("---- %f %f-----\n",dht11_temp,dht11_humi);
            }
        }
        //sleep(1);
    }
}
這樣的話可以正常讀取,由此判斷pthread實(shí)現(xiàn)方式能搶占到更多的CPU資源,并且pthread線程創(chuàng)建必須在MainWindow主窗口之前:
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    fd_dht11 = open ( "/dev/dht11" , O_RDONLY) ;
    if ( fd_dht11 == -1 )
    {
        perror ( "open dht11 error\n" ) ;
    }
    printf ( "open /dev/dht11 successfully\n" ) ;
    pthread_create(&id , NULL , Thread_CPU_Temp , NULL);
    printf ( "create pthread successfully\n" ) ;
    MainWindow w;
    w.show();
    return a.exec();
}
QThread線程就只拿來(lái)讀取CPU0溫度,CPU1溫度和ADC_IN4通道,Qthread線程的運(yùn)行和暫停又一個(gè)按鈕來(lái)控制:
void MainWindow::on_PB1_clicked()
{
    disconnect(ui->PB1,SIGNAL(clicked()),this,SLOT(on_PB1_clicked()));
    connect(ui->PB1,SIGNAL(clicked()),this,SLOT(on_PB1_clicked_2()));
    ui->PB1->setText("Pause");
    thread1->start();
}
void MainWindow::on_PB1_clicked_2()
{
    disconnect(ui->PB1,SIGNAL(clicked()),this,SLOT(on_PB1_clicked_2()));
    connect(ui->PB1,SIGNAL(clicked()),this,SLOT(on_PB1_clicked()));
    ui->PB1->setText("Start");
    thread1->closeThread();
    thread1->wait();
}
 

相關(guān)產(chǎn)品 >

  • FET3399-C核心板

    飛凌RK3399安卓高性能核心板采用 采用六核Rockchip RK3399芯片,雙Cortex-A72大核+四Cortex-A53小核結(jié)構(gòu),對(duì)整數(shù)、浮點(diǎn)、內(nèi)存等作了大幅優(yōu)化,在整體性能、功耗及核心面積三個(gè)方面提升。以下將對(duì)瑞芯微芯片RK3399參數(shù),RK3399核心板方案及其性能做具體介紹。如您對(duì)飛凌RK3399系列核心板有興趣,歡迎咨詢了解。

    了解詳情
    FET3399-C核心板
  • OK3399-C開(kāi)發(fā)板

    飛凌嵌入式RK3399安卓開(kāi)發(fā)板主芯片采用高性能六核CPU Rockchip RK3399,GPU采用Mail-T860四核 GPU,RK3399作為目RK產(chǎn)品線中低功耗、高性能的代表,可滿足人臉識(shí)別設(shè)備、機(jī)器人、無(wú)人機(jī)、IoT物聯(lián)網(wǎng)領(lǐng)域應(yīng)用。飛凌RK3399開(kāi)發(fā)板在整體性能、功耗及核心面積做了大幅度優(yōu)化,更加滿足工業(yè)設(shè)計(jì)需求。飛凌RK3399開(kāi)發(fā)板為進(jìn)一步減少用戶二次開(kāi)發(fā)難度,開(kāi)放了底板原理圖,并提供了RK3399用戶手冊(cè)、芯片手冊(cè),加上優(yōu)質(zhì)的技術(shù)服務(wù),讓您的方案從構(gòu)思到上市時(shí)間縮短。

    了解詳情
    OK3399-C開(kāi)發(fā)板

推薦閱讀 換一批 換一批