arduino_temp

The LM35 sensor operates within the widest temperature range (-55…+150°C) and is more precise compared to its two competitors. Nevertheless, it is not the possible measurement error that is critical to most IoT solutions—it is the maximum amperage and the output voltage. As you can see, the LM35 can be powered by sources of between 4 V and 30 V; the TMP36 requires sources of between 2.7 V and 5.5 V; and the DHT11 requires sources of between 3 V and 55 V. Thus, the first sensor is not compatible with some Photon chips, as the acceptable voltage for them is 3.3 V. So, the TMP36 is perfect for integrating into solutions that require working with temperatures below 0°C because you won’t be able to connect the LM35 to analogue contacts on Arduino chips. If you need maximum accuracy for Arduino based solutions that will be used indoors, the LM35 is your best option. If you need the additional feature of determining humidity levels, the DHT11 represents the best price-quality ratio.

DHT11 Connections:

Vin : 3V3 On Board

GND : Gnd

Out :D4 On Board

LM35 Connections :

Vcc : 3V3 on Board

Out: A0 on Board

GND :Ground

วันนี้จะมานำเสนอการใช้งาน Module เล็กๆ สีฟ้า DHT11 (DHT11 Humitdity and Temperature Sensor กับบอร์ด Ardiono)ที่ใช้ในการวัดอุณหภูมิกับความชื่นในอากาศกันกครับ

ก่อนอื่นมาดู Specification ของ DHT11 กันนะครับว่ามันทำอะไรได้บ้าง

  • ย่านวัดความชื่น 20-90% RH โดยมีค่าความแม่นยำ +- 5% RH ความละเอียดในการวัด 1 % แสดงผลแบบ 8 บิต

  • ย่านวัดอุณหภูมิ 0 -50 องศาเซลเซียส โดยมีค่าความแม่นยำ +- 2 องศาเซลเซียส ความละเอียดในการวัด 1 องศาเซลเซียส แสดงผลแบบ 8 บิต

  • มิ PIN 4 ขารายละเอียดดังรูปด้านบน

  • กินกระแส 0.5 - 2.5 mA (ขณะทำการวัดค่า) ที่ระดับแรงดัน 3 - 5.5 VDC

  • อ่านค่าสัญญาณ (Sample Rate) ทุก 1 วินาที

รายละเอียดของ Spec อื่นๆ นอกเหนือจากนี้ดูในที่ Manual นะครับ

จริงๆแล้ว Sensor วัด อุณหภูมิ กับ ความชื้นใน Series นี้มีออกมาหลายรุ่นครับ เช่น DHT11 DHT 22 DHT21 บางทีมาแต่ตัว sensor บางทีมาเป็น module ความแตกต่างก็คือความแม่นยำในการวัดค่าของ sensor ครับ

ทีนี้มาดูวิธีการต่อใช้งานครับ

ในการการต่อวัดแบบปกติ คือ ระยะห่างระหว่าง Sensor กับตัว Arduino ห่างกันไม่เกิน 20 เมตร จะต้องใช้ Pull up resistor ขนาด 5kohm (ว่าง่ายๆ คือต่อ R 5k ไว้กับแหล่งจ่ายแรงดันและต่อเข้าไปที่ขา DATA ด้วย)

Pin 1 ต่อกับ VDD

Pin 2 ต่อเป็นขา DATA

Pin 3 ไม่ได้ใช้

Pin 4 ลงกราวด์

โดยใช้แหล่งจ่ายแรงดัน VDD ขนาด 3-5.5 VDC ครับ ซึ่งข้อดีคือจะทำให้ DHT11 นี้สามารถใช้งานได้กับ Arduino หลายรุ่น ทั้งรุ่นที่มีแรงดัน 3.3 VDC อย่าง Arduino Dueหรือรุ่นยอดฮิตอย่าง UNO และ Mega/Mega ADK ครับ

ทีนี้มาถึงวิธีการส่งข้อมูลของ DHT11กันครับ อุปกรณ์ตัวนี้ใช้การสื่อสารกับ MCU ของเราด้วยวิธี Single-wire Two-way Serial interface ถ้าจะให้แปลเป็นภาษาไทยก็ คือ การสื่อสารอนุกรุมสองทางโดยใช้สายเส้นเดียว เอางี้ครับ แปลให้อีกที การสื่อสารแบบนี้จะใช้สายสื่อสารเพียงเส้นเดียวและส่งข้อมูลได้ทั้งจาก MCU ไปที่ตัว DHT11 และในทางกลับกันก็ได้ครับ

