Intel Galileo驱动单总线设备(DHT11\DHT22)-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9323|回复: 5

Intel Galileo驱动单总线设备(DHT11\DHT22)

[复制链接]
发表于 2014-12-3 16:55 | 显示全部楼层 |阅读模式
Intel Galileo一代的IO翻转速度不够,无法直接驱动单总线设备,二代听说改进了,但没有库,于是国外开发者想出了另一种法子,转过来给大家学习下。如果后面有时间,再来翻译。
原文地址:http://bigdinotech.com/tutorials/galileo-tutorials/using-1-wire-device-with-intel-galileo/

Many people have had trouble with getting 1-Wire devices to work with the Galileo and Galileo Gen2 boards.

The main reason is that the Galileo and Galileo Gen2 uses IO expanders for many of  its GPIOs. Even with the pins Arduno header pins that have native SoC IO speeds, it is not possible because the GPIOs that control the muxing of those pins uses pins from the IO expanders.

galMux.png
Galileo Muxing For Pin2

galcyp.png
Galileo Cypress IO Expander



If we look at the two images taken form the Galileo schematic, IO which is connected to the Arduino Digital 2 pin, is controlled by a mux pin IO2_MUX. This pin is then connected to the Cypress IO expander.

The end result is there is significant latency when switching pin direction using pinMode() becuase it requires I2C transactions with the IO expanders.



I will show a way to use 1-Wire device with the Galileo and Galileo Gen2 boards.

The trick is to use 2 pins instead of 1. For the Galileo, pins 2 and 3 must be used since they are the only pins fast enough to achieve this. For the Galileo Gen2, any pins except pins 7 and 8 can be used.

For this tutorial, I will use a DHT11 sensor which a very cheap and popular 1-Wire humidity and temperature sensor.



The Proper Way

The proper way of doing this is to use a tri-state buffer.

This works because, when pin 3 is pulled HIGH, the tri-state buffer prevents the HIGH signal from being passed to the other side. However, the 1-Wire device still sees a high signal because of the pull-up resistor.
When pin 3 is pulled LOW, the signal passes through the tri-state buffer and a LOW signal is detected by the 1-Wire device.

The Easy Way

For the easy way the only extra hardware needed is a diode such as the 1N4148 signal diode. This essential works the same way as the tri-state buffer method where only a LOW signal passes through because current only passes in one direction through a diode.
DHTGal.png


Since we are now using two pins, we will also need to make changes in the libraries used. As an example, I modified the DHT-11 library from Adafruit.
[mw_shl_code=cpp,true]#ifndef DHT_H
#define DHT_H
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

/* DHT library

MIT license
written by Adafruit Industries

Modified by Dino Tinitigan (dino.tinitigan@intel.com to work on Intel Galileo boards
*/

// how many timing transitions we need to keep track of. 2 * number bits + extra
#define MAXTIMINGS 85

#define DHT11 11
#define DHT22 22
#define DHT21 21
#define AM2301 21

class DHT {
private:
uint8_t data[6];
uint8_t _inpin, _outpin, _type, _count;
unsigned long _lastreadtime;
boolean firstreading;
int pulseLength(int pin);
void delayMicrosGal(unsigned long usec);
int bitsToByte(int bits[]);

public:
DHT(uint8_t inPin, uint8_t outPin,uint8_t type, uint8_t count=6);
void begin(void);
float readTemperature(bool S=false);
float convertCtoF(float);
float computeHeatIndex(float tempFahrenheit, float percentHumidity);
float readHumidity(void);
boolean read(void);


};
#endif[/mw_shl_code]

[mw_shl_code=cpp,true]/* DHT library

MIT license
written by Adafruit Industries

Modified by Dino Tinitigan (dino.tinitigan@intel.com to work on Intel Galileo boards
*/


#include "DHT.h"

DHT:HT(uint8_t inPin, uint8_t outPin, uint8_t type, uint8_t count) {
_inpin = inPin;
_outpin = outPin;
_type = type;
_count = count;
firstreading = true;
}

void DHT::begin(void) {
// set up the pins!
pinMode(_inpin, INPUT);
pinMode(_outpin, INPUT);
digitalWrite(_outpin, HIGH);
_lastreadtime = 0;
}

//boolean S == Scale. True == Farenheit; False == Celcius
float DHT::readTemperature(bool S) {
float f;

if (read()) {
switch (_type) {
case DHT11:
f = data[2];
if(S)
f = convertCtoF(f);

return f;
case DHT22:
case DHT21:
f = data[2] & 0x7F;
f *= 256;
f += data[3];
f /= 10;
if (data[2] & 0x80)
f *= -1;
if(S)
f = convertCtoF(f);

return f;
}
}
return NAN;
}

float DHT::convertCtoF(float c) {
return c * 9 / 5 + 32;
}

