使用pi4j从DHT11读取温度

我正在尝试使用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 = 4) && (i % 2 == 0)) { /* shove each bit into the storage bytes */ dht11_dat[j / 8] < 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包和接线版。

使用该包,下面的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!!"); } } 

如果你总是处于高状态,那么仔细检查接线是否正确(或者如果任何导线断裂,用导线进行测试)可能是好的。

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

我有同样的问题,不幸的是,我已经读过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上发布它。

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

我在raspberry pi中使用java openjdk 7。 这对于支持JVM的JVMfunction非常重要。 我将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

如果您有任何问题,请给我留言。

我希望它有所帮助。 马克安德鲁,

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我也创建了永久循环,以便在调用方法时反复创建类。)