ตกลงกันก่อนนะครับ ต่อไปนี้ผมจะเรียก Arduino ของเราไม่ว่าจะเป็น UNO, Mega, หรือ รุ่นใดๆ ก็แล้วแต่ว่า Master และ DHT11ว่า Slave นะครับ อีกนิดนึงเกี่ยวกับ Pull up resistor นะครับ การใช้ pull up resistor นั้นหมายถึงเราต้องการให้เวลาทำงานปกติในขณะที่ไม่มีอุปกรณ์ทีต่ออยุ๋กับสายสื่อสารของเรา ระดับแรงดันของสัญญาณในสาย Data คึอแรงดันระดับ "สูง" และจะมีแรงดันในระดับต่ำเมื่อมีอุปกรณ์ (จะเป็น Master หรือ Slave ก็ได้) ดึงสัญญาณลงในระดับ "ต่ำ" นะครับ ดังนั้นหากเรามี Scope วัดระดับสัญญาณได้เป็น "สูง" ตลอดเวลา ก็หมายความว่าอุปกรณ์ของเราอาจจะผิดปกตินะครับ

ในการสื่อสารโดยใช้สายเส้นเดียวนั้น จำเป็นต้องใช้โปรโตคอลที่ตกลงกันไว้ระหว่างตัว MCU และ อุปกรณ์ที่ต้องการสื่อสารด้วย (Slave) งั้นมาเริ่มพูดถึงโปรโตคอลที่ว่าเลยดีกว่างครับ อันดับแรก Master หรือ Arduino ของเราจะส่ง Start signal ที่เป็นแรงดันไฟฟ้าระดับต่ำอย่างน้อย 18 ไมโครวินาที ไปที่ Slave เพื่อให้ Slave เข้าใจว่าจะเริ่มสั่งแล้วนะ แล้วรอไป 20-40 ไมโครวินาทีเพื่อรอ Slave ตอบกลับ

ทีนี้เพื่อให้ Master รู้ว่า Slave ก็พร้อม Slave จะส่งแรงดันระดับต่ำกลับไปบ้าง การส่งแรงดันจาก Slave กลับไปจะนาน 80 ไมโครวินาที จากนั้นจะรออีก 80 ไมโครวินาที ก่อนที่จะส่งข้อมูลบิตแรก มาถึงตรงนี้ข้อมูลยังไม่ถูกส่งเลยนะครับ แต่พร้อมจะส่งแล้ว

คราวนี้เรามาดูครับว่าจะส่งบิต "0" กับ บิต "1" อย่างไร สำหรับการส่งบิตเป็น "0" ตัว Slave จะดึงระดับแรงดันลงต่ำนาน 50 ไมโครวินาที และปล่อยเป็นระดับ "สูง" นาน 26-28 ไมโครวินาที ดังรูปด้านด้านบนครับ (ดูช่วง Sending 0)

แต่ถ้าเป็นการส่งข้อมูลเป็น "1" ตัวส่งจะดึงสายสัญญาญลงระดับต่ำ 50 ไมโครวินาที และปล่อยให้เป็นระดับสูงนาน 70 ไมโครวินาที (ดูช่วง Sending 1) เอาละครับ ทีนี้รู้ว่าแต่ละบิต DH11 ส่งมาเป็นบิต "0" หรือ "1" มา และส่งมาจนครบข้อมูลหนึ่งชุดครับ

ในแต่ละชุดของข้อมูลที่ส่งมาจาก DH11ตัว MCU รับข้อมูลแล้วจะต้องเอามาแปลงต่อนะครับ ว่าข้อมูลที่ส่งมามันแปลว่าอะไร แต่ละชุดข้อมูลจะยาว 40 บิต และใช้เวลาส่งประมาณ 40 มิลลิวินาทีครับ

ใน 40 บิตที่ส่งมา ประกอบด้วย " 8bit integral RH data + 8bit decimal RH data + 8bit integral T data + 8bit decimal T data + 8bit check sum" นะครับ ฟังดูอาจจะยุ่งยากกว่าจะมาตีความหมายได้ แต่ไม่ต้องห่วงครับ มีคนเขียน library ไว้ใช้งานกับ Arduino board ให้เรียบร้อยครับ แค่เอา library มาใส่ให้ถูกแล้วเรียกใช้แค่นั้นครับ แต่คนที่ต้องการเอาไปใช้กับอุปกรณ์อื่นๆ เช่น อ่านค่าเข้า FPGA ก็ขอให้ดูรายละเอียดใน manual นะครับ ในที่นี้ขอข้ามไปก่อน ไม่งั้นคุยกันอีกนาน

สำหรับ library ของ DHT11 ก็มา ทางนี้ ครับ ถ้าไม่ทราบวิธีการติดตั้ง Library ก็ ทางนี้ ครับ

อย่าลืมนะครับ DHT มันออกมาหลายรุ่น library ก็เขียนมาให้ใชได้หลายรุ่น แต่ค่าพารามิเตอร์ในการวัดค่ามันต่างกัน อย่าลืมเลือกรุ่นให้ถูกใน sketch ที่เขียนนะครับ ไม่งั้นอ่านมั่วน่าดู

// Example testing sketch for various DHT humidity/temperature sensors

// Written by ladyada, public domain

#include "DHT.h"

#define DHTPIN 2 // what pin we're connected to

// 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(DHTPIN, DHTTYPE);

void setup() {

Serial.begin(9600);

Serial.println("DHTxx test!");

dht.begin();

}

void loop() {

// 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();

float t = dht.readTemperature();

// check if returns are valid, if they are NaN (not a number) then something went wrong!

if (isnan(t) || isnan(h)) {

Serial.println("Failed to read from DHT");

} else {

Serial.print("Humidity: ");

Serial.print(h);

Serial.print(" %\t");

Serial.print("Temperature: ");

Serial.print(t);

Serial.println(" *C");

}

}

ถ้าต่อทุกอย่างไม่พลาด ก็จะเปิด serial monotor เจอกับหน้าแบบนี้ครับ ตอนอ่านค่านี้ผมเอา DH11 ไปไว้บน Adapter ของโน๊ตบุ๊คครับ เลยอ่านมาได้ค่าที่ดูแล้วร้อนหน่อย ผมไม่ได้นั่วอยู่กลางแดดนะครับ :-)

เอาละครับ เมื่อผ่านตัวอย่างด้านบนมาแล้วแสดงว่า DHT11 ของเราใช้งานได้ปกติ ทีนี้มาลองเอาข้อมูลที่ได้ใส่ไว้ใน SD cardเป็น Temperature and Humidity + Data Logger กัน

เริ่มจากผมไปดูตัวอย่างการใช้งาน SD card moduleทีได้เขียนไปแล้วในบทความก่อนหน้าของ Arduitronics นะครับ จากนั้นเราก็เอาสองตัวอย่างที่ว่ามาปนกันซะเลย

ตัวอย่าง sketch นี้ก็ตามนี้นะครับ

// Example testing sketch for various

// DHT humidity/temperature sensors + SD Card Module

// Written by www.Arduitronics.com

// This sketch is uploaded to Arduino MEGA ADK.

// USING OTHER BOARD REQUIRED SOME MODIFICATION

#include "DHT.h"

#include

#include "floatToString.h"

#define DHTPIN 2 // what pin we're connected to

const int chipSelect = 53; // ตัวเลข 53นี้สำหรับ Arduino MEGA และ MEGA ADK นะครับ

4; //

// 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

char test[20];

DHT dht(DHTPIN, DHTTYPE);

void setup() {

Serial.begin(9600);

Serial.println("DHT11 test!");

// Open serial communications and wait for port to open:

Serial.begin(9600);

delay(200);

while (!Serial) {

; // wait for serial port to connect. Needed for Leonardo only

}

Serial.print("Initializing SD card...");

// make sure that the default chip select pin is set to

// output, even if you don't use it:

pinMode(10, OUTPUT);

// see if the card is present and can be initialized:

if (!SD.begin(chipSelect)) {

Serial.println("Card failed, or not present");

// don't do anything more:

return;

}

Serial.println("card initialized.");

dht.begin();

}

void loop() {

// make a string for assembling the data to log:

String dataString = "";

// 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();

float t = dht.readTemperature();

Serial.print("Time: ");

dataString += String(millis());

dataString += " ms";

dataString += " Humidity:";

dataString += floatToString(test,h,0,4,true);

dataString += " %RH ";

dataString += "Temperature: ";

dataString += floatToString(test,t,0,4,true);

dataString += "*C";

// open the file. note that only one file can be open at a time,

// so you have to close this one before opening another.

File dataFile = SD.open("datalog.txt", FILE_WRITE);

// if the file is available, write to it:

if (dataFile) {

dataFile.println(dataString);

dataFile.close();

}

// if the file isn't open, pop up an error:

else {

Serial.println("error opening datalog.txt");

}

// check if returns are valid, if they are NaN (not a number) then something went wrong!

if (isnan(t) || isnan(h)) {

Serial.println("Failed to read from DHT");

} else {

// Serial.print("Humidity: ");

// Serial.print(h);

// Serial.print(" %\t");

// Serial.print("Temperature: ");

// Serial.print(t);

// Serial.println(" *C");

// print to the serial port too:

Serial.println(dataString);

}

}

