ตรวจสอบสภาพอากาศกับ Unicon และ BMP085
<อ้างอิงจากวารสาร The Prototype Electronics ฉบับที่ 40>
เกี่ยวกับโมดูลวัดความกดอากาศ BMP085
BMP085 เป็นตัวตรวจจับปริมาณของสภาพแวดล้อมที่พัฒนาขึ้นจากเทคโนโลยีเปียโซ-รีซิสตีฟ (Piezo-resistive technology) เป็นผลงานของ BOSCH หนึ่งในผู้ผลิตตัวตรวจจับคุณภาพสูงในวงการอุตสาหกรรมระดับโลก ใช้ไฟเลี้ยงในย่าน +1.8 ถึง +3.6V เชื่อมต่อกับไมโครคอนโทรลเลอร์ผ่านทางบัส I2C มีคุณสมบัติที่น่าสนใจดังนี้
- วัดความกดอากาศได้ในช่วง 300 ถึง 1100 hPa (hPa คือหน่วย hecto Pascal โดยที่ hecto หมายถึง 100)
- มีความผิดพลาดในการวัดต่ำสุด +2.5hPa
- ไฟเลี้ยงย่าน 1.8 ถึง 3.6V กินกระแสไฟฟ้าเฉลี่ย 3mA ที่อัตราการเปลี่ยนแปลงของข้อมูล 1Hz
- ติดต่อกับไมโครคอนโทรลเลอร์ผ่านบัส I2C
- ให้ค่าของอุณหภูมิในพื้นที่ที่ตรวจวัดสัมพันธ์กับค่าความกดอากาศในช่วงเวลาและสภาพแวดล้อมเดียวกัน ทำให้นำผลการตรวจจับไปคำนวณเพื่อหาค่าตำแหน่งความสูงจากระดับน้ำทะเล (altitude) ของสถานที่ที่ติดตั้งตัวตรวจจับนี้ได้
- มีจุดต่อ 6 จุด มีระยะห่าง 0.1 นิ้ว หรือ 2.54 มม.
- ขนาด 0.65 x 0.65 นิ้วหรือ 16.5 x 16.5 มม
ในรูปข้างล่างนี้จะแสดงหน้าตาของโมดูล BMP085 และบอร์ดเชื่อมต่อ ADX-BMP085 ที่นำมาใช้เชื่อมต่อกับบอร์ด Unicon สำหรับบอร์ด ADX-BMP085 ได้เคยแนะนำให้สร้างและตีพิมพ์ใน TPE ฉบับที่ 23 บทความการใช้งานแผงวงจรเชื่อมต่อ BMP085 ตัวตรวจจับความกดดันอากาศ
โมดูล BMP085 และบอร์ดเชื่อมต่อ ADX-BMP085 พร้อมสายสัญญาณ JST3AA-8 สำหรับเชื่อมต่อกับบอร์ด Unicon
การต่อวงจรเพื่อใช้งานกับบอร์ด Unicon
การเชื่อมต่อกับบอร์ด Unicon ของ BMP085 ทำได้ไม่ยาก เพียงต่อขา SDA ของ BMP085 เข้าที่ขา 2 (SDA) และขา SCL เข้าที่ขา 3 (SCL) ของบอร์ด Unicon โดยติดตั้งโมดูล BMP085 ลงบนบอร์ด ADX-BMP085 จะทำให้การเชื่อมต่อง่ายขึ้นมาก อีกทั้งยังช่วยให้ใช้งาน BMP085 กับบอร์ด Unicon ที่ใช้ไฟเลี้ยง +5V ได้ เนื่องจากบอร์ด ADX-BMP085 มีวงจรควบคุมไฟเลี้ยงคงที่ +3.3V เมื่อได้ไฟเลี้ยง +5V จากบอร์ด Unicon ก็จะควบคุมให้เหลือคงที่ที่ +3.3V สำหรับเลี้ยงโมดูล BMP085 ได้
การเชื่อมต่อเพื่อทดลองใช้งานโมดูล BMP085 กับบอร์ด Unicon
สำหรับวงจรของบอร์ด ADX-BMP085 แสดงในรูป ท่านที่มีโมดูล BMP085 อยู่แล้ว ก็สามารถต่อวงจรขึ้นมาเองได้เลย
วงจรของบอร์ดเชื่อมต่อ ADX-BMP085
เรื่องที่ควรทราบเกี่ยวกับรีจิสเตอร์ของ BMP085
โมดูลวัดความกดอากาศ BMP085 มีรีจิสเตอร์เพื่อใช้ในการปรับแต่งตัวตรวจจับให้สามารถวัดค่าได้แม่นยำอยู่หลายตัวจะต้องนำค่ามาคำนวณร่วมกันเพื่ออ่านค่าอุณหภูมิและความกดอากาศ ดังมีข้อมูลโดยสรุปตามตาราง
ตารางแอดเดรสของรีจิสเตอร์ค่าสัมประสิทธิ์ที่ใช้ในการปรับแต่งสำหรับโมดูล BMP085
สำหรับการอ่านค่าความกดอากาศจะอ่านค่าแบบ Oversampling (osrs) ได้ จึงเลือกอ่านค่าจากรีจิสเตอร์ควบคุมที่เกี่ยวข้องกับการอ่านค่าแบบ Oversampling ที่ต้องการได้ โดยเลือกได้ตั้งแต่ osrs0 ถึง osrs3 ดังแสดงในตารางโดยจะต้องอ่านค่าที่ได้จาก Oversampling 4 ระดับแล้วนำมาคำนวณเพื่อให้ค่าความกดอากาศออกมา
ตารางแสดงค่าของรีจิสเตอร์ควบคุมการอ่านค่าจากโมดูล BMP085 ค่าระยะเวลาที่ปรากฏใหน่วยเป็นวินาที
สำหรับการใช้งานโมดูล BMP085 จะต้องมีการปรับแต่งตัวตรวจจับก่อนทุกครั้ง เพื่อให้ค่าที่วัดได้มีความแม่นยำ
เกี่ยวกับโปรแกรมควบคุม
โปรแกรมควบคุมเพื่ออ่านค่าจากโมดูล BMP085 ของบอร์ด Unicon จะทำการอ่านค่าจากเซ็นเซอร์ BMP085 โดยจะนำค่าอุณหภูมิและความกดอากาศที่วัดได้มาแสดงบนจอ GLCD ของบอร์ด Unicon ตอนต้นของโปรแกรมในส่วนของ setup() จะต้องเรียกฟังก์ชั่น bmp085Calibration(); ก่อนเพื่อทำการปรับแต่งตัวตรวจจับให้พร้อมใช้งาน ในส่วนของการคำนวณค่าความกดดอากาศนั้นจะเป็นหน้าที่ของฟังก์ชั่น bmp085GetPressure() ที่นำค่าของ รีจิสเตอร์ทั้งหมดของ BMP085 ที่อ่านค่าจากฟังก์ชั่น bmp085ReadUP(); มาทำการคำนวณ จนกระทั่งได้ค่าความกดอากาศมาเก็บไว้ในตัวแปร P เพื่อนำไปแสดงผลต่อไป
/***************************************************** * * TITLE : TEMPERATURE AND PRESSURE * CATAGORIES : I2C * CREATED DATE : DECEMBER 9, 2013 * AUTHOR : INNOVATIVE EXPERIMENT CO., LTD. (INEX) * WEBSITE : HTTP://WWW.INEX.CO.TH * DESCRIPTION : Measure temperature and pressure with BMP085 * and show value on Unicon board's GLCD * โปรแกรมวัดอุณหภูมิและความกดอากาศด้วย BMP085 * โดยแสดงค่าอุณหภูมิและความกดอากาศมาแสดงบน GLCD * ******************************************************/ #include <unicon.h> // Define BMP085 Address #define DEVICE_ADDRESS 0xEE >> 1 // Set oversampling to ultra low power // 0 : Ultra low poewr // 1 : Standard // 2 : High resolution // 3 : Ultra high resolution const unsigned char OSS = 0; // Declare calibration coefficient values int ac1; int ac2; int ac3; unsigned int ac4; unsigned int ac5; unsigned int ac6; int b1; int b2; int mb; int mc; int md; long b5; // Declare variable for temperature and pressure float temperature; long pressure; void setup() { // Initiate I2C Wire.begin(); // Call calibration function bmp085Calibration(); } void loop() { // Get temperature temperature = bmp085GetTemperature(bmp085ReadUT()); // Get pressure pressure = bmp085GetPressure(bmp085ReadUP()); // Write temperature at line 2 column 0 glcd(0, 0, "%f C ", temperature); // Write pressure at line 5 column 0 glcd(1, 0, "%l Pa ", pressure); // Delay time 1 second delay(1000); } // Get calibration coefficient values void bmp085Calibration() { // Get calibration coefficient values from BMP085 ac1 = bmp085ReadInt(0xAA); ac2 = bmp085ReadInt(0xAC); ac3 = bmp085ReadInt(0xAE); ac4 = bmp085ReadInt(0xB0); ac5 = bmp085ReadInt(0xB2); ac6 = bmp085ReadInt(0xB4); b1 = bmp085ReadInt(0xB6); b2 = bmp085ReadInt(0xB8); mb = bmp085ReadInt(0xBA); mc = bmp085ReadInt(0xBC); md = bmp085ReadInt(0xBE); } // Get temperature function float bmp085GetTemperature(unsigned int ut){ // Declare variable for calculate date long x1, x2; // Calculate temperature x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15; x2 = ((long)mc << 11)/(x1 + md); b5 = x1 + x2; float temp = ((b5 + 8)>>4); temp = temp /10; // Return calculated temperature return temp; } long bmp085GetPressure(unsigned long up) { // Declare variable for calculate date long x1, x2, x3, b3, b6, p; unsigned long b4, b7; // Calculate pressure b6 = b5 - 4000; x1 = (b2 * (b6 * b6)>>12)>>11; x2 = (ac2 * b6)>>11; x3 = x1 + x2; b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2; x1 = (ac3 * b6)>>13; x2 = (b1 * ((b6 * b6)>>12))>>16; x3 = ((x1 + x2) + 2)>>2; b4 = (ac4 * (unsigned long)(x3 + 32768))>>15; b7 = ((unsigned long)(up - b3) * (50000>>OSS)); if (b7 < 0x80000000) p = (b7<<1)/b4; else p = (b7/b4)<<1; x1 = (p>>8) * (p>>8); x1 = (x1 * 3038)>>16; x2 = (-7357 * p)>>16; p += (x1 + x2 + 3791)>>4; // Return calculated pressure return p; } // Get char data from BMP085 char bmp085Read(unsigned char address) { // Declare variable to get data unsigned char data; // Begin I2C transmission with BMP085 address Wire.beginTransmission(DEVICE_ADDRESS); // Send register address Wire.write(address); // End I2C trasmission Wire.endTransmission(); // Request next register address Wire.requestFrom(DEVICE_ADDRESS, 1); // Get data until all data while(!Wire.available()); // Return data from return Wire.read(); } // Get int data from BMP085 int bmp085ReadInt(unsigned char address) { // Declare variable to get data unsigned char msb, lsb; // Begin I2C transmission with BMP085 address Wire.beginTransmission(DEVICE_ADDRESS); // Send register address Wire.write(address); // End I2C trasmission Wire.endTransmission(); // Request next 2 register address Wire.requestFrom(DEVICE_ADDRESS, 2); // Get data until all data while(Wire.available()<2); // Get most significant bit msb = Wire.read(); // Get least significant bit lsb = Wire.read(); // Return data from BMP085 return (int) msb<<8 | lsb; } // Get temperature data from BMP085 unsigned int bmp085ReadUT() { // Declare variable to get data unsigned int ut; // Begin I2C transmission with BMP085 address Wire.beginTransmission(DEVICE_ADDRESS); // Send register address Wire.write(0xF4); Wire.write(0x2E); // End I2C trasmission Wire.endTransmission(); // Delay time 5 milliseconds delay(5); // Get data from 0xF6 ut = bmp085ReadInt(0xF6); // Return temperature data return ut; } // Get pressure data from BMP085 unsigned long bmp085ReadUP() { // Declare variable to get data unsigned char msb, lsb, xlsb; unsigned long up = 0; // Begin I2C transmission with BMP085 address Wire.beginTransmission(DEVICE_ADDRESS); // Send register address Wire.write(0xF4); Wire.write(0x34 + (OSS<<6)); // End I2C trasmission Wire.endTransmission(); // Delay time by depending on OSS delay(2 + (3<<OSS)); // Begin I2C transmission with BMP085 address Wire.beginTransmission(DEVICE_ADDRESS); // Send register address Wire.write(0xF6); // End I2C trasmission Wire.endTransmission(); // Request next 3 register address Wire.requestFrom(DEVICE_ADDRESS, 3); // Get data until all data while(Wire.available() < 3); // Get most significant bit msb = Wire.read(); // Get least significant bit lsb = Wire.read(); // Get extra least significant bit xlsb = Wire.read(); // Calculate pressure data up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS); // Return pressure data return up; }
โปรแกรมสำหรับอ่านค่าจากโมดูล BMP085 ของบอร์ด Unicon
ทดสอบวัดความกดอากาศ
สำหรับการทดสอบ BMP085 จะให้ได้ผลแบบชัดเจน ต้องวัดเปรียบเทียบระหว่างพื้นที่ที่มีความกดอากาศต่างกันมากๆ เช่น บนอาคารสูงกับห้องใต้ดิน จึงอาจทดสอบให้เห็นได้ไม่ง่ายนัก เนื่องจากโดยปกติพื้นที่ของประเทศไทยจะอยู่สูงจากระดับน้ำทะเลประมาณ 1.44 เมตร และภูมิประเทศเป็นที่ราบเสียส่วนใหญ่ ส่งผลให้ความกดอากาศปกติจึงไม่ต่างกันมากนักในแต่ละพื้นที่ จากการทดสอบในพื้นที่กรุงเทพมหานครโดยใช้โมดูล BMP085 วัดได้ 100,676 Pa หรือ 100.676 kPa (กิโลปาสคาล) เนื่องจากอยู่สูงกว่าระกับน้ำทะเลประมาณ 1 เมตร ค่าความกดอากาศจะลดลงเมื่ออยู่สูงจากระดับน้ำทะเล โดยที่ระดับน้ำทะเลจะมีค่าความกดอากาศ 1 atm หรือหนึ่งหน่วยบรรยากาศ หรือเท่ากับ 101.325 kPa หรือ 760 mmHg (มิลลิเมตรปรอท)
ผลการทำงานของการวัดอุณหภูมิและค่าความกดอากาศด้วยโมดูล BMP085 และบอร์ด Unicon