簡體   English   中英

使用pi4j從DHT11讀取溫度

[英]read temperature from DHT11, using pi4j

我正在嘗試使用pi4j從DHT11溫度傳感器讀取溫度數據。 我按照c和python編寫的代碼訪問了這個站點: http//www.uugear.com/portfolio/dht11-h ... or-module /但是它沒有用。 當我測試指令'dht11Pin.getState()'時,它總是處於HIGH狀態,永遠不會改變。 我的代碼有什么問題嗎?

以下是我的代碼:

import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.pi4j.component.ObserveableComponentBase;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalMultipurpose;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.PinMode;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;

public class DHT11 extends ObserveableComponentBase {

private static final Pin DEFAULT_PIN = RaspiPin.GPIO_04;
private static final int MAXTIMINGS = 85;
private int[] dht11_dat = { 0, 0, 0, 0, 0 };
private GpioPinDigitalMultipurpose dht11Pin;
private static final Logger LOGGER = LogManager.getLogger(DHT11.class
        .getName());

public DHT11() {
    final GpioController gpio = GpioFactory.getInstance();
    dht11Pin = gpio.provisionDigitalMultipurposePin(DEFAULT_PIN,
            PinMode.DIGITAL_INPUT, PinPullResistance.PULL_UP);
}

public DHT11(int pin) {
    final GpioController gpio = GpioFactory.getInstance();
    dht11Pin = gpio.provisionDigitalMultipurposePin(LibPins.getPin(pin),
            PinMode.DIGITAL_INPUT, PinPullResistance.PULL_UP);
}

public double getTemperature() {
    PinState laststate = PinState.HIGH;
    int j = 0;
    dht11_dat[0] = dht11_dat[1] = dht11_dat[2] = dht11_dat[3] = dht11_dat[4] = 0;
    StringBuilder value = new StringBuilder();
    try {

        dht11Pin.setMode(PinMode.DIGITAL_OUTPUT);
        dht11Pin.low();
        Thread.sleep(18);
        dht11Pin.high();
        TimeUnit.MICROSECONDS.sleep(40);
        dht11Pin.setMode(PinMode.DIGITAL_INPUT);

        for (int i = 0; i < MAXTIMINGS; i++) {
            int counter = 0;
            while (dht11Pin.getState() == laststate) {
                counter++;
                TimeUnit.MICROSECONDS.sleep(1);
                if (counter == 255) {
                    break;
                }
            }

            laststate = dht11Pin.getState();

            if (counter == 255) {
                break;
            }

            /* ignore first 3 transitions */
            if ((i >= 4) && (i % 2 == 0)) {
                /* shove each bit into the storage bytes */
                dht11_dat[j / 8] <<= 1;
                if (counter > 16) {
                    dht11_dat[j / 8] |= 1;
                }
                j++;
            }
        }
        // check we read 40 bits (8bit x 5 ) + verify checksum in the last
        // byte
        if ((j >= 40) && checkParity()) {
            value.append(dht11_dat[2]).append(".").append(dht11_dat[3]);
            LOGGER.info("temperature value readed: " + value.toString());
        }

    } catch (InterruptedException e) {

        LOGGER.error("InterruptedException: " + e.getMessage(), e);
    }
    if (value.toString().isEmpty()) {
        value.append(-1);
    }
    return Double.parseDouble(value.toString());
}

private boolean checkParity() {
    return (dht11_dat[4] == ((dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3]) & 0xFF));
}

}

我從原始海報的java代碼開始,用com.pi4j.wiringpi包替換了com.pi4j.io.gpio包引用。 我最近在我的Raspberry Pi上安裝了最新的pi4j包和wirespi版本。

使用該包,下面的Java代碼與該程序的c版本大致相同。 使用DHT-11,我得到了大約80% - 85%的准確答案。 這與我在c中使用wiringPi的情況大致相同。

package gpio;
import com.pi4j.wiringpi.Gpio;
import com.pi4j.wiringpi.GpioUtil;

public class DHT11 {
    private static final int    MAXTIMINGS  = 85;
    private final int[]         dht11_dat   = { 0, 0, 0, 0, 0 };

    public DHT11() {

        // setup wiringPi
        if (Gpio.wiringPiSetup() == -1) {
            System.out.println(" ==>> GPIO SETUP FAILED");
            return;
        }

        GpioUtil.export(3, GpioUtil.DIRECTION_OUT);
    }