ก่อนจะ Verify sketch ตัวนี้ยังมีขั้นตอนอีกนิดครับ เราต้องการใช้ method ที่แปลงค่า floating เป็น String ซะด้วย ไม่งั้นจะเขียนบน SD card ไม่ได้ครับ

ให้เพิม method floatToString.h ดังนี้ครับ

เปิด text editor อะไรก็ได้ (notepad, textpad) แล้ว copy ลงไปตามนี้ครับ

จากนั้น Save file เป็น "floadToString.h" "DHT.h" และ "DHT.cpp" เก็บไว้ที่เดียวกับ Library "DHT" เมื่อซักครู่นี้ครับ ถ้าเก็บไว้ที่อื่น Arduino IDE อาจจะมองไฟล์ไม่เห็นได้ครับ โหลดตามนี้เลยครับ

https://docs.google.com/file/d/0B4Ig-CbpU0IPajJmTzRodFMyN2c/edit?usp=sharing

// floatToString.h

//char * floatToString(char * outstr, float value, int places, int minwidth=, bool rightjustify) {

char * floatToString(char * outstr, float value, int places, int minwidth=0, bool rightjustify=false) {

// this is used to write a float value to string, outstr. oustr is also the return value

int digit;

float tens = 0.1;

int tenscount = 0;

int i;

float tempfloat = value;

int c = 0;

int charcount = 1;

int extra = 0;

// make sure we round properly. this could use pow from , but doesn't seem worth the import

// if this rounding step isn't here, the value 54.321 prints as 54.3209

// calculate rounding term d: 0.5/pow(10,places)

float d = 0.5;

if (value < 0)

d *= -1.0;

// divide by ten for each decimal place

for (i = 0; i < places; i++)

d/= 10.0;

// this small addition, combined with truncation will round our values properly

tempfloat += d;

// first get value tens to be the large power of ten less than value

if (value < 0)

tempfloat *= -1.0;

while ((tens * 10.0) <= tempfloat) {

tens *= 10.0;

tenscount += 1;

}

if (tenscount > 0)

charcount += tenscount;

else

charcount += 1;

if (value < 0)

charcount += 1;

charcount += 1 + places;

minwidth += 1; // both count the null final character

if (minwidth > charcount){

extra = minwidth - charcount;

charcount = minwidth;

}

if (extra > 0 and rightjustify) {

for (int i = 0; i< extra; i++) {

outstr[c++] = ' ';

}

}

// write out the negative if needed

if (value < 0)

outstr[c++] = '-';

if (tenscount == 0)

outstr[c++] = '0';

for (i=0; i< tenscount; i++) {

digit = (int) (tempfloat/tens);

itoa(digit, &outstr[c++], 10);

tempfloat = tempfloat - ((float)digit * tens);

tens /= 10.0;

}

// if no places after decimal, stop now and return

// otherwise, write the point and continue on

if (places > 0)

outstr[c++] = '.';

// now write out each decimal place by shifting digits one by one into the ones place and writing the truncated value

for (i = 0; i < places; i++) {

tempfloat *= 10.0;

digit = (int) tempfloat;

itoa(digit, &outstr[c++], 10);

// once written, subtract off that digit

tempfloat = tempfloat - (float) digit;

}

if (extra > 0 and not rightjustify) {

for (int i = 0; i< extra; i++) {

outstr[c++] = ' ';

}

}

outstr[c++] = '\0';

return outstr;

}

Upload แล้วเปิดหน้าจอ Serial monitor จะได้ผลดังนี้ครับ

ไฟล์ที่เก็บข้อมูลของ sketch นี้คือ "datalog.txt"

ถ้าเอา SD card ย้ายไปเปิดบนคอมพิวเตอร์ก็จะเห็นแบบนี้ครับ

ข้อควรระวัง !!!!!

1. อย่าลืมไปสร้างไฟล์ "datalog.txt" ไว้ใน SD card ก่อนนะครับ ไม่อย่างน้้น SD card จะเปิดไฟล์ไม่ได้ และร้องแสดง error

2. อย่าลืมเพิ่ม "floadToString.h" ไว้ใน Folder เดียวกับไฟล์ที่เก็บ Sketch นี้นะครับ ไม่งั้นจะร้อง error หา "floadToString.h" ไม่เจอ