float DHT::readHumidity(void) {
float f;
if (read()) {
switch (_type) {
case DHT11:
f = data[0];
return f;
case DHT22:
case DHT21:
f = data[0];
f *= 256;
f += data[1];
f /= 10;
return f;
}
}
return NAN;
}

float DHT::computeHeatIndex(float tempFahrenheit, float percentHumidity) {
// Adapted from equation at: https://github.com/adafruit/DHT-sensor-library/issues/9 and
// Wikipedia: http://en.wikipedia.org/wiki/Heat_index
return -42.379 +
2.04901523 * tempFahrenheit +
10.14333127 * percentHumidity +
-0.22475541 * tempFahrenheit*percentHumidity +
-0.00683783 * pow(tempFahrenheit, 2) +
-0.05481717 * pow(percentHumidity, 2) +
0.00122874 * pow(tempFahrenheit, 2) * percentHumidity +
0.00085282 * tempFahrenheit*pow(percentHumidity, 2) +
-0.00000199 * pow(tempFahrenheit, 2) * pow(percentHumidity, 2);
}


boolean DHT::read(void) {
uint8_t laststate = HIGH;
uint8_t counter = 0;
uint8_t j = 0, i;
unsigned long currenttime;

int bitContainer[8];

// Check if sensor was read less than two seconds ago and return early
// to use last reading.
currenttime = millis();
if (currenttime < _lastreadtime) {
// ie there was a rollover
_lastreadtime = 0;
}
if (!firstreading && ((currenttime - _lastreadtime) < 2000)) {
return true; // return last correct measurement
//delay(2000 - (currenttime - _lastreadtime));
}
firstreading = false;
/*
Serial.print("Currtime: "); Serial.print(currenttime);
Serial.print(" Lasttime: "); Serial.print(_lastreadtime);
*/
_lastreadtime = millis();

data[0] = data[1] = data[2] = data[3] = data[4] = 0;

// pull the pin high and wait 250 milliseconds
pinMode(_outpin, OUTPUT_FAST);
pinMode(_inpin, INPUT_FAST);
digitalWrite(_outpin, HIGH);
delay(250);

// now pull it low for ~20 milliseconds
noInterrupts();
digitalWrite(_outpin, LOW);
delay(20);
digitalWrite(_outpin, HIGH);
delayMicrosGal(40);

//read the 40 bits
delayMicrosGal(160);
for(int bytes = 0; bytes < 5; bytes++)
{
for(int i = 0; i < 8; i++)
{
int pulse = pulseLength(_inpin);
if(pulse > 30)
{
bitContainer = 1;
}
else
{
bitContainer = 0;
}
}
data[bytes] = bitsToByte(bitContainer);
}

interrupts();


//Serial.println(j, DEC);
/**
Serial.print(data[0], HEX); Serial.print(", ");
Serial.print(data[1], HEX); Serial.print(", ");
Serial.print(data[2], HEX); Serial.print(", ");
Serial.print(data[3], HEX); Serial.print(", ");
Serial.print(data[4], HEX); Serial.print(" =? ");
Serial.println(data[0] + data[1] + data[2] + data[3], HEX);
**/
/**
Serial.println(data[0]);
Serial.println(data[1]);
Serial.println(data[2]);
Serial.println(data[3]);
Serial.println(data[4]);
**/
// check we read 40 bits and that the checksum matches

if((data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)))
{
return true;
}


return false;

}

void DHT::delayMicrosGal(unsigned long usec)
{
unsigned long a = micros();
unsigned long b = a;
while((b-a) < usec)
{
b = micros();
}
}