    public void getTemperature(final int pin) {
        int laststate = Gpio.HIGH;
        int j = 0;
        dht11_dat[0] = dht11_dat[1] = dht11_dat[2] = dht11_dat[3] = dht11_dat[4] = 0;

        Gpio.pinMode(pin, Gpio.OUTPUT);
        Gpio.digitalWrite(pin, Gpio.LOW);
        Gpio.delay(18);

        Gpio.digitalWrite(pin, Gpio.HIGH);
        Gpio.pinMode(pin, Gpio.INPUT);

        for (int i = 0; i < MAXTIMINGS; i++) {
            int counter = 0;
            while (Gpio.digitalRead(pin) == laststate) {
                counter++;
                Gpio.delayMicroseconds(1);
                if (counter == 255) {
                    break;
                }
            }

            laststate = Gpio.digitalRead(pin);

            if (counter == 255) {
                break;
            }

            /* ignore first 3 transitions */
            if (i >= 4 && i % 2 == 0) {
                /* shove each bit into the storage bytes */
                dht11_dat[j / 8] <<= 1;
                if (counter > 16) {
                    dht11_dat[j / 8] |= 1;
                }
                j++;
            }
        }
        // check we read 40 bits (8bit x 5 ) + verify checksum in the last
        // byte
        if (j >= 40 && checkParity()) {
            float h = (float) ((dht11_dat[0] << 8) + dht11_dat[1]) / 10;
            if (h > 100) {
                h = dht11_dat[0]; // for DHT11
            }
            float c = (float) (((dht11_dat[2] & 0x7F) << 8) + dht11_dat[3]) / 10;
            if (c > 125) {
                c = dht11_dat[2]; // for DHT11
            }
            if ((dht11_dat[2] & 0x80) != 0) {
                c = -c;
            }
            final float f = c * 1.8f + 32;
            System.out.println("Humidity = " + h + " Temperature = " + c + "(" + f + "f)");
        } else {
            System.out.println("Data not good, skip");
        }

    }

    private boolean checkParity() {
        return dht11_dat[4] == (dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3] & 0xFF);
    }

    public static void main(final String ars[]) throws Exception {

        final DHT11 dht = new DHT11();

        for (int i = 0; i < 10; i++) {
            Thread.sleep(2000);
            dht.getTemperature(21);
        }

        System.out.println("Done!!");

    }
}

我有同樣的問題,不幸的是,我已經讀過Java無法以這種方式從DHT11 / 22讀取數據以解決時序問題。

我在Raspberry論壇上發現了一個線程,你可以在其中找到一些使用SPI或pigpio的解決方案。 另一個完整的Java可能解決方案就在那

我昨天收到了傳感器,我還沒有嘗試過這個解決方案。 當我試試的時候,我會告訴你的。

[編輯]

嗨,我已經解決了調用python腳本(使用Adafruit驅動程序 )並讀取它的輸出的問題。 python腳本只是Adafruit庫中發布的示例。 我只更改了第48行的輸出

print '{0:0.1f}   {1:0.1f}'.format(temperature, humidity)

使用新值更新值的Java方法是:

public void update() {
    String cmd = "sudo python DHTReader.py 11 4";
    try {
        String ret = "";
        try {
            String line;
            Process p = Runtime.getRuntime().exec(cmd.split(" "));
            p.waitFor();
            BufferedReader input = new BufferedReader
                    (new InputStreamReader(p.getInputStream()));
            while ((line = input.readLine()) != null) {
                output += (line + '\n');
            }
            input.close();
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
        ret.trim();
        if (ret.length() == 0) // Library is not present
            throw new RuntimeException(LIB_NOT_PRESENT_MESSAGE);
        else{
            // Error reading the the sensor, maybe is not connected. 
            if(ret.contains(ERROR_READING)){
                String msg = String.format(ERROR_READING_MSG,toString());
                throw new Exception(msg);
            }
            else{
                // Read completed. Parse and update the values
                String[] vals = ret.split("   ");
                float t = Float.parseFloat(vals[0].trim());
                float h = Float.parseFloat(vals[1].trim());
                if( (t != lastTemp) || (h != lastHum) ){
                    lastUpdate = new Date();
                    lastTemp = t;
                    lastHum = h;
                }
            }
        }
    } catch (Exception e) {
        System.out.println(e.getMessage());
        if( e instanceof RuntimeException)
            System.exit(-1);
    }
}

要使其工作,您必須按照鏈接頁面中的描述安裝Adafruit庫,並使用scipt的路徑更改DHTReader.py。 我正在努力建立一個“圖書館”。 如果你需要,當我完成后,我會在GitHub上發布它。

如果你總是處於高狀態,那么仔細檢查接線是否正確(或者如果任何導線斷開,用導線進行測試)可能是好的。

我在C和python中使用過adafruit的教程 ,它在我的DHT22上工作。

我得到了Java Native Interface JNI和WiringPi的解決方案。

我在raspberry pi中使用java openjdk 7。 這對於支持JVM的JVM功能非常重要。 我將DHT11傳感器連接到GPIO1或引腳1。

從src / main / java的包根目錄,您可以安裝庫。 我准備了一個腳本,您可以使用以下命令運行:

sudo sh jniDHT11SensorReaderBuilder.sh

然后測試它是否有效嘗試使用該命令運行DHT11SensorReader

sudo java org.mandfer.dht11.DHT11SensorReader

如果一切正常並且您希望每1.5秒獲得更多值,請嘗試從項目根文件夾運行練習20

sh runPi.sh org.mandfer.sunfunpi4j.Ex20_DHT11_Native

如果您有任何問題,請給我留言。

我希望它有所幫助。 Marc Andreu,

Eric Smith的優秀代碼適合我使用兩個小mod,首先我編輯了這一行:

if (counter > 16)

至:

if (counter > 30)

根據dht11的規格,當“Gpio.HIGH”的延遲大約為70us時發送“1”位,如果延遲為26-28us則發送“0”位。 很明顯,Java需要一些時間來執行,因此可以安全地假設如果延遲超過30us,則數據必須為“1”。 但是如果你的機器中Java程序的執行時間不同(這可能是pi的處理器更快/更慢,有更多的后台程序等),這可能是不同的值。 因此,30對於每種情況都不一定是正確的價值。

根據規范1 ,還可以注意到發送者(raspberry pi,在規范中稱為MCU),也應該發送Gpio.HIGH至少18ms。 之后,MCU應發送20-40 us“Gpio.HIGH”。 我使用System.nanoTime()測試了Java執行將Gpio.Pinmode設置為“Input”所需的時間。 它需要20us,所以我補充說:

Gpio.delayMicroseconds(7);

...只是為了確保引腳為高電平至少20us,以便傳感器可以注冊該信號並開始發送其溫度和濕度數據。 在這些變化之后,溫度數據幾乎總是正確讀取,成功率大約為90%。 我不確定修改是否可以與其他系統一起使用,但希望這些修改可以使其他實驗更成功!

(ps我也創建了永久循環,以便在調用方法時反復創建類。)

我發現裝有Raspian的RPi3b太慢了,無法使用此處顯示的代碼示例。 可能與java> pi4j> wirespi傳播延遲有關。 我的方法如下; 在發送激活傳感器的命令后,我讀取所需引腳上的時間級別更改並將值保存到數組中。 然后解析將在稍后完成。 我使用此代碼獲得95%的成功率。 我讓它在帶有循環的Runnable類中運行,因此它有自己的線程。 如果您發現時間不正確,請嘗試調整計數器偏移量。 同時啟用標記為調試的println,它有助於指示未接收到哪些位(由0表示)。

public void scopeSensor(int pin){

    int x = 0;
    int lastState = 1;
    int valueRead = 1;
    int counter = 0; 
    int limit = 84;
    int timeout = 0;
    int[] results = new int[limit];    
    int[] pinState = new int[limit]; 


    //set pin low for 18ms to request data        
    Gpio.pinMode(pin, Gpio.OUTPUT);
    Gpio.digitalWrite(pin, Gpio.LOW);
    Gpio.delay(18);        

    //get ready to recieve data back from dht11
    Gpio.pinMode(pin, Gpio.INPUT);
    Gpio.pullUpDnControl(pin, Gpio.PUD_UP); //activate internal pullup



    while (x < limit) //84 sample changes to cover DHT11
    {           
        timeout = 0;
        counter = 2; //offset for time taken to perform read by pi
        while (valueRead == lastState && timeout < 300){
             Gpio.delayMicroseconds(1); 
            valueRead = Gpio.digitalRead(pin);

                    counter++;  
                    timeout++;
        }         

        if (timeout < 300)
        {
        results[x] = counter;
        pinState[x] = lastState;
        lastState = valueRead;
        }

        x++;
    }

    //reset our bytes
    dht11_dat[0] = dht11_dat[1] =dht11_dat[2]=dht11_dat[3]=dht11_dat[4]=0;
    int pointer = 0;
    for (int i = 4; i<x; i=i+2){
        //shift left so we are ready for next result

            pointer = ((i-4) / 2) / 8;

            dht11_dat[pointer] = dht11_dat[pointer] <<= 1;

            //if more than 30, mark bit as 1
        if (results[i] > 30){
            dht11_dat[pointer] = dht11_dat[pointer] |= 1;
        }        

    //for debugging only
       // System.out.println(Integer.toString(pinState[i]) + "," + Integer.toString(results[i]));           

    }

    int checksumByte = ((dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3]) & 0xff);
    if (dht11_dat[4]  != checksumByte){
        System.out.println("Warning: Bad checksum value!");
    }


        System.out.println("                                                                    Temp: " +  Integer.toString((dht11_dat[2])) + "  RH: " +  Integer.toString((dht11_dat[0])));

         WriteToFile.writeTextToFile("RH-T.csv", Integer.toString((dht11_dat[0])) + "," + Integer.toString((dht11_dat[2])));
}

運行方法:

@Override
public void run() {
    ReadTempRH dht = new ReadTempRH();

    while (NbSerialApp.runThreads){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException ex) {
            Logger.getLogger(ReadTempRH.class.getName()).log(Level.SEVERE, null, ex);
        }
        //getTempRH(7);
        scopeSensor(7);
    }
}

ReadTempRH構造函數:

private final int[] dht11_dat = {0,0,0,0,0};

public ReadTempRH() {

    //setup wiringPi
    if (Gpio.wiringPiSetup() == -1){
        System.out.println("GPIO setup failed!");
        return;            
    }

    GpioUtil.export(3, GpioUtil.DIRECTION_OUT);
    System.out.println("GPIO setup complete!");

}

對不起我的代碼有點亂,我沒有時間整理東西! 但你應該明白這個想法。 我通常是ac#guy,而Netbeans在整理前端不像VS那樣工作!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM