2012年10月29日

arduino的數位溫度計

以前曾經用arduino作過一個溫濕度計,不過那個在使用上還是不夠好,原因包括溫度感測器太貴、arduino太貴、無法即時秀出折線圖。

最近又開始對數位溫度計感到興趣了,所以以上的問題都有辦法解決了。首先是溫度感測器,我後來看感測器應用的書籍時得知,原來有些便宜的溫度IC可以用,足以解決我的問題,像是LM35和DS18B20,前者只要45元(網拍價可更便宜到30元,但我習慣買的那家電子材料行居然要價90元),後者DS18B20則是用30元購得。

LM35是接類比接腳,每上升1度C,就會增加 10 mv,所以直接用arduino測出改變的電壓,再轉換一下,就可以換算成溫度。

DS18B20接的是數位接腳,安裝DS18B20有點麻煩,還要先找一些library來裝,不過裝好之後就很好用了,可以用一個pin同時接好幾個感測器來同時感測。

arduino太貴的問題,後來我找到德州儀器出的MSP 430 Lauchpad ,售價只要4.3元美金,在台灣要買的話,約是160元左右,目前中文的教學網站只有一個,arduino的程式修改一下可以直接用在Lauchpad 上面,但是要用 energia 來上傳。

而秀出即時折線圖的功能,後來我從arduino的競爭者parallax那邊找到一個免費軟體 ,叫做PLX    DAQ,是 MS Excel的外掛,可以把 serial port 讀到的資料直接餵給 Excel,這樣就可以即時呈現曲線圖了。





以下是我參考的網站

Arduino接LM35的接法和程式碼,還有Processing怎麼寫接收端的程式
http://pscmpf.blogspot.tw/2008/12/arduino-lm35-sensor.html


Arduino接 DS18B20,再用Processing呈現的教程
http://www.naozhendang.com/2011/06/20/learning-arduino-8-arduinoprocessingpachubeds18b20/

給DS18B20裝的libary-DallasTemperature.h
http://www.milesburton.com/?title=Dallas_Temperature_Control_Library


給DS18B20裝的libary-OneWire.h
http://www.pjrc.com/teensy/td_libs_OneWire.html



PLX DAQ的網站
http://www.parallax.com/tabid/393/Default.aspx



即時用Excel,透過PLX DAQ 來接收Arduino的資料
http://robottini.altervista.org/arduino-and-real-time-charts-in-excel




接著是程式碼,這是LM35的,中間的腳要接arduino的Analog in 0。輸出的資料,已經改成用在PLX DAQ上面的,另外因為資料數據會跳動,所以我將資料取了五次再作平均。


//declare variables
float tempC;
int tempPin = 0;
int row = 0;
void setup()
{
  Serial.begin(9600); //opens serial port, sets data rate to 9600 bps
  Serial.println("CLEARDATA");
  Serial.println("LABEL,Time,T");
}
void loop()
{
  tempC = analogRead(tempPin);           
  //tempC = 0.7*tempC + 0.3*analogRead(tempPin);
  tempC += analogRead(tempPin);
  tempC += analogRead(tempPin);
  tempC += analogRead(tempPin);
  tempC += analogRead(tempPin);
  tempC =tempC/5;
  tempC = (5.0 * tempC * 100.0)/1024.0;  //轉換類比資料變成溫度
  row++;
  Serial.print("DATA,TIME,"); 
  Serial.println(tempC);
  if (row > 1000) 
  {
    row=0;
    Serial.println("ROW,SET,2");
  }
  delay(500);                           //每500毫秒再測一次。
}




這是DS18B20用的,用之前一定要先把兩個library裝好,DS18B20中間的腳是接到Digital in 10,另外還要接4.7k的電阻,細節看datasheet就知道了。這個code,我是先設定在給 Processing ,如果要輸出給PLX  DAQ,那就要學前面的code改那些輸出的設定。


#include
#include
OneWire oneWire(10); // port 10
DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature.

void setup(void)
{
Serial.begin(115200); // start serial port
sensors.begin(); // Start up the library
}

void loop(void)
{
sensors.requestTemperatures();
Serial.print(sensors.getTempCByIndex(0)); //Send SensorA data to computer
Serial.println();
delay(750);
}



Processing
這些code,是東湊西湊得來的,主要是從這邊改的。arduino傳到serial port的資料是有小數的,但Processing read的資料卻得不到小數,所以我就東改西改,還想辦法把曲線圖的區域加大,但還沒改好,我就看到有PLX DAQ可以用了,所以以下的程式是個未完成的程式。



import processing.serial.*;

Serial myPort; // create object from Serial class
float myValue;
float tempC;
int yDist;
PFont font12;
PFont font24;
float[] tempHistory = new float[300];



void setup() {
  //setup fonts for use throughout the application
  font12 = loadFont("Verdana-12.vlw");
  font24 = loadFont("Verdana-24.vlw");

  //set the size of the window
  size(800, 800);


  String portName = Serial.list()[0];
   //windows用2  linux用0
  myPort = new Serial(this, portName, 9600);
  myPort.bufferUntil('\n');    // read it and store it in val
}

void draw(){

   tempC = myValue;

    //refresh the background to clear old data
    background(123);

    //draw the temp rectangle
    colorMode(RGB, 160);  //use color mode sized for fading
    stroke (0);
    rect (49,19,22,162);
    //fade red and blue within the rectangle
    for (int colorIndex = 0; colorIndex <= 160; colorIndex ++)
    {
      stroke(160 - colorIndex, 0, colorIndex);
      line(50, colorIndex + 20, 70, colorIndex + 20);
    }

    //draw graph
    stroke(0);
    fill(255,255,255);
    rect(90,80,300,100);
    for (int index = 0; index<300 font="font" index="index">
    { 
      if(index == 299)
        tempHistory[index] = tempC;
      else
        tempHistory[index] = tempHistory[index + 1];
      point(390 + index, 1600 - tempHistory[index]*50);
    }

    //write reference values
    fill(0,0,0);
    textFont(font12);
    textAlign(RIGHT);
    text("100 C", 45, 25);
    text("0 C", 45, 187);

    //draw triangle pointer
    yDist = int(160 - (160 * (tempC * 0.01)));
    stroke(0);
    triangle(75, yDist + 20, 85, yDist + 15, 85, yDist + 25);

    //write the temp in C and F
    fill(0,0,0);
    textFont(font24);
    textAlign(LEFT);
    text(str(tempC) + " C", 115, 37);
  } 



void serialEvent(Serial myPort) {
  // read the serial buffer:
  String myString = myPort.readStringUntil('\n');
  myString = trim(myString);
  myValue = float(myString);
  println(myValue);
 }