int DHT::pulseLength(int pin)
{
unsigned long a = micros();
unsigned long b = a;
unsigned long c = a;
int timeout = 150;
int fastPin = 0;
int highValue = 0;

if(PLATFORM_NAME == "GalileoGen2")
{
switch(pin)
{
case 0:
fastPin = GPIO_FAST_ID_QUARK_SC(0x08);
highValue = 0x08;
break;
case 1:
fastPin = GPIO_FAST_ID_QUARK_SC(0x10);
highValue = 0x10;
break;
case 2:
fastPin = GPIO_FAST_ID_QUARK_SC(0x20);
highValue = 0x20;
break;
case 3:
fastPin = GPIO_FAST_ID_QUARK_SC(0x40);
highValue = 0x40;
break;
case 4:
fastPin = GPIO_FAST_ID_QUARK_NC_RW(0x10);
highValue = 0x10;
break;
case 5:
fastPin = GPIO_FAST_ID_QUARK_NC_CW(0x01);
highValue = 0x01;
break;
case 6:
fastPin = GPIO_FAST_ID_QUARK_NC_CW(0x02);
highValue = 0x02;
break;
case 9:
fastPin = GPIO_FAST_ID_QUARK_NC_RW(0x04);
highValue = 0x04;
break;
case 10:
fastPin = GPIO_FAST_ID_QUARK_SC(0x04);
highValue = 0x04;
break;
case 11:
fastPin = GPIO_FAST_ID_QUARK_NC_RW(0x08);
highValue = 0x08;
break;
case 12:
fastPin = GPIO_FAST_ID_QUARK_SC(0x80);
highValue = 0x80;
break;
case 13:
fastPin = GPIO_FAST_ID_QUARK_NC_RW(0x20);
highValue = 0x20;
break;
default:
highValue = 1;
break;
}
}
else
{
switch(_inpin)
{
case 2:
fastPin = GPIO_FAST_ID_QUARK_SC(0x40);
highValue = 0x40;
break;
case 3:
fastPin = GPIO_FAST_ID_QUARK_SC(0x80);
highValue = 0x80;
break;
default:
highValue = 1;
break;
}
}
a = micros();
while(fastGpioDigitalRead(fastPin) == 0)
{
b= micros();
if((b - a) >= timeout)
{
break;
}
}
a = micros();
while(fastGpioDigitalRead(fastPin) == highValue)
{
b= micros();
if((b - a) >= timeout)
{
break;
}
}
return (b - a);
return 0;
}


int DHT::bitsToByte(int bits[])
{
int data = 0;
for(int i = 0; i < 8; i++)
{
if (bits)
{
data |= (int)(1 << (7 - i));
}
}
return data;
}[/mw_shl_code]

[mw_shl_code=cpp,true]// Example testing sketch for various DHT humidity/temperature sensors
// Written by ladyada, public domain

#include "DHT.h"

#define DHTIN 2 // what pin we're connected to
#define DHTOUT 3

// Uncomment whatever type you're using!
#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)

// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

DHT dht(DHTIN,DHTOUT, DHTTYPE);

void setup() {
Serial.begin(9600);
Serial.println("DHTxx test!");

dht.begin();
}

void loop() {
// Wait a few seconds between measurements.
delay(2000);

// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius
float t = dht.readTemperature();
// Read temperature as Fahrenheit
float f = dht.readTemperature(true);

// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println("Failed to read from DHT sensor!");
return;
}

// Compute heat index
// Must send in temp in Fahrenheit!
float hi = dht.computeHeatIndex(f, h);

Serial.print("Humidity: ");
Serial.print(h);
Serial.print(" %\t");
Serial.print("Temperature: ");
Serial.print(t);
Serial.print(" *C ");
Serial.print(f);
Serial.print(" *F\t");
Serial.print("Heat index: ");
Serial.print(hi);
Serial.println(" *F");
}[/mw_shl_code]

DHTGalSerial.png
发表于 2014-12-3 21:36 | 显示全部楼层
好巧啊,我刚想转这篇文档过来,今天下午和Sean刚好试了这个功能,确实可以实现。从原理图上看也看到这两个口可以直接连接到Quark的GPIO INT0/1上面,不过想问个问题,是不是只能作为输入了。 QQ截图20141203213420.jpg

点评

我给他说了这个文章,顺便我就转过来了,不过我无法理解,为啥ide要自带一个无法使用的oneWire库  详情 回复 发表于 2014-12-3 22:44
 楼主| 发表于 2014-12-3 22:44 | 显示全部楼层
luooove 发表于 2014-12-3 21:36
好巧啊,我刚想转这篇文档过来,今天下午和Sean刚好试了这个功能,确实可以实现。从原理图上看也看到这两个 ...

我给他说了这个文章,顺便我就转过来了,不过我无法理解,为啥ide要自带一个无法使用的oneWire库
发表于 2015-1-26 23:57 | 显示全部楼层
如果我买的是DHT22模块,他只有三根引脚线出来啊,两根电源线和一根数据线,这个应该怎么做呢?求大神回复。。。
发表于 2015-7-14 19:51 | 显示全部楼层
小手冰凉 发表于 2015-1-26 23:57
如果我买的是DHT22模块,他只有三根引脚线出来啊,两根电源线和一根数据线,这个应该怎么做呢?求大神回复 ...

本來就只需要三根阿...上面有接腳圖可以看他是將一根訊號線分接到兩個GPIO,這樣可以彌補GPIO轉態的延遲。

发表于 2015-10-21 14:43 | 显示全部楼层
小手冰凉 发表于 2015-1-26 23:57
如果我买的是DHT22模块,他只有三根引脚线出来啊,两根电源线和一根数据线,这个应该怎么做呢?求大神回复 ...

有控制DHT22的程序吗?能给我发一份吗?576370952@qq.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-9-21 13:31 , Processed in 0.099359 second(s), 27 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表